diff --git a/AconfigFlags.bp b/AconfigFlags.bp index 26fbd270eb468eba36a0746a1a6c097ffb1e152a..ad849002cca1701eedf6fb93fe2817751269a763 100644 --- a/AconfigFlags.bp +++ b/AconfigFlags.bp @@ -21,6 +21,7 @@ aconfig_declarations_group { java_aconfig_libraries: [ // !!! KEEP THIS LIST ALPHABETICAL !!! "aconfig_mediacodec_flags_java_lib", + "aconfig_settingslib_flags_java_lib", "aconfig_trade_in_mode_flags_java_lib", "android-sdk-flags-java", "android.adaptiveauth.flags-aconfig-java", @@ -348,6 +349,7 @@ java_aconfig_library { aconfig_declarations { name: "android.security.flags-aconfig", package: "android.security", + exportable: true, container: "system", srcs: ["core/java/android/security/*.aconfig"], } @@ -365,6 +367,13 @@ java_aconfig_library { defaults: ["framework-minus-apex-aconfig-java-defaults"], } +java_aconfig_library { + name: "android.security.flags-aconfig-java-export", + aconfig_declarations: "android.security.flags-aconfig", + mode: "exported", + defaults: ["framework-minus-apex-aconfig-java-defaults"], +} + cc_aconfig_library { name: "android_security_flags_aconfig_c_lib", aconfig_declarations: "android.security.flags-aconfig", @@ -1749,3 +1758,19 @@ cc_aconfig_library { ], min_sdk_version: "apex_inherit", } + +// Settings Lib +aconfig_declarations { + name: "aconfig_settingslib_flags", + package: "com.android.settingslib.flags", + container: "system", + srcs: [ + "packages/SettingsLib/aconfig/settingslib.aconfig", + ], +} + +java_aconfig_library { + name: "aconfig_settingslib_flags_java_lib", + aconfig_declarations: "aconfig_settingslib_flags", + defaults: ["framework-minus-apex-aconfig-java-defaults"], +} diff --git a/Android.bp b/Android.bp index 26d0d65f329ca4a1db3591be6b20c17f1a0a8f68..48f0928f24d7a0fe0337bde751036c2eae43c4e9 100644 --- a/Android.bp +++ b/Android.bp @@ -220,7 +220,7 @@ java_library { "android.hardware.contexthub-V1.0-java", "android.hardware.contexthub-V1.1-java", "android.hardware.contexthub-V1.2-java", - "android.hardware.contexthub-V3-java", + "android.hardware.contexthub-V4-java", "android.hardware.gnss-V1.0-java", "android.hardware.gnss-V2.1-java", "android.hardware.health-V1.0-java-constants", @@ -399,6 +399,7 @@ java_defaults { "com.android.sysprop.foldlockbehavior", "com.android.sysprop.view", "framework-internal-utils", + "dynamic_instrumentation_manager_aidl-java", // If MimeMap ever becomes its own APEX, then this dependency would need to be removed // in favor of an API stubs dependency in java_library "framework" below. "mimemap", diff --git a/android-sdk-flags/OWNERS b/android-sdk-flags/OWNERS new file mode 100644 index 0000000000000000000000000000000000000000..01f45dd01e365da9e4bbf60c82827d08989cc237 --- /dev/null +++ b/android-sdk-flags/OWNERS @@ -0,0 +1 @@ +include /SDK_OWNERS diff --git a/android-sdk-flags/flags.aconfig b/android-sdk-flags/flags.aconfig index cfe298e187d150fe9a63bf926797117f772af857..19c7bf6748329fb7631db5ddfc4578a4d7b089ee 100644 --- a/android-sdk-flags/flags.aconfig +++ b/android-sdk-flags/flags.aconfig @@ -6,6 +6,7 @@ flag { namespace: "android_sdk" description: "Use the new SDK major.minor versioning scheme (e.g. Android 40.1) which replaces the old single-integer scheme (e.g. Android 15)." bug: "350458259" + is_exported: true # Use is_fixed_read_only because DeviceConfig may not be available when Build.VERSION_CODES is first accessed is_fixed_read_only: true diff --git a/apct-tests/perftests/core/src/android/os/LongArrayMultiStateCounterPerfTest.java b/apct-tests/perftests/core/src/android/os/LongArrayMultiStateCounterPerfTest.java index 8d2d04471f8e17b2f179d481cc07fce5b80e6830..8160ca2eba695e19734dbc269ff9be09bdd314b6 100644 --- a/apct-tests/perftests/core/src/android/os/LongArrayMultiStateCounterPerfTest.java +++ b/apct-tests/perftests/core/src/android/os/LongArrayMultiStateCounterPerfTest.java @@ -159,9 +159,7 @@ public class LongArrayMultiStateCounterPerfTest { LongArrayMultiStateCounter counter = new LongArrayMultiStateCounter(2, 4); final BenchmarkState state = mPerfStatusReporter.getBenchmarkState(); long time = 1000; - LongArrayMultiStateCounter.LongArrayContainer timeInFreq = - new LongArrayMultiStateCounter.LongArrayContainer(4); - timeInFreq.setValues(new long[]{100, 200, 300, 400}); + long[] timeInFreq = {100, 200, 300, 400}; while (state.keepRunning()) { counter.setState(1, time); counter.setState(0, time + 1000); diff --git a/apex/jobscheduler/framework/aconfig/job.aconfig b/apex/jobscheduler/framework/aconfig/job.aconfig index debd85096488bce1e9d22cc90eafb57a8d9dc01c..47a85498f51be84254a9450857b0f9b888ba06a3 100644 --- a/apex/jobscheduler/framework/aconfig/job.aconfig +++ b/apex/jobscheduler/framework/aconfig/job.aconfig @@ -37,3 +37,19 @@ flag { description: "Ignore the important_while_foreground flag and change the related APIs to be not effective" bug: "374175032" } + +flag { + name: "get_pending_job_reasons_api" + is_exported: true + namespace: "backstage_power" + description: "Introduce a new getPendingJobReasons() API which returns reasons why a job may not have executed. Also deprecate the existing getPendingJobReason() API." + bug: "372031023" +} + +flag { + name: "get_pending_job_reasons_history_api" + is_exported: true + namespace: "backstage_power" + description: "Introduce a new getPendingJobReasonsHistory() API which returns a limited historical view of getPendingJobReasons()." + bug: "372031023" +} diff --git a/apex/jobscheduler/framework/java/android/app/JobSchedulerImpl.java b/apex/jobscheduler/framework/java/android/app/JobSchedulerImpl.java index 3cfddc6d8e2b28a79bf5880042bca5326cacd6f6..fb5ef8771c26b19a9ff7d482d57e0a342cd4743c 100644 --- a/apex/jobscheduler/framework/java/android/app/JobSchedulerImpl.java +++ b/apex/jobscheduler/framework/java/android/app/JobSchedulerImpl.java @@ -172,6 +172,16 @@ public class JobSchedulerImpl extends JobScheduler { } } + @Override + @NonNull + public int[] getPendingJobReasons(int jobId) { + try { + return mBinder.getPendingJobReasons(mNamespace, jobId); + } catch (RemoteException e) { + return new int[] { PENDING_JOB_REASON_UNDEFINED }; + } + } + @Override public boolean canRunUserInitiatedJobs() { try { diff --git a/apex/jobscheduler/framework/java/android/app/job/IJobScheduler.aidl b/apex/jobscheduler/framework/java/android/app/job/IJobScheduler.aidl index 416a2d8c0002abcdd49552614babce78c80fad4f..21051b520d8406591e3ef77904f8a147786fcd39 100644 --- a/apex/jobscheduler/framework/java/android/app/job/IJobScheduler.aidl +++ b/apex/jobscheduler/framework/java/android/app/job/IJobScheduler.aidl @@ -39,6 +39,7 @@ interface IJobScheduler { ParceledListSlice getAllPendingJobsInNamespace(String namespace); JobInfo getPendingJob(String namespace, int jobId); int getPendingJobReason(String namespace, int jobId); + int[] getPendingJobReasons(String namespace, int jobId); boolean canRunUserInitiatedJobs(String packageName); boolean hasRunUserInitiatedJobsPermission(String packageName, int userId); List getStartedJobs(); diff --git a/apex/jobscheduler/framework/java/android/app/job/JobScheduler.java b/apex/jobscheduler/framework/java/android/app/job/JobScheduler.java index ad54cd397413994901281531ded375dab8cea256..bfdd15e9b0cd8f8acf79e409746acfa1cd6f17be 100644 --- a/apex/jobscheduler/framework/java/android/app/job/JobScheduler.java +++ b/apex/jobscheduler/framework/java/android/app/job/JobScheduler.java @@ -16,6 +16,7 @@ package android.app.job; +import android.annotation.FlaggedApi; import android.annotation.IntDef; import android.annotation.NonNull; import android.annotation.Nullable; @@ -238,6 +239,13 @@ public abstract class JobScheduler { * to defer this job. */ public static final int PENDING_JOB_REASON_USER = 15; + /** + * The override deadline has not transpired. + * + * @see JobInfo.Builder#setOverrideDeadline(long) + */ + @FlaggedApi(Flags.FLAG_GET_PENDING_JOB_REASONS_API) + public static final int PENDING_JOB_REASON_CONSTRAINT_DEADLINE = 16; /** @hide */ @IntDef(prefix = {"PENDING_JOB_REASON_"}, value = { @@ -259,6 +267,7 @@ public abstract class JobScheduler { PENDING_JOB_REASON_JOB_SCHEDULER_OPTIMIZATION, PENDING_JOB_REASON_QUOTA, PENDING_JOB_REASON_USER, + PENDING_JOB_REASON_CONSTRAINT_DEADLINE, }) @Retention(RetentionPolicy.SOURCE) public @interface PendingJobReason { @@ -458,12 +467,31 @@ public abstract class JobScheduler { /** * Returns a reason why the job is pending and not currently executing. If there are multiple * reasons why a job may be pending, this will only return one of them. + * + * @apiNote + * To know all the potential reasons why the job may be pending, + * use {@link #getPendingJobReasons(int)} instead. */ @PendingJobReason public int getPendingJobReason(int jobId) { return PENDING_JOB_REASON_UNDEFINED; } + /** + * Returns potential reasons why the job with the given {@code jobId} may be pending + * and not currently executing. + * + * The returned array will include {@link PendingJobReason reasons} composed of both + * explicitly set constraints on the job and implicit constraints imposed by the system. + * The results can be used to debug why a given job may not be currently executing. + */ + @FlaggedApi(Flags.FLAG_GET_PENDING_JOB_REASONS_API) + @NonNull + @PendingJobReason + public int[] getPendingJobReasons(int jobId) { + return new int[] { PENDING_JOB_REASON_UNDEFINED }; + } + /** * Returns {@code true} if the calling app currently holds the * {@link android.Manifest.permission#RUN_USER_INITIATED_JOBS} permission, allowing it to run diff --git a/apex/jobscheduler/service/aconfig/device_idle.aconfig b/apex/jobscheduler/service/aconfig/device_idle.aconfig index c4d0d1850a180005f03a740e9de106818085ca92..426031fbeb9c38cebb9f5eef25b6326152c9b3ea 100644 --- a/apex/jobscheduler/service/aconfig/device_idle.aconfig +++ b/apex/jobscheduler/service/aconfig/device_idle.aconfig @@ -17,3 +17,13 @@ flag { description: "Disable wakelocks for background apps while Light Device Idle is active" bug: "326607666" } + +flag { + name: "use_cpu_time_for_temp_allowlist" + namespace: "backstage_power" + description: "Use CPU time for temporary allowlists" + bug: "376561328" + metadata { + purpose: PURPOSE_BUGFIX + } +} diff --git a/apex/jobscheduler/service/java/com/android/server/DeviceIdleController.java b/apex/jobscheduler/service/java/com/android/server/DeviceIdleController.java index 3e650da2e66f9385fc00382df704e271a146762e..41fd4a29cfd1af59c127ad918cf3a7a5b7bd918b 100644 --- a/apex/jobscheduler/service/java/com/android/server/DeviceIdleController.java +++ b/apex/jobscheduler/service/java/com/android/server/DeviceIdleController.java @@ -620,8 +620,8 @@ public class DeviceIdleController extends SystemService * the network and acquire wakelocks. Times are in milliseconds. */ @GuardedBy("this") - private final SparseArray> mTempWhitelistAppIdEndTimes - = new SparseArray<>(); + @VisibleForTesting + final SparseArray> mTempWhitelistAppIdEndTimes = new SparseArray<>(); private NetworkPolicyManagerInternal mNetworkPolicyManagerInternal; @@ -1941,7 +1941,8 @@ public class DeviceIdleController extends SystemService private static final int MSG_REPORT_IDLE_ON_LIGHT = 3; private static final int MSG_REPORT_IDLE_OFF = 4; private static final int MSG_REPORT_ACTIVE = 5; - private static final int MSG_TEMP_APP_WHITELIST_TIMEOUT = 6; + @VisibleForTesting + static final int MSG_TEMP_APP_WHITELIST_TIMEOUT = 6; @VisibleForTesting static final int MSG_REPORT_STATIONARY_STATUS = 7; private static final int MSG_FINISH_IDLE_OP = 8; @@ -2511,6 +2512,11 @@ public class DeviceIdleController extends SystemService return SystemClock.elapsedRealtime(); } + /** Returns the current elapsed realtime in milliseconds. */ + long getUptimeMillis() { + return SystemClock.uptimeMillis(); + } + LocationManager getLocationManager() { if (mLocationManager == null) { mLocationManager = mContext.getSystemService(LocationManager.class); @@ -3264,7 +3270,8 @@ public class DeviceIdleController extends SystemService void addPowerSaveTempWhitelistAppDirectInternal(int callingUid, int uid, long duration, @TempAllowListType int tempAllowListType, boolean sync, @ReasonCode int reasonCode, @Nullable String reason) { - final long timeNow = SystemClock.elapsedRealtime(); + final long timeNow = Flags.useCpuTimeForTempAllowlist() ? mInjector.getUptimeMillis() + : mInjector.getElapsedRealtime(); boolean informWhitelistChanged = false; int appId = UserHandle.getAppId(uid); synchronized (this) { @@ -3350,7 +3357,8 @@ public class DeviceIdleController extends SystemService } void checkTempAppWhitelistTimeout(int uid) { - final long timeNow = SystemClock.elapsedRealtime(); + final long timeNow = Flags.useCpuTimeForTempAllowlist() ? mInjector.getUptimeMillis() + : mInjector.getElapsedRealtime(); final int appId = UserHandle.getAppId(uid); if (DEBUG) { Slog.d(TAG, "checkTempAppWhitelistTimeout: uid=" + uid + ", timeNow=" + timeNow); @@ -5219,6 +5227,17 @@ public class DeviceIdleController extends SystemService } } + pw.println(" Flags:"); + pw.print(" "); + pw.print(Flags.FLAG_USE_CPU_TIME_FOR_TEMP_ALLOWLIST); + pw.print("="); + pw.println(Flags.useCpuTimeForTempAllowlist()); + pw.print(" "); + pw.print(Flags.FLAG_REMOVE_IDLE_LOCATION); + pw.print("="); + pw.println(Flags.removeIdleLocation()); + pw.println(); + synchronized (this) { mConstants.dump(pw); @@ -5449,7 +5468,8 @@ public class DeviceIdleController extends SystemService pw.println(" Temp whitelist schedule:"); prefix = " "; } - final long timeNow = SystemClock.elapsedRealtime(); + final long timeNow = Flags.useCpuTimeForTempAllowlist() ? mInjector.getUptimeMillis() + : mInjector.getElapsedRealtime(); for (int i = 0; i < size; i++) { pw.print(prefix); pw.print("UID="); diff --git a/apex/jobscheduler/service/java/com/android/server/job/JobConcurrencyManager.java b/apex/jobscheduler/service/java/com/android/server/job/JobConcurrencyManager.java index ba8e3e8b48fc7f9c52d1ed458470d4433c8a2e93..8f44698ffd8d196f60f767a6e445273e0975e9ad 100644 --- a/apex/jobscheduler/service/java/com/android/server/job/JobConcurrencyManager.java +++ b/apex/jobscheduler/service/java/com/android/server/job/JobConcurrencyManager.java @@ -1550,7 +1550,7 @@ class JobConcurrencyManager { mActivePkgStats.add( jobStatus.getSourceUserId(), jobStatus.getSourcePackageName(), packageStats); - mService.resetPendingJobReasonCache(jobStatus); + mService.resetPendingJobReasonsCache(jobStatus); } if (mService.getPendingJobQueue().remove(jobStatus)) { mService.mJobPackageTracker.noteNonpending(jobStatus); 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 4c1951ae9d39bf9cca5ee4657a81d20a40b2ab29..f569388ef3c19654959cf9a5ec51a4174ed78e49 100644 --- a/apex/jobscheduler/service/java/com/android/server/job/JobSchedulerService.java +++ b/apex/jobscheduler/service/java/com/android/server/job/JobSchedulerService.java @@ -460,10 +460,10 @@ public class JobSchedulerService extends com.android.server.SystemService private final ArraySet mChangedJobList = new ArraySet<>(); /** - * Cached pending job reasons. Mapping from UID -> namespace -> job ID -> reason. + * Cached pending job reasons. Mapping from UID -> namespace -> job ID -> reasons. */ - @GuardedBy("mPendingJobReasonCache") // Use its own lock to avoid blocking JS processing - private final SparseArrayMap mPendingJobReasonCache = + @GuardedBy("mPendingJobReasonsCache") // Use its own lock to avoid blocking JS processing + private final SparseArrayMap> mPendingJobReasonsCache = new SparseArrayMap<>(); /** @@ -2021,139 +2021,123 @@ public class JobSchedulerService extends com.android.server.SystemService } } - @JobScheduler.PendingJobReason - private int getPendingJobReason(int uid, String namespace, int jobId) { - int reason; + @NonNull + private int[] getPendingJobReasons(int uid, String namespace, int jobId) { + int[] reasons; // Some apps may attempt to query this frequently, so cache the reason under a separate lock // so that the rest of JS processing isn't negatively impacted. - synchronized (mPendingJobReasonCache) { - SparseIntArray jobIdToReason = mPendingJobReasonCache.get(uid, namespace); - if (jobIdToReason != null) { - reason = jobIdToReason.get(jobId, JobScheduler.PENDING_JOB_REASON_UNDEFINED); - if (reason != JobScheduler.PENDING_JOB_REASON_UNDEFINED) { - return reason; + synchronized (mPendingJobReasonsCache) { + SparseArray jobIdToReasons = mPendingJobReasonsCache.get(uid, namespace); + if (jobIdToReasons != null) { + reasons = jobIdToReasons.get(jobId); + if (reasons != null) { + return reasons; } } } synchronized (mLock) { - reason = getPendingJobReasonLocked(uid, namespace, jobId); + reasons = getPendingJobReasonsLocked(uid, namespace, jobId); if (DEBUG) { - Slog.v(TAG, "getPendingJobReason(" - + uid + "," + namespace + "," + jobId + ")=" + reason); + Slog.v(TAG, "getPendingJobReasons(" + + uid + "," + namespace + "," + jobId + ")=" + Arrays.toString(reasons)); } } - synchronized (mPendingJobReasonCache) { - SparseIntArray jobIdToReason = mPendingJobReasonCache.get(uid, namespace); - if (jobIdToReason == null) { - jobIdToReason = new SparseIntArray(); - mPendingJobReasonCache.add(uid, namespace, jobIdToReason); + synchronized (mPendingJobReasonsCache) { + SparseArray jobIdToReasons = mPendingJobReasonsCache.get(uid, namespace); + if (jobIdToReasons == null) { + jobIdToReasons = new SparseArray<>(); + mPendingJobReasonsCache.add(uid, namespace, jobIdToReasons); } - jobIdToReason.put(jobId, reason); + jobIdToReasons.put(jobId, reasons); } - return reason; + return reasons; } @VisibleForTesting @JobScheduler.PendingJobReason int getPendingJobReason(JobStatus job) { - return getPendingJobReason(job.getUid(), job.getNamespace(), job.getJobId()); + // keep original method to enable unit testing with flags + return getPendingJobReasons(job.getUid(), job.getNamespace(), job.getJobId())[0]; + } + + @VisibleForTesting + @NonNull + int[] getPendingJobReasons(JobStatus job) { + return getPendingJobReasons(job.getUid(), job.getNamespace(), job.getJobId()); } - @JobScheduler.PendingJobReason @GuardedBy("mLock") - private int getPendingJobReasonLocked(int uid, String namespace, int jobId) { + @NonNull + private int[] getPendingJobReasonsLocked(int uid, String namespace, int jobId) { // Very similar code to isReadyToBeExecutedLocked. - - JobStatus job = mJobs.getJobByUidAndJobId(uid, namespace, jobId); + final JobStatus job = mJobs.getJobByUidAndJobId(uid, namespace, jobId); if (job == null) { // Job doesn't exist. - return JobScheduler.PENDING_JOB_REASON_INVALID_JOB_ID; + return new int[] { JobScheduler.PENDING_JOB_REASON_INVALID_JOB_ID }; } - if (isCurrentlyRunningLocked(job)) { - return JobScheduler.PENDING_JOB_REASON_EXECUTING; + return new int[] { JobScheduler.PENDING_JOB_REASON_EXECUTING }; } + final String debugPrefix = "getPendingJobReasonsLocked: " + job.toShortString(); final boolean jobReady = job.isReady(); - if (DEBUG) { - Slog.v(TAG, "getPendingJobReasonLocked: " + job.toShortString() - + " ready=" + jobReady); + Slog.v(TAG, debugPrefix + " ready=" + jobReady); } - if (!jobReady) { - return job.getPendingJobReason(); + return job.getPendingJobReasons(); } final boolean userStarted = areUsersStartedLocked(job); - if (DEBUG) { - Slog.v(TAG, "getPendingJobReasonLocked: " + job.toShortString() - + " userStarted=" + userStarted); + Slog.v(TAG, debugPrefix + " userStarted=" + userStarted); } if (!userStarted) { - return JobScheduler.PENDING_JOB_REASON_USER; + return new int[] { JobScheduler.PENDING_JOB_REASON_USER }; } final boolean backingUp = mBackingUpUids.get(job.getSourceUid()); if (DEBUG) { - Slog.v(TAG, "getPendingJobReasonLocked: " + job.toShortString() - + " backingUp=" + backingUp); + Slog.v(TAG, debugPrefix + " backingUp=" + backingUp); } - if (backingUp) { // TODO: Should we make a special reason for this? - return JobScheduler.PENDING_JOB_REASON_APP; + return new int[] { JobScheduler.PENDING_JOB_REASON_APP }; } - JobRestriction restriction = checkIfRestricted(job); + final JobRestriction restriction = checkIfRestricted(job); if (DEBUG) { - Slog.v(TAG, "getPendingJobReasonLocked: " + job.toShortString() - + " restriction=" + restriction); + Slog.v(TAG, debugPrefix + " restriction=" + restriction); } if (restriction != null) { - return restriction.getPendingReason(); + // 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 (especially jobActive, since we need to - // go through the array of all potentially active jobs), so we are doing them - // later... but still before checking with the package manager! + // 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); - - if (DEBUG) { - Slog.v(TAG, "getPendingJobReasonLocked: " + job.toShortString() - + " pending=" + jobPending); + Slog.v(TAG, debugPrefix + " pending=" + jobPending); } - if (jobPending) { - // We haven't started the job for some reason. Presumably, there are too many jobs - // running. - return JobScheduler.PENDING_JOB_REASON_DEVICE_STATE; - } - - final boolean jobActive = mConcurrencyManager.isJobRunningLocked(job); - - if (DEBUG) { - Slog.v(TAG, "getPendingJobReasonLocked: " + job.toShortString() - + " active=" + jobActive); - } - if (jobActive) { - return JobScheduler.PENDING_JOB_REASON_UNDEFINED; + // We haven't started the job - presumably, there are too many jobs running. + return new int[] { JobScheduler.PENDING_JOB_REASON_DEVICE_STATE }; } // Validate that the defined package+service is still present & viable. final boolean componentUsable = isComponentUsable(job); - if (DEBUG) { - Slog.v(TAG, "getPendingJobReasonLocked: " + job.toShortString() - + " componentUsable=" + componentUsable); + Slog.v(TAG, debugPrefix + " componentUsable=" + componentUsable); } if (!componentUsable) { - return JobScheduler.PENDING_JOB_REASON_APP; + return new int[] { JobScheduler.PENDING_JOB_REASON_APP }; } - return JobScheduler.PENDING_JOB_REASON_UNDEFINED; + return new int[] { JobScheduler.PENDING_JOB_REASON_UNDEFINED }; } private JobInfo getPendingJob(int uid, @Nullable String namespace, int jobId) { @@ -2195,15 +2179,16 @@ public class JobSchedulerService extends com.android.server.SystemService // The app process will be killed soon. There's no point keeping its jobs in // the pending queue to try and start them. if (mPendingJobQueue.remove(job)) { - synchronized (mPendingJobReasonCache) { - SparseIntArray jobIdToReason = mPendingJobReasonCache.get( + synchronized (mPendingJobReasonsCache) { + SparseArray jobIdToReason = mPendingJobReasonsCache.get( job.getUid(), job.getNamespace()); if (jobIdToReason == null) { - jobIdToReason = new SparseIntArray(); - mPendingJobReasonCache.add(job.getUid(), job.getNamespace(), + jobIdToReason = new SparseArray<>(); + mPendingJobReasonsCache.add(job.getUid(), job.getNamespace(), jobIdToReason); } - jobIdToReason.put(job.getJobId(), JobScheduler.PENDING_JOB_REASON_USER); + jobIdToReason.put(job.getJobId(), + new int[] { JobScheduler.PENDING_JOB_REASON_USER }); } } } @@ -2229,8 +2214,8 @@ public class JobSchedulerService extends com.android.server.SystemService synchronized (mLock) { mJobs.removeJobsOfUnlistedUsers(umi.getUserIds()); } - synchronized (mPendingJobReasonCache) { - mPendingJobReasonCache.clear(); + synchronized (mPendingJobReasonsCache) { + mPendingJobReasonsCache.clear(); } } @@ -2875,7 +2860,7 @@ public class JobSchedulerService extends com.android.server.SystemService final boolean update = lastJob != null; mJobs.add(jobStatus); // Clear potentially cached INVALID_JOB_ID reason. - resetPendingJobReasonCache(jobStatus); + resetPendingJobReasonsCache(jobStatus); if (mReadyToRock) { for (int i = 0; i < mControllers.size(); i++) { StateController controller = mControllers.get(i); @@ -2897,9 +2882,9 @@ public class JobSchedulerService extends com.android.server.SystemService // Deal with any remaining work items in the old job. jobStatus.stopTrackingJobLocked(incomingJob); - synchronized (mPendingJobReasonCache) { - SparseIntArray reasonCache = - mPendingJobReasonCache.get(jobStatus.getUid(), jobStatus.getNamespace()); + synchronized (mPendingJobReasonsCache) { + SparseArray reasonCache = + mPendingJobReasonsCache.get(jobStatus.getUid(), jobStatus.getNamespace()); if (reasonCache != null) { reasonCache.delete(jobStatus.getJobId()); } @@ -2927,11 +2912,11 @@ public class JobSchedulerService extends com.android.server.SystemService return removed; } - /** Remove the pending job reason for this job from the cache. */ - void resetPendingJobReasonCache(@NonNull JobStatus jobStatus) { - synchronized (mPendingJobReasonCache) { - final SparseIntArray reasons = - mPendingJobReasonCache.get(jobStatus.getUid(), jobStatus.getNamespace()); + /** Remove the pending job reasons for this job from the cache. */ + void resetPendingJobReasonsCache(@NonNull JobStatus jobStatus) { + synchronized (mPendingJobReasonsCache) { + final SparseArray reasons = + mPendingJobReasonsCache.get(jobStatus.getUid(), jobStatus.getNamespace()); if (reasons != null) { reasons.delete(jobStatus.getJobId()); } @@ -3313,18 +3298,18 @@ public class JobSchedulerService extends com.android.server.SystemService public void onControllerStateChanged(@Nullable ArraySet changedJobs) { if (changedJobs == null) { mHandler.obtainMessage(MSG_CHECK_JOB).sendToTarget(); - synchronized (mPendingJobReasonCache) { - mPendingJobReasonCache.clear(); + synchronized (mPendingJobReasonsCache) { + mPendingJobReasonsCache.clear(); } } else if (changedJobs.size() > 0) { synchronized (mLock) { mChangedJobList.addAll(changedJobs); } mHandler.obtainMessage(MSG_CHECK_CHANGED_JOB_LIST).sendToTarget(); - synchronized (mPendingJobReasonCache) { + synchronized (mPendingJobReasonsCache) { for (int i = changedJobs.size() - 1; i >= 0; --i) { final JobStatus job = changedJobs.valueAt(i); - resetPendingJobReasonCache(job); + resetPendingJobReasonsCache(job); } } } @@ -3893,23 +3878,21 @@ public class JobSchedulerService extends com.android.server.SystemService // Update the pending reason for any jobs that aren't going to be run. final int numRunnableJobs = runnableJobs.size(); if (numRunnableJobs > 0 && numRunnableJobs != jobsToRun.size()) { - synchronized (mPendingJobReasonCache) { + synchronized (mPendingJobReasonsCache) { for (int i = 0; i < numRunnableJobs; ++i) { final JobStatus job = runnableJobs.get(i); if (jobsToRun.contains(job)) { - // We're running this job. Skip updating the pending reason. - continue; + continue; // we're running this job - skip updating the pending reason. } - SparseIntArray reasons = - mPendingJobReasonCache.get(job.getUid(), job.getNamespace()); + SparseArray reasons = + mPendingJobReasonsCache.get(job.getUid(), job.getNamespace()); if (reasons == null) { - reasons = new SparseIntArray(); - mPendingJobReasonCache.add(job.getUid(), job.getNamespace(), reasons); + reasons = new SparseArray<>(); + mPendingJobReasonsCache.add(job.getUid(), job.getNamespace(), reasons); } - // We're force batching these jobs, so consider it an optimization - // policy reason. - reasons.put(job.getJobId(), - JobScheduler.PENDING_JOB_REASON_JOB_SCHEDULER_OPTIMIZATION); + // we're force batching these jobs - note it as optimization. + reasons.put(job.getJobId(), new int[] + { JobScheduler.PENDING_JOB_REASON_JOB_SCHEDULER_OPTIMIZATION }); } } } @@ -5123,12 +5106,16 @@ public class JobSchedulerService extends com.android.server.SystemService @Override public int getPendingJobReason(String namespace, int jobId) throws RemoteException { - final int uid = Binder.getCallingUid(); + return getPendingJobReasons(validateNamespace(namespace), jobId)[0]; + } + @Override + public int[] getPendingJobReasons(String namespace, int jobId) throws RemoteException { + final int uid = Binder.getCallingUid(); final long ident = Binder.clearCallingIdentity(); try { - return JobSchedulerService.this.getPendingJobReason( - uid, validateNamespace(namespace), jobId); + return JobSchedulerService.this.getPendingJobReasons( + uid, validateNamespace(namespace), jobId); } finally { Binder.restoreCallingIdentity(ident); } @@ -5867,6 +5854,9 @@ public class JobSchedulerService extends com.android.server.SystemService pw.print(android.app.job.Flags.FLAG_IGNORE_IMPORTANT_WHILE_FOREGROUND, android.app.job.Flags.ignoreImportantWhileForeground()); pw.println(); + pw.print(android.app.job.Flags.FLAG_GET_PENDING_JOB_REASONS_API, + android.app.job.Flags.getPendingJobReasonsApi()); + pw.println(); pw.decreaseIndent(); pw.println(); diff --git a/apex/jobscheduler/service/java/com/android/server/job/JobSchedulerShellCommand.java b/apex/jobscheduler/service/java/com/android/server/job/JobSchedulerShellCommand.java index 68303e86055ca52d1dfa7048ca3bf532222e517f..a4a30245084900205b3d529e8847766daa08989f 100644 --- a/apex/jobscheduler/service/java/com/android/server/job/JobSchedulerShellCommand.java +++ b/apex/jobscheduler/service/java/com/android/server/job/JobSchedulerShellCommand.java @@ -439,6 +439,9 @@ public final class JobSchedulerShellCommand extends BasicShellCommandHandler { case android.app.job.Flags.FLAG_IGNORE_IMPORTANT_WHILE_FOREGROUND: pw.println(android.app.job.Flags.ignoreImportantWhileForeground()); break; + case android.app.job.Flags.FLAG_GET_PENDING_JOB_REASONS_API: + pw.println(android.app.job.Flags.getPendingJobReasonsApi()); + break; default: pw.println("Unknown flag: " + flagName); break; 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 1dc5a714337c43ab9632fb502082118f84f8d3dd..58579eb0db479a528a0d635ba2031de9f3162630 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 @@ -2067,12 +2067,11 @@ public final class JobStatus { } /** - * If {@link #isReady()} returns false, this will return a single reason why the job isn't - * ready. If {@link #isReady()} returns true, this will return - * {@link JobScheduler#PENDING_JOB_REASON_UNDEFINED}. + * This will return all potential reasons why the job is pending. */ - @JobScheduler.PendingJobReason - public int getPendingJobReason() { + @NonNull + public int[] getPendingJobReasons() { + final ArrayList reasons = new ArrayList<>(); final int unsatisfiedConstraints = ~satisfiedConstraints & (requiredConstraints | mDynamicConstraints | IMPLICIT_CONSTRAINTS); if ((CONSTRAINT_BACKGROUND_NOT_RESTRICTED & unsatisfiedConstraints) != 0) { @@ -2084,78 +2083,99 @@ public final class JobStatus { // (they'll always get BACKGROUND_RESTRICTION) as the reason, regardless of // battery saver state. if (mIsUserBgRestricted) { - return JobScheduler.PENDING_JOB_REASON_BACKGROUND_RESTRICTION; + reasons.addLast(JobScheduler.PENDING_JOB_REASON_BACKGROUND_RESTRICTION); + } else { + reasons.addLast(JobScheduler.PENDING_JOB_REASON_DEVICE_STATE); + } + } + if ((CONSTRAINT_DEVICE_NOT_DOZING & unsatisfiedConstraints) != 0) { + if (!reasons.contains(JobScheduler.PENDING_JOB_REASON_DEVICE_STATE)) { + reasons.addLast(JobScheduler.PENDING_JOB_REASON_DEVICE_STATE); } - return JobScheduler.PENDING_JOB_REASON_DEVICE_STATE; } + if ((CONSTRAINT_BATTERY_NOT_LOW & unsatisfiedConstraints) != 0) { if ((CONSTRAINT_BATTERY_NOT_LOW & requiredConstraints) != 0) { // The developer requested this constraint, so it makes sense to return the // explicit constraint reason. - return JobScheduler.PENDING_JOB_REASON_CONSTRAINT_BATTERY_NOT_LOW; + reasons.addLast(JobScheduler.PENDING_JOB_REASON_CONSTRAINT_BATTERY_NOT_LOW); + } else { + // Hard-coding right now since the current dynamic constraint sets don't overlap + // TODO: return based on active dynamic constraint sets when they start overlapping + reasons.addLast(JobScheduler.PENDING_JOB_REASON_APP_STANDBY); } - // Hard-coding right now since the current dynamic constraint sets don't overlap - // TODO: return based on active dynamic constraint sets when they start overlapping - return JobScheduler.PENDING_JOB_REASON_APP_STANDBY; } if ((CONSTRAINT_CHARGING & unsatisfiedConstraints) != 0) { if ((CONSTRAINT_CHARGING & requiredConstraints) != 0) { // The developer requested this constraint, so it makes sense to return the // explicit constraint reason. - return JobScheduler.PENDING_JOB_REASON_CONSTRAINT_CHARGING; + reasons.addLast(JobScheduler.PENDING_JOB_REASON_CONSTRAINT_CHARGING); + } else { + // Hard-coding right now since the current dynamic constraint sets don't overlap + // TODO: return based on active dynamic constraint sets when they start overlapping + if (!reasons.contains(JobScheduler.PENDING_JOB_REASON_APP_STANDBY)) { + reasons.addLast(JobScheduler.PENDING_JOB_REASON_APP_STANDBY); + } } - // Hard-coding right now since the current dynamic constraint sets don't overlap - // TODO: return based on active dynamic constraint sets when they start overlapping - return JobScheduler.PENDING_JOB_REASON_APP_STANDBY; - } - if ((CONSTRAINT_CONNECTIVITY & unsatisfiedConstraints) != 0) { - return JobScheduler.PENDING_JOB_REASON_CONSTRAINT_CONNECTIVITY; - } - if ((CONSTRAINT_CONTENT_TRIGGER & unsatisfiedConstraints) != 0) { - return JobScheduler.PENDING_JOB_REASON_CONSTRAINT_CONTENT_TRIGGER; - } - if ((CONSTRAINT_DEVICE_NOT_DOZING & unsatisfiedConstraints) != 0) { - return JobScheduler.PENDING_JOB_REASON_DEVICE_STATE; - } - if ((CONSTRAINT_FLEXIBLE & unsatisfiedConstraints) != 0) { - return JobScheduler.PENDING_JOB_REASON_JOB_SCHEDULER_OPTIMIZATION; } if ((CONSTRAINT_IDLE & unsatisfiedConstraints) != 0) { if ((CONSTRAINT_IDLE & requiredConstraints) != 0) { // The developer requested this constraint, so it makes sense to return the // explicit constraint reason. - return JobScheduler.PENDING_JOB_REASON_CONSTRAINT_DEVICE_IDLE; + reasons.addLast(JobScheduler.PENDING_JOB_REASON_CONSTRAINT_DEVICE_IDLE); + } else { + // Hard-coding right now since the current dynamic constraint sets don't overlap + // TODO: return based on active dynamic constraint sets when they start overlapping + if (!reasons.contains(JobScheduler.PENDING_JOB_REASON_APP_STANDBY)) { + reasons.addLast(JobScheduler.PENDING_JOB_REASON_APP_STANDBY); + } } - // Hard-coding right now since the current dynamic constraint sets don't overlap - // TODO: return based on active dynamic constraint sets when they start overlapping - return JobScheduler.PENDING_JOB_REASON_APP_STANDBY; + } + + if ((CONSTRAINT_CONNECTIVITY & unsatisfiedConstraints) != 0) { + reasons.addLast(JobScheduler.PENDING_JOB_REASON_CONSTRAINT_CONNECTIVITY); + } + if ((CONSTRAINT_CONTENT_TRIGGER & unsatisfiedConstraints) != 0) { + reasons.addLast(JobScheduler.PENDING_JOB_REASON_CONSTRAINT_CONTENT_TRIGGER); + } + if ((CONSTRAINT_FLEXIBLE & unsatisfiedConstraints) != 0) { + reasons.addLast(JobScheduler.PENDING_JOB_REASON_JOB_SCHEDULER_OPTIMIZATION); } if ((CONSTRAINT_PREFETCH & unsatisfiedConstraints) != 0) { - return JobScheduler.PENDING_JOB_REASON_CONSTRAINT_PREFETCH; + reasons.addLast(JobScheduler.PENDING_JOB_REASON_CONSTRAINT_PREFETCH); } if ((CONSTRAINT_STORAGE_NOT_LOW & unsatisfiedConstraints) != 0) { - return JobScheduler.PENDING_JOB_REASON_CONSTRAINT_STORAGE_NOT_LOW; + reasons.addLast(JobScheduler.PENDING_JOB_REASON_CONSTRAINT_STORAGE_NOT_LOW); } if ((CONSTRAINT_TIMING_DELAY & unsatisfiedConstraints) != 0) { - return JobScheduler.PENDING_JOB_REASON_CONSTRAINT_MINIMUM_LATENCY; + reasons.addLast(JobScheduler.PENDING_JOB_REASON_CONSTRAINT_MINIMUM_LATENCY); } if ((CONSTRAINT_WITHIN_QUOTA & unsatisfiedConstraints) != 0) { - return JobScheduler.PENDING_JOB_REASON_QUOTA; + reasons.addLast(JobScheduler.PENDING_JOB_REASON_QUOTA); } - - if (getEffectiveStandbyBucket() == NEVER_INDEX) { - Slog.wtf(TAG, "App in NEVER bucket querying pending job reason"); - // The user hasn't officially launched this app. - return JobScheduler.PENDING_JOB_REASON_USER; + if (android.app.job.Flags.getPendingJobReasonsApi()) { + if ((CONSTRAINT_DEADLINE & unsatisfiedConstraints) != 0) { + reasons.addLast(JobScheduler.PENDING_JOB_REASON_CONSTRAINT_DEADLINE); + } } - if (serviceProcessName != null) { - return JobScheduler.PENDING_JOB_REASON_APP; + + if (reasons.isEmpty()) { + if (getEffectiveStandbyBucket() == NEVER_INDEX) { + Slog.wtf(TAG, "App in NEVER bucket querying pending job reason"); + // The user hasn't officially launched this app. + reasons.add(JobScheduler.PENDING_JOB_REASON_USER); + } else if (serviceProcessName != null) { + reasons.add(JobScheduler.PENDING_JOB_REASON_APP); + } else { + reasons.add(JobScheduler.PENDING_JOB_REASON_UNDEFINED); + } } - if (!isReady()) { - Slog.wtf(TAG, "Unknown reason job isn't ready"); + final int[] reasonsArr = new int[reasons.size()]; + for (int i = 0; i < reasonsArr.length; i++) { + reasonsArr[i] = reasons.get(i); } - return JobScheduler.PENDING_JOB_REASON_UNDEFINED; + return reasonsArr; } /** @return whether or not the @param constraint is satisfied */ diff --git a/api/Android.bp b/api/Android.bp index ff674c7f8bd37c89472f47e9dc73205d1fd2ecfd..cdc5cd120956408026e5bced483e2a93b07b13fc 100644 --- a/api/Android.bp +++ b/api/Android.bp @@ -73,6 +73,7 @@ combined_apis { "framework-bluetooth", "framework-configinfrastructure", "framework-connectivity", + "framework-connectivity-b", "framework-connectivity-t", "framework-devicelock", "framework-graphics", @@ -126,27 +127,54 @@ combined_apis { }), } +// Create a single file containing the latest released version of the whole +// Android public API. +java_genrule { + name: "android.api.merged.public.latest", + srcs: [ + ":android.api.combined.public.latest", + ], + out: ["public-latest.txt"], + tools: ["metalava"], + cmd: metalava_cmd + " merge-signatures --format=2.0 $(in) --out $(out)", +} + +// Make sure that the Android public API is compatible with the +// previously released public API. java_genrule { name: "frameworks-base-api-current-compat", srcs: [ - ":android.api.public.latest", + ":android.api.merged.public.latest", ":android-incompatibilities.api.public.latest", ":frameworks-base-api-current.txt", ], out: ["updated-baseline.txt"], tools: ["metalava"], cmd: metalava_cmd + - "--check-compatibility:api:released $(location :android.api.public.latest) " + + "--check-compatibility:api:released $(location :android.api.merged.public.latest) " + "--baseline:compatibility:released $(location :android-incompatibilities.api.public.latest) " + "--update-baseline:compatibility:released $(genDir)/updated-baseline.txt " + "$(location :frameworks-base-api-current.txt)", } +// Create a single file containing the latest released version of the whole +// Android system API. +java_genrule { + name: "android.api.merged.system.latest", + srcs: [ + ":android.api.combined.system.latest", + ], + out: ["system-latest.txt"], + tools: ["metalava"], + cmd: metalava_cmd + " merge-signatures --format=2.0 $(in) --out $(out)", +} + +// Make sure that the Android system API is compatible with the +// previously released system API. java_genrule { name: "frameworks-base-api-system-current-compat", srcs: [ - ":android.api.public.latest", - ":android.api.system.latest", + ":android.api.merged.system.latest", ":android-incompatibilities.api.system.latest", ":frameworks-base-api-current.txt", ":frameworks-base-api-system-current.txt", @@ -154,20 +182,31 @@ java_genrule { out: ["updated-baseline.txt"], tools: ["metalava"], cmd: metalava_cmd + - "--check-compatibility:api:released $(location :android.api.public.latest) " + - "--check-compatibility:api:released $(location :android.api.system.latest) " + + "--check-compatibility:api:released $(location :android.api.merged.system.latest) " + "--baseline:compatibility:released $(location :android-incompatibilities.api.system.latest) " + "--update-baseline:compatibility:released $(genDir)/updated-baseline.txt " + "$(location :frameworks-base-api-current.txt) " + "$(location :frameworks-base-api-system-current.txt)", } +// Create a single file containing the latest released version of the whole +// Android module-lib API. +java_genrule { + name: "android.api.merged.module-lib.latest", + srcs: [ + ":android.api.combined.module-lib.latest", + ], + out: ["module-lib-latest.txt"], + tools: ["metalava"], + cmd: metalava_cmd + " merge-signatures --format=2.0 $(in) --out $(out)", +} + +// Make sure that the Android module-lib API is compatible with the +// previously released module-lib API. java_genrule { name: "frameworks-base-api-module-lib-current-compat", srcs: [ - ":android.api.public.latest", - ":android.api.system.latest", - ":android.api.module-lib.latest", + ":android.api.merged.module-lib.latest", ":android-incompatibilities.api.module-lib.latest", ":frameworks-base-api-current.txt", ":frameworks-base-api-system-current.txt", @@ -176,9 +215,7 @@ java_genrule { out: ["updated-baseline.txt"], tools: ["metalava"], cmd: metalava_cmd + - "--check-compatibility:api:released $(location :android.api.public.latest) " + - "--check-compatibility:api:released $(location :android.api.system.latest) " + - "--check-compatibility:api:released $(location :android.api.module-lib.latest) " + + "--check-compatibility:api:released $(location :android.api.merged.module-lib.latest) " + "--baseline:compatibility:released $(location :android-incompatibilities.api.module-lib.latest) " + "--update-baseline:compatibility:released $(genDir)/updated-baseline.txt " + "$(location :frameworks-base-api-current.txt) " + @@ -193,7 +230,7 @@ java_genrule { cmd: "$(location merge_zips) $(out) $(in)", srcs: [ ":api-stubs-docs-non-updatable{.exportable}", - ":all-modules-public-stubs-source", + ":all-modules-public-stubs-source-exportable", ], visibility: ["//visibility:private"], // Used by make module in //development, mind } diff --git a/api/ApiDocs.bp b/api/ApiDocs.bp index e8fcf4b2b32daa065c98c544835847f8939e86c0..1ebe0cdfabd70eba75c0b50e37f51d31df587b9e 100644 --- a/api/ApiDocs.bp +++ b/api/ApiDocs.bp @@ -129,7 +129,7 @@ droidstubs { droidstubs { name: "framework-doc-stubs", defaults: ["android-non-updatable-doc-stubs-defaults"], - srcs: [":all-modules-public-stubs-source"], + srcs: [":all-modules-public-stubs-source-exportable"], api_levels_module: "api_versions_public", aidl: { include_dirs: [ diff --git a/api/api.go b/api/api.go index f32bdc32f75de960acb57b2dd2cf2ff78eb12252..5ca24de1b46acb29603439978194363f411eaeb7 100644 --- a/api/api.go +++ b/api/api.go @@ -429,8 +429,9 @@ func createMergedFrameworkSystemServerExportableStubs(ctx android.LoadHookContex func createPublicStubsSourceFilegroup(ctx android.LoadHookContext, modules proptools.Configurable[[]string]) { props := fgProps{} - props.Name = proptools.StringPtr("all-modules-public-stubs-source") - props.Device_common_srcs = createSrcs(modules, "{.public.stubs.source}") + props.Name = proptools.StringPtr("all-modules-public-stubs-source-exportable") + transformConfigurableArray(modules, "", ".stubs.source") + props.Device_common_srcs = createSrcs(modules, "{.exportable}") props.Visibility = []string{"//frameworks/base"} ctx.CreateModule(android.FileGroupFactory, &props) } diff --git a/cmds/idmap2/libidmap2/ResourceContainer.cpp b/cmds/idmap2/libidmap2/ResourceContainer.cpp index 3c0e118bbfe76f09af9db8ae12ad340554f79ed7..57ae3548123b738971ff1c70394e40f244fdd52a 100644 --- a/cmds/idmap2/libidmap2/ResourceContainer.cpp +++ b/cmds/idmap2/libidmap2/ResourceContainer.cpp @@ -17,6 +17,7 @@ #include "idmap2/ResourceContainer.h" #include +#include #include #include #include @@ -296,7 +297,7 @@ struct ResState { } // namespace struct ApkResourceContainer : public TargetResourceContainer, public OverlayResourceContainer { - static Result> FromPath(const std::string& path); + static Result> FromPath(std::string path); // inherited from TargetResourceContainer Result DefinesOverlayable() const override; @@ -320,6 +321,7 @@ struct ApkResourceContainer : public TargetResourceContainer, public OverlayReso Result GetState() const; ZipAssetsProvider* GetZipAssets() const; + mutable std::mutex state_lock_; mutable std::variant, ResState> state_; std::string path_; }; @@ -330,16 +332,17 @@ ApkResourceContainer::ApkResourceContainer(std::unique_ptr zi } Result> ApkResourceContainer::FromPath( - const std::string& path) { + std::string path) { auto zip_assets = ZipAssetsProvider::Create(path, 0 /* flags */); if (zip_assets == nullptr) { return Error("failed to load zip assets"); } return std::unique_ptr( - new ApkResourceContainer(std::move(zip_assets), path)); + new ApkResourceContainer(std::move(zip_assets), std::move(path))); } Result ApkResourceContainer::GetState() const { + std::lock_guard lock(state_lock_); if (auto state = std::get_if(&state_); state != nullptr) { return state; } @@ -355,6 +358,7 @@ Result ApkResourceContainer::GetState() const { } ZipAssetsProvider* ApkResourceContainer::GetZipAssets() const { + std::lock_guard lock(state_lock_); if (auto zip = std::get_if>(&state_); zip != nullptr) { return zip->get(); } @@ -427,7 +431,7 @@ Result ApkResourceContainer::GetResourceName(ResourceId id) const { Result> TargetResourceContainer::FromPath( std::string path) { - auto result = ApkResourceContainer::FromPath(path); + auto result = ApkResourceContainer::FromPath(std::move(path)); if (!result) { return result.GetError(); } @@ -438,7 +442,7 @@ Result> OverlayResourceContainer::From std::string path) { // Load the path as a fabricated overlay if the file magic indicates this is a fabricated overlay. if (android::IsFabricatedOverlay(path)) { - auto result = FabricatedOverlayContainer::FromPath(path); + auto result = FabricatedOverlayContainer::FromPath(std::move(path)); if (!result) { return result.GetError(); } @@ -446,7 +450,7 @@ Result> OverlayResourceContainer::From } // Fallback to loading the container as an APK. - auto result = ApkResourceContainer::FromPath(path); + auto result = ApkResourceContainer::FromPath(std::move(path)); if (!result) { return result.GetError(); } diff --git a/config/preloaded-classes-denylist b/config/preloaded-classes-denylist index a413bbd68f60f1d43ab70cd22b96caedc1f266de..16f0693946399df6a670ff7b29ed7be892b29e84 100644 --- a/config/preloaded-classes-denylist +++ b/config/preloaded-classes-denylist @@ -1,13 +1,16 @@ android.content.AsyncTaskLoader$LoadTask +android.media.MediaCodecInfo$CodecCapabilities$FeatureList android.net.ConnectivityThread$Singleton android.os.FileObserver android.os.NullVibrator +android.permission.PermissionManager +android.provider.MediaStore android.speech.tts.TextToSpeech$Connection$SetupConnectionAsyncTask +android.view.HdrRenderState android.widget.Magnifier +com.android.internal.jank.InteractionJankMonitor$InstanceHolder +com.android.internal.util.LatencyTracker$SLatencyTrackerHolder gov.nist.core.net.DefaultNetworkLayer -android.net.rtp.AudioGroup -android.net.rtp.AudioStream -android.net.rtp.RtpStream java.util.concurrent.ThreadLocalRandom java.util.ImmutableCollections -com.android.internal.jank.InteractionJankMonitor$InstanceHolder +sun.nio.fs.UnixChannelFactory diff --git a/core/api/current.txt b/core/api/current.txt index 2cb7a30eb28caf7eb8cb4cfc23820ebbc48770d5..2f5bde9d37f274d716bdfd2dbe6a7881646738eb 100644 --- a/core/api/current.txt +++ b/core/api/current.txt @@ -241,6 +241,7 @@ package android { field public static final String PROVIDE_REMOTE_CREDENTIALS = "android.permission.PROVIDE_REMOTE_CREDENTIALS"; field @FlaggedApi("android.security.aapm_api") public static final String QUERY_ADVANCED_PROTECTION_MODE = "android.permission.QUERY_ADVANCED_PROTECTION_MODE"; field public static final String QUERY_ALL_PACKAGES = "android.permission.QUERY_ALL_PACKAGES"; + field @FlaggedApi("android.permission.flags.ranging_permission_enabled") public static final String RANGING = "android.permission.RANGING"; field public static final String READ_ASSISTANT_APP_SEARCH_DATA = "android.permission.READ_ASSISTANT_APP_SEARCH_DATA"; field public static final String READ_BASIC_PHONE_STATE = "android.permission.READ_BASIC_PHONE_STATE"; field public static final String READ_CALENDAR = "android.permission.READ_CALENDAR"; @@ -262,6 +263,7 @@ package android { field public static final String READ_SMS = "android.permission.READ_SMS"; field public static final String READ_SYNC_SETTINGS = "android.permission.READ_SYNC_SETTINGS"; field public static final String READ_SYNC_STATS = "android.permission.READ_SYNC_STATS"; + field @FlaggedApi("com.android.settingslib.flags.settings_catalyst") public static final String READ_SYSTEM_PREFERENCES = "android.permission.READ_SYSTEM_PREFERENCES"; field public static final String READ_VOICEMAIL = "com.android.voicemail.permission.READ_VOICEMAIL"; field public static final String REBOOT = "android.permission.REBOOT"; field public static final String RECEIVE_BOOT_COMPLETED = "android.permission.RECEIVE_BOOT_COMPLETED"; @@ -312,6 +314,7 @@ package android { field public static final String SYSTEM_ALERT_WINDOW = "android.permission.SYSTEM_ALERT_WINDOW"; field public static final String TRANSMIT_IR = "android.permission.TRANSMIT_IR"; field public static final String TURN_SCREEN_ON = "android.permission.TURN_SCREEN_ON"; + field @FlaggedApi("android.app.enable_tv_implicit_enter_pip_restriction") public static final String TV_IMPLICIT_ENTER_PIP = "android.permission.TV_IMPLICIT_ENTER_PIP"; field public static final String UNINSTALL_SHORTCUT = "com.android.launcher.permission.UNINSTALL_SHORTCUT"; field public static final String UPDATE_DEVICE_STATS = "android.permission.UPDATE_DEVICE_STATS"; field public static final String UPDATE_PACKAGES_WITHOUT_USER_ACTION = "android.permission.UPDATE_PACKAGES_WITHOUT_USER_ACTION"; @@ -333,6 +336,7 @@ package android { field public static final String WRITE_SECURE_SETTINGS = "android.permission.WRITE_SECURE_SETTINGS"; field public static final String WRITE_SETTINGS = "android.permission.WRITE_SETTINGS"; field public static final String WRITE_SYNC_SETTINGS = "android.permission.WRITE_SYNC_SETTINGS"; + field @FlaggedApi("com.android.settingslib.flags.settings_catalyst") public static final String WRITE_SYSTEM_PREFERENCES = "android.permission.WRITE_SYSTEM_PREFERENCES"; field public static final String WRITE_VOICEMAIL = "com.android.voicemail.permission.WRITE_VOICEMAIL"; } @@ -474,6 +478,8 @@ package android { field public static final int alpha = 16843551; // 0x101031f field public static final int alphabeticModifiers = 16844110; // 0x101054e field public static final int alphabeticShortcut = 16843235; // 0x10101e3 + field @FlaggedApi("android.content.pm.change_launcher_badging") public static final int alternateLauncherIcons; + field @FlaggedApi("android.content.pm.change_launcher_badging") public static final int alternateLauncherLabels; field public static final int alwaysDrawnWithCache = 16842991; // 0x10100ef field public static final int alwaysRetainTaskState = 16843267; // 0x1010203 field @Deprecated public static final int amPmBackgroundColor = 16843941; // 0x10104a5 @@ -1074,6 +1080,7 @@ package android { field public static final int layout = 16842994; // 0x10100f2 field public static final int layoutAnimation = 16842988; // 0x10100ec field public static final int layoutDirection = 16843698; // 0x10103b2 + field @FlaggedApi("android.view.inputmethod.ime_switcher_revamp_api") public static final int layoutLabel; field public static final int layoutMode = 16843738; // 0x10103da field public static final int layout_above = 16843140; // 0x1010184 field public static final int layout_alignBaseline = 16843142; // 0x1010186 @@ -8023,6 +8030,7 @@ package android.app.admin { field @FlaggedApi("android.view.contentprotection.flags.manage_device_policy_enabled") public static final String CONTENT_PROTECTION_POLICY = "contentProtection"; field public static final String KEYGUARD_DISABLED_FEATURES_POLICY = "keyguardDisabledFeatures"; field public static final String LOCK_TASK_POLICY = "lockTask"; + field @FlaggedApi("android.app.admin.flags.set_mte_policy_coexistence") public static final String MEMORY_TAGGING_POLICY = "memoryTagging"; field public static final String PACKAGES_SUSPENDED_POLICY = "packagesSuspended"; field public static final String PACKAGE_UNINSTALL_BLOCKED_POLICY = "packageUninstallBlocked"; field public static final String PASSWORD_COMPLEXITY_POLICY = "passwordComplexity"; @@ -8784,8 +8792,31 @@ package android.app.admin { package android.app.appfunctions { + @FlaggedApi("android.app.appfunctions.flags.enable_app_function_manager") public final class AppFunctionException extends java.lang.Exception implements android.os.Parcelable { + ctor public AppFunctionException(int, @Nullable String); + ctor public AppFunctionException(int, @Nullable String, @NonNull android.os.Bundle); + method public int describeContents(); + method public int getErrorCategory(); + method public int getErrorCode(); + method @Nullable public String getErrorMessage(); + method @NonNull public android.os.Bundle getExtras(); + 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_APP_UNKNOWN_ERROR = 3000; // 0xbb8 + field public static final int ERROR_CANCELLED = 2001; // 0x7d1 + field public static final int ERROR_CATEGORY_APP = 3; // 0x3 + field public static final int ERROR_CATEGORY_REQUEST_ERROR = 1; // 0x1 + field public static final int ERROR_CATEGORY_SYSTEM = 2; // 0x2 + field public static final int ERROR_CATEGORY_UNKNOWN = 0; // 0x0 + field public static final int ERROR_DENIED = 1000; // 0x3e8 + field public static final int ERROR_DISABLED = 1002; // 0x3ea + field public static final int ERROR_FUNCTION_NOT_FOUND = 1003; // 0x3eb + field public static final int ERROR_INVALID_ARGUMENT = 1001; // 0x3e9 + field public static final int ERROR_SYSTEM_ERROR = 2000; // 0x7d0 + } + @FlaggedApi("android.app.appfunctions.flags.enable_app_function_manager") public final class AppFunctionManager { - method @RequiresPermission(anyOf={"android.permission.EXECUTE_APP_FUNCTIONS_TRUSTED", "android.permission.EXECUTE_APP_FUNCTIONS"}, conditional=true) public void executeAppFunction(@NonNull android.app.appfunctions.ExecuteAppFunctionRequest, @NonNull java.util.concurrent.Executor, @NonNull android.os.CancellationSignal, @NonNull java.util.function.Consumer); + method @RequiresPermission(anyOf={"android.permission.EXECUTE_APP_FUNCTIONS_TRUSTED", "android.permission.EXECUTE_APP_FUNCTIONS"}, conditional=true) public void executeAppFunction(@NonNull android.app.appfunctions.ExecuteAppFunctionRequest, @NonNull java.util.concurrent.Executor, @NonNull android.os.CancellationSignal, @NonNull android.os.OutcomeReceiver); method @RequiresPermission(anyOf={"android.permission.EXECUTE_APP_FUNCTIONS_TRUSTED", "android.permission.EXECUTE_APP_FUNCTIONS"}, conditional=true) public void isAppFunctionEnabled(@NonNull String, @NonNull String, @NonNull java.util.concurrent.Executor, @NonNull android.os.OutcomeReceiver); method public void isAppFunctionEnabled(@NonNull String, @NonNull java.util.concurrent.Executor, @NonNull android.os.OutcomeReceiver); method public void setAppFunctionEnabled(@NonNull String, int, @NonNull java.util.concurrent.Executor, @NonNull android.os.OutcomeReceiver); @@ -8797,7 +8828,7 @@ package android.app.appfunctions { @FlaggedApi("android.app.appfunctions.flags.enable_app_function_manager") public abstract class AppFunctionService extends android.app.Service { ctor public AppFunctionService(); method @NonNull public final android.os.IBinder onBind(@Nullable android.content.Intent); - method @MainThread public abstract void onExecuteFunction(@NonNull android.app.appfunctions.ExecuteAppFunctionRequest, @NonNull String, @NonNull android.os.CancellationSignal, @NonNull java.util.function.Consumer); + method @MainThread public abstract void onExecuteFunction(@NonNull android.app.appfunctions.ExecuteAppFunctionRequest, @NonNull String, @NonNull android.os.CancellationSignal, @NonNull android.os.OutcomeReceiver); field @NonNull public static final String SERVICE_INTERFACE = "android.app.appfunctions.AppFunctionService"; } @@ -8819,30 +8850,14 @@ package android.app.appfunctions { } @FlaggedApi("android.app.appfunctions.flags.enable_app_function_manager") public final class ExecuteAppFunctionResponse implements android.os.Parcelable { + ctor public ExecuteAppFunctionResponse(@NonNull android.app.appsearch.GenericDocument); + ctor public ExecuteAppFunctionResponse(@NonNull android.app.appsearch.GenericDocument, @NonNull android.os.Bundle); method public int describeContents(); - method public int getErrorCategory(); - method @Nullable public String getErrorMessage(); method @NonNull public android.os.Bundle getExtras(); - method public int getResultCode(); method @NonNull public android.app.appsearch.GenericDocument getResultDocument(); - method public boolean isSuccess(); - method @FlaggedApi("android.app.appfunctions.flags.enable_app_function_manager") @NonNull public static android.app.appfunctions.ExecuteAppFunctionResponse newFailure(int, @Nullable String, @Nullable android.os.Bundle); - method @FlaggedApi("android.app.appfunctions.flags.enable_app_function_manager") @NonNull public static android.app.appfunctions.ExecuteAppFunctionResponse newSuccess(@NonNull android.app.appsearch.GenericDocument, @Nullable android.os.Bundle); 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_CATEGORY_APP = 3; // 0x3 - field public static final int ERROR_CATEGORY_REQUEST_ERROR = 1; // 0x1 - field public static final int ERROR_CATEGORY_SYSTEM = 2; // 0x2 - field public static final int ERROR_CATEGORY_UNKNOWN = 0; // 0x0 - field public static final String PROPERTY_RETURN_VALUE = "returnValue"; - field public static final int RESULT_APP_UNKNOWN_ERROR = 3000; // 0xbb8 - field public static final int RESULT_CANCELLED = 2001; // 0x7d1 - field public static final int RESULT_DENIED = 1000; // 0x3e8 - field public static final int RESULT_DISABLED = 1002; // 0x3ea - field public static final int RESULT_FUNCTION_NOT_FOUND = 1003; // 0x3eb - field public static final int RESULT_INVALID_ARGUMENT = 1001; // 0x3e9 - field public static final int RESULT_OK = 0; // 0x0 - field public static final int RESULT_SYSTEM_ERROR = 2000; // 0x7d0 + field public static final String PROPERTY_RETURN_VALUE = "androidAppfunctionsReturnValue"; } } @@ -8865,6 +8880,7 @@ package android.app.assist { method public void setWebUri(android.net.Uri); method public void writeToParcel(android.os.Parcel, int); field @NonNull public static final android.os.Parcelable.Creator CREATOR; + field @FlaggedApi("android.app.appfunctions.flags.enable_app_function_manager") public static final String EXTRA_APP_FUNCTION_DATA = "android.app.assist.extra.APP_FUNCTION_DATA"; } public class AssistStructure implements android.os.Parcelable { @@ -9245,6 +9261,7 @@ package android.app.job { method @Nullable public String getNamespace(); method @Nullable public abstract android.app.job.JobInfo getPendingJob(int); method public int getPendingJobReason(int); + method @FlaggedApi("android.app.job.get_pending_job_reasons_api") @NonNull public int[] getPendingJobReasons(int); method @NonNull public java.util.Map> getPendingJobsInAllNamespaces(); method public abstract int schedule(@NonNull android.app.job.JobInfo); field public static final int PENDING_JOB_REASON_APP = 1; // 0x1 @@ -9254,6 +9271,7 @@ package android.app.job { field public static final int PENDING_JOB_REASON_CONSTRAINT_CHARGING = 5; // 0x5 field public static final int PENDING_JOB_REASON_CONSTRAINT_CONNECTIVITY = 6; // 0x6 field public static final int PENDING_JOB_REASON_CONSTRAINT_CONTENT_TRIGGER = 7; // 0x7 + field @FlaggedApi("android.app.job.get_pending_job_reasons_api") public static final int PENDING_JOB_REASON_CONSTRAINT_DEADLINE = 16; // 0x10 field public static final int PENDING_JOB_REASON_CONSTRAINT_DEVICE_IDLE = 8; // 0x8 field public static final int PENDING_JOB_REASON_CONSTRAINT_MINIMUM_LATENCY = 9; // 0x9 field public static final int PENDING_JOB_REASON_CONSTRAINT_PREFETCH = 10; // 0xa @@ -9687,10 +9705,8 @@ package android.app.wallpaper { method @Nullable public String getId(); method @Nullable public android.net.Uri getThumbnail(); method @Nullable public CharSequence getTitle(); - method @NonNull public static android.app.wallpaper.WallpaperDescription readFromStream(@NonNull java.io.InputStream) throws java.io.IOException; method @NonNull public android.app.wallpaper.WallpaperDescription.Builder toBuilder(); method public void writeToParcel(@NonNull android.os.Parcel, int); - method public void writeToStream(@NonNull java.io.OutputStream) throws java.io.IOException; field @NonNull public static final android.os.Parcelable.Creator CREATOR; } @@ -12732,6 +12748,7 @@ package android.content.pm { method public abstract void onPackagesUnavailable(String[], android.os.UserHandle, boolean); method public void onPackagesUnsuspended(String[], android.os.UserHandle); method public void onShortcutsChanged(@NonNull String, @NonNull java.util.List, @NonNull android.os.UserHandle); + method @FlaggedApi("android.multiuser.add_launcher_user_config") public void onUserConfigChanged(@NonNull android.content.pm.LauncherUserInfo); } public static final class LauncherApps.PinItemRequest implements android.os.Parcelable { @@ -12767,10 +12784,12 @@ package android.content.pm { @FlaggedApi("android.os.allow_private_profile") public final class LauncherUserInfo implements android.os.Parcelable { method @FlaggedApi("android.os.allow_private_profile") public int describeContents(); + method @FlaggedApi("android.multiuser.add_launcher_user_config") @NonNull public android.os.Bundle getUserConfig(); method @FlaggedApi("android.os.allow_private_profile") public int getUserSerialNumber(); method @FlaggedApi("android.os.allow_private_profile") @NonNull public String getUserType(); method @FlaggedApi("android.os.allow_private_profile") public void writeToParcel(@NonNull android.os.Parcel, int); field @FlaggedApi("android.os.allow_private_profile") @NonNull public static final android.os.Parcelable.Creator CREATOR; + field @FlaggedApi("android.multiuser.add_launcher_user_config") public static final String PRIVATE_SPACE_ENTRYPOINT_HIDDEN = "private_space_entrypoint_hidden"; } public final class ModuleInfo implements android.os.Parcelable { @@ -13701,7 +13720,7 @@ package android.content.pm { field public static final int FLAG_STOP_WITH_TASK = 1; // 0x1 field public static final int FLAG_USE_APP_ZYGOTE = 8; // 0x8 field @RequiresPermission(allOf={android.Manifest.permission.FOREGROUND_SERVICE_CAMERA}, anyOf={android.Manifest.permission.CAMERA}, conditional=true) public static final int FOREGROUND_SERVICE_TYPE_CAMERA = 64; // 0x40 - field @RequiresPermission(allOf={android.Manifest.permission.FOREGROUND_SERVICE_CONNECTED_DEVICE}, anyOf={android.Manifest.permission.BLUETOOTH_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}, conditional=true) public static final int FOREGROUND_SERVICE_TYPE_CONNECTED_DEVICE = 16; // 0x10 + 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 @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 @@ -16418,6 +16437,7 @@ package android.graphics { field public static final int FLEX_RGBA_8888 = 42; // 0x2a field public static final int FLEX_RGB_888 = 41; // 0x29 field public static final int HEIC = 1212500294; // 0x48454946 + field @FlaggedApi("com.android.internal.camera.flags.camera_heif_gainmap") public static final int HEIC_ULTRAHDR = 4102; // 0x1006 field public static final int JPEG = 256; // 0x100 field public static final int JPEG_R = 4101; // 0x1005 field public static final int NV16 = 16; // 0x10 @@ -16844,6 +16864,7 @@ package android.graphics { field @FlaggedApi("com.android.text.flags.letter_spacing_justification") public static final int TEXT_RUN_FLAG_LEFT_EDGE = 8192; // 0x2000 field @FlaggedApi("com.android.text.flags.letter_spacing_justification") public static final int TEXT_RUN_FLAG_RIGHT_EDGE = 16384; // 0x4000 field public static final int UNDERLINE_TEXT_FLAG = 8; // 0x8 + field @FlaggedApi("com.android.text.flags.vertical_text_layout") public static final int VERTICAL_TEXT_FLAG = 4096; // 0x1000 } public enum Paint.Align { @@ -18708,6 +18729,7 @@ package android.hardware { field public static final int DATASPACE_DISPLAY_P3 = 143261696; // 0x88a0000 field public static final int DATASPACE_DYNAMIC_DEPTH = 4098; // 0x1002 field public static final int DATASPACE_HEIF = 4100; // 0x1004 + field @FlaggedApi("com.android.internal.camera.flags.camera_heif_gainmap") public static final int DATASPACE_HEIF_ULTRAHDR = 4102; // 0x1006 field public static final int DATASPACE_JFIF = 146931712; // 0x8c20000 field public static final int DATASPACE_JPEG_R = 4101; // 0x1005 field public static final int DATASPACE_SCRGB = 411107328; // 0x18810000 @@ -19761,6 +19783,8 @@ package android.hardware.camera2 { field public static final int CONTROL_VIDEO_STABILIZATION_MODE_OFF = 0; // 0x0 field public static final int CONTROL_VIDEO_STABILIZATION_MODE_ON = 1; // 0x1 field public static final int CONTROL_VIDEO_STABILIZATION_MODE_PREVIEW_STABILIZATION = 2; // 0x2 + field @FlaggedApi("com.android.internal.camera.flags.zoom_method") public static final int CONTROL_ZOOM_METHOD_AUTO = 0; // 0x0 + field @FlaggedApi("com.android.internal.camera.flags.zoom_method") public static final int CONTROL_ZOOM_METHOD_ZOOM_RATIO = 1; // 0x1 field public static final int DISTORTION_CORRECTION_MODE_FAST = 1; // 0x1 field public static final int DISTORTION_CORRECTION_MODE_HIGH_QUALITY = 2; // 0x2 field public static final int DISTORTION_CORRECTION_MODE_OFF = 0; // 0x0 @@ -19768,6 +19792,9 @@ package android.hardware.camera2 { field public static final int EDGE_MODE_HIGH_QUALITY = 2; // 0x2 field public static final int EDGE_MODE_OFF = 0; // 0x0 field public static final int EDGE_MODE_ZERO_SHUTTER_LAG = 3; // 0x3 + field @FlaggedApi("com.android.internal.camera.flags.night_mode_indicator") public static final int EXTENSION_NIGHT_MODE_INDICATOR_OFF = 1; // 0x1 + field @FlaggedApi("com.android.internal.camera.flags.night_mode_indicator") public static final int EXTENSION_NIGHT_MODE_INDICATOR_ON = 2; // 0x2 + field @FlaggedApi("com.android.internal.camera.flags.night_mode_indicator") public static final int EXTENSION_NIGHT_MODE_INDICATOR_UNKNOWN = 0; // 0x0 field public static final int FLASH_MODE_OFF = 0; // 0x0 field public static final int FLASH_MODE_SINGLE = 1; // 0x1 field public static final int FLASH_MODE_TORCH = 2; // 0x2 @@ -19965,6 +19992,7 @@ package android.hardware.camera2 { field @NonNull public static final android.hardware.camera2.CaptureRequest.Key CONTROL_SCENE_MODE; field @NonNull public static final android.hardware.camera2.CaptureRequest.Key CONTROL_SETTINGS_OVERRIDE; field @NonNull public static final android.hardware.camera2.CaptureRequest.Key CONTROL_VIDEO_STABILIZATION_MODE; + field @FlaggedApi("com.android.internal.camera.flags.zoom_method") @NonNull public static final android.hardware.camera2.CaptureRequest.Key CONTROL_ZOOM_METHOD; field @NonNull public static final android.hardware.camera2.CaptureRequest.Key CONTROL_ZOOM_RATIO; field @NonNull public static final android.os.Parcelable.Creator CREATOR; field @NonNull public static final android.hardware.camera2.CaptureRequest.Key DISTORTION_CORRECTION_MODE; @@ -20063,10 +20091,12 @@ package android.hardware.camera2 { field @NonNull public static final android.hardware.camera2.CaptureResult.Key CONTROL_SCENE_MODE; field @NonNull public static final android.hardware.camera2.CaptureResult.Key CONTROL_SETTINGS_OVERRIDE; field @NonNull public static final android.hardware.camera2.CaptureResult.Key CONTROL_VIDEO_STABILIZATION_MODE; + field @FlaggedApi("com.android.internal.camera.flags.zoom_method") @NonNull public static final android.hardware.camera2.CaptureResult.Key CONTROL_ZOOM_METHOD; field @NonNull public static final android.hardware.camera2.CaptureResult.Key CONTROL_ZOOM_RATIO; field @NonNull public static final android.hardware.camera2.CaptureResult.Key DISTORTION_CORRECTION_MODE; field @NonNull public static final android.hardware.camera2.CaptureResult.Key EDGE_MODE; field @NonNull public static final android.hardware.camera2.CaptureResult.Key EXTENSION_CURRENT_TYPE; + field @FlaggedApi("com.android.internal.camera.flags.night_mode_indicator") @NonNull public static final android.hardware.camera2.CaptureResult.Key EXTENSION_NIGHT_MODE_INDICATOR; field @NonNull public static final android.hardware.camera2.CaptureResult.Key EXTENSION_STRENGTH; field @NonNull public static final android.hardware.camera2.CaptureResult.Key FLASH_MODE; field @NonNull public static final android.hardware.camera2.CaptureResult.Key FLASH_STATE; @@ -23964,6 +23994,7 @@ package android.media { field public static final String KEY_MPEGH_COMPATIBLE_SETS = "mpegh-compatible-sets"; field public static final String KEY_MPEGH_PROFILE_LEVEL_INDICATION = "mpegh-profile-level-indication"; field public static final String KEY_MPEGH_REFERENCE_CHANNEL_LAYOUT = "mpegh-reference-channel-layout"; + field @FlaggedApi("android.media.codec.num_input_slots") public static final String KEY_NUM_SLOTS = "num-slots"; 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"; @@ -24660,6 +24691,7 @@ package android.media { field @FlaggedApi("com.android.media.flags.enable_built_in_speaker_route_suitability_statuses") public static final int SUITABILITY_STATUS_NOT_SUITABLE_FOR_TRANSFER = 2; // 0x2 field @FlaggedApi("com.android.media.flags.enable_built_in_speaker_route_suitability_statuses") public static final int SUITABILITY_STATUS_SUITABLE_FOR_DEFAULT_TRANSFER = 0; // 0x0 field @FlaggedApi("com.android.media.flags.enable_built_in_speaker_route_suitability_statuses") public static final int SUITABILITY_STATUS_SUITABLE_FOR_MANUAL_TRANSFER = 1; // 0x1 + field @FlaggedApi("com.android.media.flags.enable_new_wired_media_route_2_info_types") public static final int TYPE_AUX_LINE = 19; // 0x13 field public static final int TYPE_BLE_HEADSET = 26; // 0x1a field public static final int TYPE_BLUETOOTH_A2DP = 8; // 0x8 field public static final int TYPE_BUILTIN_SPEAKER = 2; // 0x2 @@ -24669,6 +24701,8 @@ package android.media { field @FlaggedApi("com.android.media.flags.enable_audio_policies_device_and_bluetooth_controller") public static final int TYPE_HDMI_ARC = 10; // 0xa field @FlaggedApi("com.android.media.flags.enable_audio_policies_device_and_bluetooth_controller") public static final int TYPE_HDMI_EARC = 29; // 0x1d field public static final int TYPE_HEARING_AID = 23; // 0x17 + field @FlaggedApi("com.android.media.flags.enable_new_wired_media_route_2_info_types") public static final int TYPE_LINE_ANALOG = 5; // 0x5 + field @FlaggedApi("com.android.media.flags.enable_new_wired_media_route_2_info_types") public static final int TYPE_LINE_DIGITAL = 6; // 0x6 field @FlaggedApi("android.media.audio.enable_multichannel_group_device") public static final int TYPE_MULTICHANNEL_SPEAKER_GROUP = 32; // 0x20 field public static final int TYPE_REMOTE_AUDIO_VIDEO_RECEIVER = 1003; // 0x3eb field @FlaggedApi("com.android.media.flags.enable_new_media_route_2_info_types") public static final int TYPE_REMOTE_CAR = 1008; // 0x3f0 @@ -32944,11 +32978,16 @@ package android.os { public class Build { ctor public Build(); + method @FlaggedApi("android.os.api_for_backported_fixes") public static int getBackportedFixStatus(long); method @NonNull public static java.util.List getFingerprintedPartitions(); method @FlaggedApi("android.sdk.major_minor_versioning_scheme") public static int getMajorSdkVersion(int); method @FlaggedApi("android.sdk.major_minor_versioning_scheme") public static int getMinorSdkVersion(int); method public static String getRadioVersion(); method @RequiresPermission("android.permission.READ_PRIVILEGED_PHONE_STATE") public static String getSerial(); + field @FlaggedApi("android.os.api_for_backported_fixes") public static final int BACKPORTED_FIX_STATUS_FIXED = 1; // 0x1 + field @FlaggedApi("android.os.api_for_backported_fixes") public static final int BACKPORTED_FIX_STATUS_NOT_APPLICABLE = 2; // 0x2 + field @FlaggedApi("android.os.api_for_backported_fixes") public static final int BACKPORTED_FIX_STATUS_NOT_FIXED = 3; // 0x3 + field @FlaggedApi("android.os.api_for_backported_fixes") public static final int BACKPORTED_FIX_STATUS_UNKNOWN = 0; // 0x0 field public static final String BOARD; field public static final String BOOTLOADER; field public static final String BRAND; @@ -33965,12 +34004,14 @@ package android.os { } public final class PowerManager { + method @FlaggedApi("android.os.allow_thermal_thresholds_callback") public void addThermalHeadroomListener(@NonNull android.os.PowerManager.OnThermalHeadroomChangedListener); + method @FlaggedApi("android.os.allow_thermal_thresholds_callback") public void addThermalHeadroomListener(@NonNull java.util.concurrent.Executor, @NonNull android.os.PowerManager.OnThermalHeadroomChangedListener); method public void addThermalStatusListener(@NonNull android.os.PowerManager.OnThermalStatusChangedListener); method public void addThermalStatusListener(@NonNull java.util.concurrent.Executor, @NonNull android.os.PowerManager.OnThermalStatusChangedListener); method @Nullable public java.time.Duration getBatteryDischargePrediction(); method public int getCurrentThermalStatus(); method public int getLocationPowerSaveMode(); - method public float getThermalHeadroom(@IntRange(from=0, to=60) int); + method @FloatRange(from=0.0f) public float getThermalHeadroom(@IntRange(from=0, to=60) int); method @FlaggedApi("android.os.allow_thermal_headroom_thresholds") @NonNull public java.util.Map getThermalHeadroomThresholds(); method public boolean isAllowedInLowPowerStandby(int); method public boolean isAllowedInLowPowerStandby(@NonNull String); @@ -33988,6 +34029,7 @@ package android.os { method public boolean isWakeLockLevelSupported(int); method public android.os.PowerManager.WakeLock newWakeLock(int, String); method @RequiresPermission(android.Manifest.permission.REBOOT) public void reboot(@Nullable String); + method @FlaggedApi("android.os.allow_thermal_thresholds_callback") public void removeThermalHeadroomListener(@NonNull android.os.PowerManager.OnThermalHeadroomChangedListener); method public void removeThermalStatusListener(@NonNull android.os.PowerManager.OnThermalStatusChangedListener); field @Deprecated @RequiresPermission(value=android.Manifest.permission.TURN_SCREEN_ON, conditional=true) public static final int ACQUIRE_CAUSES_WAKEUP = 268435456; // 0x10000000 field public static final String ACTION_DEVICE_IDLE_MODE_CHANGED = "android.os.action.DEVICE_IDLE_MODE_CHANGED"; @@ -34020,6 +34062,10 @@ package android.os { field public static final int THERMAL_STATUS_SHUTDOWN = 6; // 0x6 } + @FlaggedApi("android.os.allow_thermal_thresholds_callback") public static interface PowerManager.OnThermalHeadroomChangedListener { + method public void onThermalHeadroomChanged(@FloatRange(from=0.0f) float, @FloatRange(from=0.0f) float, @IntRange(from=0) int, @NonNull java.util.Map); + } + public static interface PowerManager.OnThermalStatusChangedListener { method public void onThermalStatusChanged(int); } @@ -40347,7 +40393,7 @@ package android.security.keystore { method @NonNull public android.security.keystore.KeyProtection.Builder setUserPresenceRequired(boolean); } - @FlaggedApi("android.security.keystore_grant_api") public class KeyStoreManager { + @FlaggedApi("android.security.keystore_grant_api") public final class KeyStoreManager { method @NonNull public java.util.List getGrantedCertificateChainFromId(long) throws android.security.keystore.KeyPermanentlyInvalidatedException, java.security.UnrecoverableKeyException; method @NonNull public java.security.Key getGrantedKeyFromId(long) throws android.security.keystore.KeyPermanentlyInvalidatedException, java.security.UnrecoverableKeyException; method @NonNull public java.security.KeyPair getGrantedKeyPairFromId(long) throws android.security.keystore.KeyPermanentlyInvalidatedException, java.security.UnrecoverableKeyException; @@ -41975,6 +42021,193 @@ package android.service.restrictions { } +package android.service.settings.preferences { + + @FlaggedApi("com.android.settingslib.flags.settings_catalyst") public final class GetValueRequest implements android.os.Parcelable { + method public int describeContents(); + method @NonNull public String getPreferenceKey(); + method @NonNull public String getScreenKey(); + method public void writeToParcel(@NonNull android.os.Parcel, int); + field @NonNull public static final android.os.Parcelable.Creator CREATOR; + } + + public static final class GetValueRequest.Builder { + ctor public GetValueRequest.Builder(@NonNull String, @NonNull String); + method @NonNull public android.service.settings.preferences.GetValueRequest build(); + } + + @FlaggedApi("com.android.settingslib.flags.settings_catalyst") public final class GetValueResult implements android.os.Parcelable { + method public int describeContents(); + method @Nullable public android.service.settings.preferences.SettingsPreferenceMetadata getMetadata(); + method public int getResultCode(); + method @Nullable public android.service.settings.preferences.SettingsPreferenceValue getValue(); + method public void writeToParcel(@NonNull android.os.Parcel, int); + field @NonNull public static final android.os.Parcelable.Creator CREATOR; + field public static final int RESULT_DISALLOW = 4; // 0x4 + field public static final int RESULT_INTERNAL_ERROR = 6; // 0x6 + field public static final int RESULT_INVALID_REQUEST = 5; // 0x5 + field public static final int RESULT_OK = 0; // 0x0 + field public static final int RESULT_REQUIRE_APP_PERMISSION = 3; // 0x3 + field public static final int RESULT_UNAVAILABLE = 2; // 0x2 + field public static final int RESULT_UNSUPPORTED = 1; // 0x1 + } + + public static final class GetValueResult.Builder { + ctor public GetValueResult.Builder(int); + method @NonNull public android.service.settings.preferences.GetValueResult build(); + method @NonNull public android.service.settings.preferences.GetValueResult.Builder setMetadata(@Nullable android.service.settings.preferences.SettingsPreferenceMetadata); + method @NonNull public android.service.settings.preferences.GetValueResult.Builder setValue(@Nullable android.service.settings.preferences.SettingsPreferenceValue); + } + + @FlaggedApi("com.android.settingslib.flags.settings_catalyst") public final class MetadataRequest implements android.os.Parcelable { + method public int describeContents(); + method public void writeToParcel(@NonNull android.os.Parcel, int); + field @NonNull public static final android.os.Parcelable.Creator CREATOR; + } + + public static final class MetadataRequest.Builder { + ctor public MetadataRequest.Builder(); + method @NonNull public android.service.settings.preferences.MetadataRequest build(); + } + + @FlaggedApi("com.android.settingslib.flags.settings_catalyst") public final class MetadataResult implements android.os.Parcelable { + method public int describeContents(); + method @NonNull public java.util.List getMetadataList(); + method public int getResultCode(); + method public void writeToParcel(@NonNull android.os.Parcel, int); + field @NonNull public static final android.os.Parcelable.Creator CREATOR; + field public static final int RESULT_INTERNAL_ERROR = 2; // 0x2 + field public static final int RESULT_OK = 0; // 0x0 + field public static final int RESULT_UNSUPPORTED = 1; // 0x1 + } + + public static final class MetadataResult.Builder { + ctor public MetadataResult.Builder(int); + method @NonNull public android.service.settings.preferences.MetadataResult build(); + method @NonNull public android.service.settings.preferences.MetadataResult.Builder setMetadataList(@NonNull java.util.List); + } + + @FlaggedApi("com.android.settingslib.flags.settings_catalyst") public final class SetValueRequest implements android.os.Parcelable { + method public int describeContents(); + method @NonNull public String getPreferenceKey(); + method @NonNull public android.service.settings.preferences.SettingsPreferenceValue getPreferenceValue(); + method @NonNull public String getScreenKey(); + method public void writeToParcel(@NonNull android.os.Parcel, int); + field @NonNull public static final android.os.Parcelable.Creator CREATOR; + } + + public static final class SetValueRequest.Builder { + ctor public SetValueRequest.Builder(@NonNull String, @NonNull String, @NonNull android.service.settings.preferences.SettingsPreferenceValue); + method @NonNull public android.service.settings.preferences.SetValueRequest build(); + } + + @FlaggedApi("com.android.settingslib.flags.settings_catalyst") public final class SetValueResult implements android.os.Parcelable { + method public int describeContents(); + method public int getResultCode(); + method public void writeToParcel(@NonNull android.os.Parcel, int); + field @NonNull public static final android.os.Parcelable.Creator CREATOR; + field public static final int RESULT_DISABLED = 2; // 0x2 + field public static final int RESULT_DISALLOW = 7; // 0x7 + field public static final int RESULT_INTERNAL_ERROR = 9; // 0x9 + field public static final int RESULT_INVALID_REQUEST = 8; // 0x8 + field public static final int RESULT_OK = 0; // 0x0 + field public static final int RESULT_REQUIRE_APP_PERMISSION = 5; // 0x5 + field public static final int RESULT_REQUIRE_USER_CONSENT = 6; // 0x6 + field public static final int RESULT_RESTRICTED = 3; // 0x3 + field public static final int RESULT_UNAVAILABLE = 4; // 0x4 + field public static final int RESULT_UNSUPPORTED = 1; // 0x1 + } + + public static final class SetValueResult.Builder { + ctor public SetValueResult.Builder(int); + method @NonNull public android.service.settings.preferences.SetValueResult build(); + } + + @FlaggedApi("com.android.settingslib.flags.settings_catalyst") public final class SettingsPreferenceMetadata implements android.os.Parcelable { + method public int describeContents(); + 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 @NonNull public java.util.List getReadPermissions(); + method @NonNull public String getScreenKey(); + method @Nullable public String getSummary(); + method @Nullable public String getTitle(); + method @NonNull public java.util.List getWritePermissions(); + method public int getWriteSensitivity(); + method public boolean isAvailable(); + method public boolean isEnabled(); + method public boolean isRestricted(); + method public boolean isWritable(); + method public void writeToParcel(@NonNull android.os.Parcel, int); + field @NonNull public static final android.os.Parcelable.Creator CREATOR; + field public static final int INTENT_ONLY = 2; // 0x2 + field public static final int NOT_SENSITIVE = 0; // 0x0 + field public static final int SENSITIVE = 1; // 0x1 + } + + public static final class SettingsPreferenceMetadata.Builder { + ctor public SettingsPreferenceMetadata.Builder(@NonNull String, @NonNull String); + method @NonNull public android.service.settings.preferences.SettingsPreferenceMetadata build(); + method @NonNull public android.service.settings.preferences.SettingsPreferenceMetadata.Builder setAvailable(boolean); + 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 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); + method @NonNull public android.service.settings.preferences.SettingsPreferenceMetadata.Builder setTitle(@Nullable String); + method @NonNull public android.service.settings.preferences.SettingsPreferenceMetadata.Builder setWritable(boolean); + method @NonNull public android.service.settings.preferences.SettingsPreferenceMetadata.Builder setWritePermissions(@NonNull java.util.List); + method @NonNull public android.service.settings.preferences.SettingsPreferenceMetadata.Builder setWriteSensitivity(int); + } + + @FlaggedApi("com.android.settingslib.flags.settings_catalyst") public abstract class SettingsPreferenceService extends android.app.Service { + ctor public SettingsPreferenceService(); + method @NonNull public final android.os.IBinder onBind(@Nullable android.content.Intent); + method public abstract void onGetAllPreferenceMetadata(@NonNull android.service.settings.preferences.MetadataRequest, @NonNull android.os.OutcomeReceiver); + method public abstract void onGetPreferenceValue(@NonNull android.service.settings.preferences.GetValueRequest, @NonNull android.os.OutcomeReceiver); + method public abstract void onSetPreferenceValue(@NonNull android.service.settings.preferences.SetValueRequest, @NonNull android.os.OutcomeReceiver); + field public static final String ACTION_PREFERENCE_SERVICE = "android.service.settings.preferences.action.PREFERENCE_SERVICE"; + } + + @FlaggedApi("com.android.settingslib.flags.settings_catalyst") public class SettingsPreferenceServiceClient implements java.lang.AutoCloseable { + ctor public SettingsPreferenceServiceClient(@NonNull android.content.Context, @NonNull String); + 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 long getLongValue(); + method @Nullable public String getStringValue(); + method 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 TYPE_BOOLEAN = 0; // 0x0 + field public static final int TYPE_DOUBLE = 2; // 0x2 + field public static final int TYPE_LONG = 1; // 0x1 + field public static final int TYPE_STRING = 3; // 0x3 + } + + public static final class SettingsPreferenceValue.Builder { + ctor public SettingsPreferenceValue.Builder(int); + 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 setLongValue(long); + method @NonNull public android.service.settings.preferences.SettingsPreferenceValue.Builder setStringValue(@Nullable String); + } + +} + package android.service.textservice { public abstract class SpellCheckerService extends android.app.Service { @@ -44080,6 +44313,8 @@ package android.telephony { field public static final String ACTION_CARRIER_CONFIG_CHANGED = "android.telephony.action.CARRIER_CONFIG_CHANGED"; field public static final int CARRIER_NR_AVAILABILITY_NSA = 1; // 0x1 field public static final int CARRIER_NR_AVAILABILITY_SA = 2; // 0x2 + field @FlaggedApi("com.android.internal.telephony.flags.satellite_system_apis") public static final int CARRIER_ROAMING_NTN_CONNECT_AUTOMATIC = 0; // 0x0 + field @FlaggedApi("com.android.internal.telephony.flags.satellite_system_apis") public static final int CARRIER_ROAMING_NTN_CONNECT_MANUAL = 1; // 0x1 field public static final int CROSS_SIM_SPN_FORMAT_CARRIER_NAME_ONLY = 0; // 0x0 field public static final int CROSS_SIM_SPN_FORMAT_CARRIER_NAME_WITH_BRANDING = 1; // 0x1 field public static final int DATA_CYCLE_THRESHOLD_DISABLED = -2; // 0xfffffffe @@ -44150,11 +44385,14 @@ package android.telephony { field public static final String KEY_CARRIER_NR_AVAILABILITIES_INT_ARRAY = "carrier_nr_availabilities_int_array"; field public static final String KEY_CARRIER_PROVISIONS_WIFI_MERGED_NETWORKS_BOOL = "carrier_provisions_wifi_merged_networks_bool"; field public static final String KEY_CARRIER_RCS_PROVISIONING_REQUIRED_BOOL = "carrier_rcs_provisioning_required_bool"; + field @FlaggedApi("com.android.internal.telephony.flags.satellite_system_apis") public static final String KEY_CARRIER_ROAMING_NTN_CONNECT_TYPE_INT = "carrier_roaming_ntn_connect_type_int"; field @FlaggedApi("com.android.internal.telephony.flags.carrier_roaming_nb_iot_ntn") public static final String KEY_CARRIER_ROAMING_NTN_EMERGENCY_CALL_TO_SATELLITE_HANDOVER_TYPE_INT = "carrier_roaming_ntn_emergency_call_to_satellite_handover_type_int"; + field @FlaggedApi("com.android.internal.telephony.flags.satellite_system_apis") public static final String KEY_CARRIER_ROAMING_SATELLITE_DEFAULT_SERVICES_INT_ARRAY = "carrier_roaming_satellite_default_services_int_array"; field public static final String KEY_CARRIER_SERVICE_NAME_STRING_ARRAY = "carrier_service_name_array"; field public static final String KEY_CARRIER_SERVICE_NUMBER_STRING_ARRAY = "carrier_service_number_array"; field public static final String KEY_CARRIER_SETTINGS_ACTIVITY_COMPONENT_NAME_STRING = "carrier_settings_activity_component_name_string"; field public static final String KEY_CARRIER_SETTINGS_ENABLE_BOOL = "carrier_settings_enable_bool"; + field @FlaggedApi("com.android.internal.telephony.flags.satellite_system_apis") public static final String KEY_CARRIER_SUPPORTED_SATELLITE_NOTIFICATION_HYSTERESIS_SEC_INT = "carrier_supported_satellite_notification_hysteresis_sec_int"; field @FlaggedApi("com.android.internal.telephony.flags.carrier_enabled_satellite_flag") public static final String KEY_CARRIER_SUPPORTED_SATELLITE_SERVICES_PER_PROVIDER_BUNDLE = "carrier_supported_satellite_services_per_provider_bundle"; field public static final String KEY_CARRIER_SUPPORTS_OPP_DATA_AUTO_PROVISIONING_BOOL = "carrier_supports_opp_data_auto_provisioning_bool"; field public static final String KEY_CARRIER_SUPPORTS_SS_OVER_UT_BOOL = "carrier_supports_ss_over_ut_bool"; @@ -44205,6 +44443,7 @@ package android.telephony { field public static final String KEY_DIAL_STRING_REPLACE_STRING_ARRAY = "dial_string_replace_string_array"; field public static final String KEY_DISABLE_CDMA_ACTIVATION_CODE_BOOL = "disable_cdma_activation_code_bool"; field public static final String KEY_DISABLE_CHARGE_INDICATION_BOOL = "disable_charge_indication_bool"; + field @FlaggedApi("com.android.internal.telephony.flags.satellite_system_apis") public static final String KEY_DISABLE_DUN_APN_WHILE_ROAMING_WITH_PRESET_APN_BOOL = "disable_dun_apn_while_roaming_with_preset_apn_bool"; field public static final String KEY_DISABLE_SUPPLEMENTARY_SERVICES_IN_AIRPLANE_MODE_BOOL = "disable_supplementary_services_in_airplane_mode_bool"; field public static final String KEY_DISCONNECT_CAUSE_PLAY_BUSYTONE_INT_ARRAY = "disconnect_cause_play_busytone_int_array"; field public static final String KEY_DISPLAY_CALL_STRENGTH_INDICATOR_BOOL = "display_call_strength_indicator_bool"; @@ -44217,6 +44456,8 @@ package android.telephony { field public static final String KEY_EDITABLE_VOICEMAIL_NUMBER_SETTING_BOOL = "editable_voicemail_number_setting_bool"; field public static final String KEY_EDITABLE_WFC_MODE_BOOL = "editable_wfc_mode_bool"; field public static final String KEY_EDITABLE_WFC_ROAMING_MODE_BOOL = "editable_wfc_roaming_mode_bool"; + field @FlaggedApi("com.android.internal.telephony.flags.satellite_system_apis") public static final String KEY_EMERGENCY_CALL_TO_SATELLITE_T911_HANDOVER_TIMEOUT_MILLIS_INT = "emergency_call_to_satellite_t911_handover_timeout_millis_int"; + field @FlaggedApi("com.android.internal.telephony.flags.satellite_system_apis") public static final String KEY_EMERGENCY_MESSAGING_SUPPORTED_BOOL = "emergency_messaging_supported_bool"; field public static final String KEY_EMERGENCY_NOTIFICATION_DELAY_INT = "emergency_notification_delay_int"; field public static final String KEY_EMERGENCY_NUMBER_PREFIX_STRING_ARRAY = "emergency_number_prefix_string_array"; field public static final String KEY_ENABLE_CROSS_SIM_CALLING_ON_OPPORTUNISTIC_DATA_BOOL = "enable_cross_sim_calling_on_opportunistic_data_bool"; @@ -44263,6 +44504,7 @@ package android.telephony { field public static final String KEY_MMS_MAX_IMAGE_HEIGHT_INT = "maxImageHeight"; field public static final String KEY_MMS_MAX_IMAGE_WIDTH_INT = "maxImageWidth"; field public static final String KEY_MMS_MAX_MESSAGE_SIZE_INT = "maxMessageSize"; + field @FlaggedApi("com.android.internal.telephony.flags.satellite_system_apis") public static final String KEY_MMS_MAX_NTN_PAYLOAD_SIZE_BYTES_INT = "mms_max_ntn_payload_size_bytes_int"; field public static final String KEY_MMS_MESSAGE_TEXT_MAX_SIZE_INT = "maxMessageTextSize"; field public static final String KEY_MMS_MMS_DELIVERY_REPORT_ENABLED_BOOL = "enableMMSDeliveryReports"; field public static final String KEY_MMS_MMS_ENABLED_BOOL = "enabledMMS"; @@ -44301,6 +44543,7 @@ package android.telephony { field public static final String KEY_OPPORTUNISTIC_NETWORK_EXIT_THRESHOLD_RSSNR_INT = "opportunistic_network_exit_threshold_rssnr_int"; field public static final String KEY_OPPORTUNISTIC_NETWORK_MAX_BACKOFF_TIME_LONG = "opportunistic_network_max_backoff_time_long"; field public static final String KEY_OPPORTUNISTIC_NETWORK_PING_PONG_TIME_LONG = "opportunistic_network_ping_pong_time_long"; + field @FlaggedApi("com.android.internal.telephony.flags.satellite_system_apis") public static final String KEY_OVERRIDE_WFC_ROAMING_MODE_WHILE_USING_NTN_BOOL = "override_wfc_roaming_mode_while_using_ntn_bool"; field @FlaggedApi("com.android.internal.telephony.flags.carrier_enabled_satellite_flag") public static final String KEY_PARAMETERS_USED_FOR_NTN_LTE_SIGNAL_BAR_INT = "parameters_used_for_ntn_lte_signal_bar_int"; field public static final String KEY_PING_TEST_BEFORE_DATA_SWITCH_BOOL = "ping_test_before_data_switch_bool"; field public static final String KEY_PREFER_2G_BOOL = "prefer_2g_bool"; @@ -44319,6 +44562,7 @@ package android.telephony { field public static final String KEY_RCS_CONFIG_SERVER_URL_STRING = "rcs_config_server_url_string"; field public static final String KEY_READ_ONLY_APN_FIELDS_STRING_ARRAY = "read_only_apn_fields_string_array"; field public static final String KEY_READ_ONLY_APN_TYPES_STRING_ARRAY = "read_only_apn_types_string_array"; + field @FlaggedApi("com.android.internal.telephony.flags.satellite_system_apis") public static final String KEY_REMOVE_SATELLITE_PLMN_IN_MANUAL_NETWORK_SCAN_BOOL = "remove_satellite_plmn_in_manual_network_scan_bool"; field public static final String KEY_REQUIRE_ENTITLEMENT_CHECKS_BOOL = "require_entitlement_checks_bool"; field @Deprecated public static final String KEY_RESTART_RADIO_ON_PDP_FAIL_REGULAR_DEACTIVATION_BOOL = "restart_radio_on_pdp_fail_regular_deactivation_bool"; field public static final String KEY_RTT_AUTO_UPGRADE_BOOL = "rtt_auto_upgrade_bool"; @@ -44330,13 +44574,18 @@ package android.telephony { field public static final String KEY_RTT_UPGRADE_SUPPORTED_FOR_DOWNGRADED_VT_CALL_BOOL = "rtt_upgrade_supported_for_downgraded_vt_call"; field @FlaggedApi("com.android.internal.telephony.flags.carrier_enabled_satellite_flag") public static final String KEY_SATELLITE_ATTACH_SUPPORTED_BOOL = "satellite_attach_supported_bool"; field @FlaggedApi("com.android.internal.telephony.flags.carrier_enabled_satellite_flag") public static final String KEY_SATELLITE_CONNECTION_HYSTERESIS_SEC_INT = "satellite_connection_hysteresis_sec_int"; + field @FlaggedApi("com.android.internal.telephony.flags.satellite_system_apis") public static final String KEY_SATELLITE_DATA_SUPPORT_MODE_INT = "satellite_data_support_mode_int"; + field @FlaggedApi("com.android.internal.telephony.flags.satellite_system_apis") public static final String KEY_SATELLITE_ENTITLEMENT_APP_NAME_STRING = "satellite_entitlement_app_name_string"; field @FlaggedApi("com.android.internal.telephony.flags.carrier_enabled_satellite_flag") public static final String KEY_SATELLITE_ENTITLEMENT_STATUS_REFRESH_DAYS_INT = "satellite_entitlement_status_refresh_days_int"; field @FlaggedApi("com.android.internal.telephony.flags.carrier_enabled_satellite_flag") public static final String KEY_SATELLITE_ENTITLEMENT_SUPPORTED_BOOL = "satellite_entitlement_supported_bool"; field @FlaggedApi("com.android.internal.telephony.flags.carrier_roaming_nb_iot_ntn") public static final String KEY_SATELLITE_ESOS_SUPPORTED_BOOL = "satellite_esos_supported_bool"; + field @FlaggedApi("com.android.internal.telephony.flags.satellite_system_apis") public static final String KEY_SATELLITE_INFORMATION_REDIRECT_URL_STRING = "satellite_information_redirect_url_string"; + field @FlaggedApi("com.android.internal.telephony.flags.satellite_system_apis") public static final String KEY_SATELLITE_NIDD_APN_NAME_STRING = "satellite_nidd_apn_name_string"; field @FlaggedApi("com.android.internal.telephony.flags.carrier_roaming_nb_iot_ntn") public static final String KEY_SATELLITE_ROAMING_ESOS_INACTIVITY_TIMEOUT_SEC_INT = "satellite_roaming_esos_inactivity_timeout_sec_int"; field @FlaggedApi("com.android.internal.telephony.flags.carrier_roaming_nb_iot_ntn") public static final String KEY_SATELLITE_ROAMING_P2P_SMS_INACTIVITY_TIMEOUT_SEC_INT = "satellite_roaming_p2p_sms_inactivity_timeout_sec_int"; field @FlaggedApi("com.android.internal.telephony.flags.carrier_roaming_nb_iot_ntn") public static final String KEY_SATELLITE_ROAMING_P2P_SMS_SUPPORTED_BOOL = "satellite_roaming_p2p_sms_supported_bool"; field @FlaggedApi("com.android.internal.telephony.flags.carrier_roaming_nb_iot_ntn") public static final String KEY_SATELLITE_ROAMING_SCREEN_OFF_INACTIVITY_TIMEOUT_SEC_INT = "satellite_roaming_screen_off_inactivity_timeout_sec_int"; + field @FlaggedApi("com.android.internal.telephony.flags.satellite_system_apis") public static final String KEY_SATELLITE_ROAMING_TURN_OFF_SESSION_FOR_EMERGENCY_CALL_BOOL = "satellite_roaming_turn_off_session_for_emergency_call_bool"; field public static final String KEY_SHOW_4G_FOR_3G_DATA_ICON_BOOL = "show_4g_for_3g_data_icon_bool"; field public static final String KEY_SHOW_4G_FOR_LTE_DATA_ICON_BOOL = "show_4g_for_lte_data_icon_bool"; field public static final String KEY_SHOW_APN_SETTING_CDMA_BOOL = "show_apn_setting_cdma_bool"; @@ -44406,6 +44655,9 @@ package android.telephony { field public static final String KEY_WORLD_MODE_ENABLED_BOOL = "world_mode_enabled_bool"; field public static final String KEY_WORLD_PHONE_BOOL = "world_phone_bool"; field public static final String REMOVE_GROUP_UUID_STRING = "00000000-0000-0000-0000-000000000000"; + field @FlaggedApi("com.android.internal.telephony.flags.satellite_system_apis") public static final int SATELLITE_DATA_SUPPORT_ALL = 2; // 0x2 + field @FlaggedApi("com.android.internal.telephony.flags.satellite_system_apis") public static final int SATELLITE_DATA_SUPPORT_BANDWIDTH_CONSTRAINED = 1; // 0x1 + field @FlaggedApi("com.android.internal.telephony.flags.satellite_system_apis") public static final int SATELLITE_DATA_SUPPORT_ONLY_RESTRICTED = 0; // 0x0 field public static final int SERVICE_CLASS_NONE = 0; // 0x0 field public static final int SERVICE_CLASS_VOICE = 1; // 0x1 field public static final int USSD_OVER_CS_ONLY = 2; // 0x2 @@ -51775,6 +52027,7 @@ package android.view { field public static final int KEYCODE_CHANNEL_DOWN = 167; // 0xa7 field public static final int KEYCODE_CHANNEL_UP = 166; // 0xa6 field public static final int KEYCODE_CLEAR = 28; // 0x1c + field @FlaggedApi("com.android.hardware.input.enable_new_25q2_keycodes") public static final int KEYCODE_CLOSE = 321; // 0x141 field public static final int KEYCODE_COMMA = 55; // 0x37 field public static final int KEYCODE_CONTACTS = 207; // 0xcf field public static final int KEYCODE_COPY = 278; // 0x116 @@ -51787,6 +52040,8 @@ package android.view { field public static final int KEYCODE_DEMO_APP_2 = 302; // 0x12e field public static final int KEYCODE_DEMO_APP_3 = 303; // 0x12f field public static final int KEYCODE_DEMO_APP_4 = 304; // 0x130 + field @FlaggedApi("com.android.hardware.input.enable_new_25q2_keycodes") public static final int KEYCODE_DICTATE = 319; // 0x13f + field @FlaggedApi("com.android.hardware.input.enable_new_25q2_keycodes") public static final int KEYCODE_DO_NOT_DISTURB = 322; // 0x142 field public static final int KEYCODE_DPAD_CENTER = 23; // 0x17 field public static final int KEYCODE_DPAD_DOWN = 20; // 0x14 field public static final int KEYCODE_DPAD_DOWN_LEFT = 269; // 0x10d @@ -51799,7 +52054,7 @@ package android.view { field public static final int KEYCODE_DVR = 173; // 0xad field public static final int KEYCODE_E = 33; // 0x21 field public static final int KEYCODE_EISU = 212; // 0xd4 - field @FlaggedApi("com.android.hardware.input.emoji_and_screenshot_keycodes_available") public static final int KEYCODE_EMOJI_PICKER = 317; // 0x13d + field public static final int KEYCODE_EMOJI_PICKER = 317; // 0x13d field public static final int KEYCODE_ENDCALL = 6; // 0x6 field public static final int KEYCODE_ENTER = 66; // 0x42 field public static final int KEYCODE_ENVELOPE = 65; // 0x41 @@ -51811,7 +52066,19 @@ package android.view { field public static final int KEYCODE_F10 = 140; // 0x8c field public static final int KEYCODE_F11 = 141; // 0x8d field public static final int KEYCODE_F12 = 142; // 0x8e + field @FlaggedApi("com.android.hardware.input.enable_new_25q2_keycodes") public static final int KEYCODE_F13 = 326; // 0x146 + field @FlaggedApi("com.android.hardware.input.enable_new_25q2_keycodes") public static final int KEYCODE_F14 = 327; // 0x147 + field @FlaggedApi("com.android.hardware.input.enable_new_25q2_keycodes") public static final int KEYCODE_F15 = 328; // 0x148 + field @FlaggedApi("com.android.hardware.input.enable_new_25q2_keycodes") public static final int KEYCODE_F16 = 329; // 0x149 + field @FlaggedApi("com.android.hardware.input.enable_new_25q2_keycodes") public static final int KEYCODE_F17 = 330; // 0x14a + field @FlaggedApi("com.android.hardware.input.enable_new_25q2_keycodes") public static final int KEYCODE_F18 = 331; // 0x14b + field @FlaggedApi("com.android.hardware.input.enable_new_25q2_keycodes") public static final int KEYCODE_F19 = 332; // 0x14c field public static final int KEYCODE_F2 = 132; // 0x84 + field @FlaggedApi("com.android.hardware.input.enable_new_25q2_keycodes") public static final int KEYCODE_F20 = 333; // 0x14d + field @FlaggedApi("com.android.hardware.input.enable_new_25q2_keycodes") public static final int KEYCODE_F21 = 334; // 0x14e + field @FlaggedApi("com.android.hardware.input.enable_new_25q2_keycodes") public static final int KEYCODE_F22 = 335; // 0x14f + field @FlaggedApi("com.android.hardware.input.enable_new_25q2_keycodes") public static final int KEYCODE_F23 = 336; // 0x150 + field @FlaggedApi("com.android.hardware.input.enable_new_25q2_keycodes") public static final int KEYCODE_F24 = 337; // 0x151 field public static final int KEYCODE_F3 = 133; // 0x85 field public static final int KEYCODE_F4 = 134; // 0x86 field public static final int KEYCODE_F5 = 135; // 0x87 @@ -51826,6 +52093,7 @@ package android.view { field public static final int KEYCODE_FOCUS = 80; // 0x50 field public static final int KEYCODE_FORWARD = 125; // 0x7d field public static final int KEYCODE_FORWARD_DEL = 112; // 0x70 + field @FlaggedApi("com.android.hardware.input.enable_new_25q2_keycodes") public static final int KEYCODE_FULLSCREEN = 325; // 0x145 field public static final int KEYCODE_FUNCTION = 119; // 0x77 field public static final int KEYCODE_G = 35; // 0x23 field public static final int KEYCODE_GRAVE = 68; // 0x44 @@ -51849,6 +52117,7 @@ package android.view { field public static final int KEYCODE_LANGUAGE_SWITCH = 204; // 0xcc field public static final int KEYCODE_LAST_CHANNEL = 229; // 0xe5 field public static final int KEYCODE_LEFT_BRACKET = 71; // 0x47 + field @FlaggedApi("com.android.hardware.input.enable_new_25q2_keycodes") public static final int KEYCODE_LOCK = 324; // 0x144 field public static final int KEYCODE_M = 41; // 0x29 field public static final int KEYCODE_MACRO_1 = 313; // 0x139 field public static final int KEYCODE_MACRO_2 = 314; // 0x13a @@ -51886,6 +52155,7 @@ package android.view { field public static final int KEYCODE_NAVIGATE_NEXT = 261; // 0x105 field public static final int KEYCODE_NAVIGATE_OUT = 263; // 0x107 field public static final int KEYCODE_NAVIGATE_PREVIOUS = 260; // 0x104 + field @FlaggedApi("com.android.hardware.input.enable_new_25q2_keycodes") public static final int KEYCODE_NEW = 320; // 0x140 field public static final int KEYCODE_NOTIFICATION = 83; // 0x53 field public static final int KEYCODE_NUM = 78; // 0x4e field public static final int KEYCODE_NUMPAD_0 = 144; // 0x90 @@ -51920,6 +52190,7 @@ package android.view { field public static final int KEYCODE_PLUS = 81; // 0x51 field public static final int KEYCODE_POUND = 18; // 0x12 field public static final int KEYCODE_POWER = 26; // 0x1a + field @FlaggedApi("com.android.hardware.input.enable_new_25q2_keycodes") public static final int KEYCODE_PRINT = 323; // 0x143 field public static final int KEYCODE_PROFILE_SWITCH = 288; // 0x120 field public static final int KEYCODE_PROG_BLUE = 186; // 0xba field public static final int KEYCODE_PROG_GREEN = 184; // 0xb8 @@ -51932,7 +52203,7 @@ package android.view { field public static final int KEYCODE_RIGHT_BRACKET = 72; // 0x48 field public static final int KEYCODE_RO = 217; // 0xd9 field public static final int KEYCODE_S = 47; // 0x2f - field @FlaggedApi("com.android.hardware.input.emoji_and_screenshot_keycodes_available") public static final int KEYCODE_SCREENSHOT = 318; // 0x13e + field public static final int KEYCODE_SCREENSHOT = 318; // 0x13e field public static final int KEYCODE_SCROLL_LOCK = 116; // 0x74 field public static final int KEYCODE_SEARCH = 84; // 0x54 field public static final int KEYCODE_SEMICOLON = 74; // 0x4a @@ -52997,7 +53268,7 @@ package android.view { method public void addOnUnhandledKeyEventListener(android.view.View.OnUnhandledKeyEventListener); method public void addTouchables(java.util.ArrayList); method public android.view.ViewPropertyAnimator animate(); - method public void announceForAccessibility(CharSequence); + method @Deprecated @FlaggedApi("android.view.accessibility.deprecate_accessibility_announcement_apis") public void announceForAccessibility(CharSequence); method public void autofill(android.view.autofill.AutofillValue); method public void autofill(@NonNull android.util.SparseArray); method protected boolean awakenScrollBars(); @@ -55247,7 +55518,7 @@ package android.view.accessibility { field public static final int SPEECH_STATE_SPEAKING_END = 2; // 0x2 field public static final int SPEECH_STATE_SPEAKING_START = 1; // 0x1 field public static final int TYPES_ALL_MASK = -1; // 0xffffffff - field public static final int TYPE_ANNOUNCEMENT = 16384; // 0x4000 + field @Deprecated @FlaggedApi("android.view.accessibility.deprecate_accessibility_announcement_apis") public static final int TYPE_ANNOUNCEMENT = 16384; // 0x4000 field public static final int TYPE_ASSIST_READING_CONTEXT = 16777216; // 0x1000000 field public static final int TYPE_GESTURE_DETECTION_END = 524288; // 0x80000 field public static final int TYPE_GESTURE_DETECTION_START = 262144; // 0x40000 @@ -55386,8 +55657,8 @@ package android.view.accessibility { method public android.os.Bundle getExtras(); method public CharSequence getHintText(); method public int getInputType(); - method public android.view.accessibility.AccessibilityNodeInfo getLabelFor(); - method public android.view.accessibility.AccessibilityNodeInfo getLabeledBy(); + method @Deprecated @FlaggedApi("android.view.accessibility.deprecate_ani_label_for_apis") public android.view.accessibility.AccessibilityNodeInfo getLabelFor(); + method @Deprecated @FlaggedApi("android.view.accessibility.support_multiple_labeledby") public android.view.accessibility.AccessibilityNodeInfo getLabeledBy(); method @FlaggedApi("android.view.accessibility.support_multiple_labeledby") @NonNull public java.util.List getLabeledByList(); method public int getLiveRegion(); method public int getMaxTextLength(); @@ -55485,10 +55756,10 @@ package android.view.accessibility { method public void setHintText(CharSequence); method public void setImportantForAccessibility(boolean); method public void setInputType(int); - method public void setLabelFor(android.view.View); - method public void setLabelFor(android.view.View, int); - method public void setLabeledBy(android.view.View); - method public void setLabeledBy(android.view.View, int); + method @Deprecated @FlaggedApi("android.view.accessibility.deprecate_ani_label_for_apis") public void setLabelFor(android.view.View); + method @Deprecated @FlaggedApi("android.view.accessibility.deprecate_ani_label_for_apis") public void setLabelFor(android.view.View, int); + method @Deprecated @FlaggedApi("android.view.accessibility.support_multiple_labeledby") public void setLabeledBy(android.view.View); + method @Deprecated @FlaggedApi("android.view.accessibility.support_multiple_labeledby") public void setLabeledBy(android.view.View, int); method public void setLiveRegion(int); method public void setLongClickable(boolean); method public void setMaxTextLength(int); @@ -55573,6 +55844,7 @@ package android.view.accessibility { field public static final String EXTRA_DATA_TEXT_CHARACTER_LOCATION_ARG_LENGTH = "android.view.accessibility.extra.DATA_TEXT_CHARACTER_LOCATION_ARG_LENGTH"; field public static final int EXTRA_DATA_TEXT_CHARACTER_LOCATION_ARG_MAX_LENGTH = 20000; // 0x4e20 field public static final String EXTRA_DATA_TEXT_CHARACTER_LOCATION_ARG_START_INDEX = "android.view.accessibility.extra.DATA_TEXT_CHARACTER_LOCATION_ARG_START_INDEX"; + field @FlaggedApi("android.view.accessibility.a11y_character_in_window_api") public static final String EXTRA_DATA_TEXT_CHARACTER_LOCATION_IN_WINDOW_KEY = "android.view.accessibility.extra.DATA_TEXT_CHARACTER_LOCATION_IN_WINDOW_KEY"; field public static final String EXTRA_DATA_TEXT_CHARACTER_LOCATION_KEY = "android.view.accessibility.extra.DATA_TEXT_CHARACTER_LOCATION_KEY"; field public static final int FLAG_PREFETCH_ANCESTORS = 1; // 0x1 field public static final int FLAG_PREFETCH_DESCENDANTS_BREADTH_FIRST = 16; // 0x10 @@ -56975,6 +57247,9 @@ package android.view.inputmethod { method public String getExtraValueOf(String); method public int getIconResId(); method @NonNull public String getLanguageTag(); + method @FlaggedApi("android.view.inputmethod.ime_switcher_revamp_api") @NonNull public CharSequence getLayoutDisplayName(@NonNull android.content.Context, @NonNull android.content.pm.ApplicationInfo); + method @FlaggedApi("android.view.inputmethod.ime_switcher_revamp_api") @NonNull public CharSequence getLayoutLabelNonLocalized(); + method @FlaggedApi("android.view.inputmethod.ime_switcher_revamp_api") @StringRes public int getLayoutLabelResource(); method @Deprecated @NonNull public String getLocale(); method public String getMode(); method @NonNull public CharSequence getNameOverride(); @@ -56994,6 +57269,8 @@ package android.view.inputmethod { method public android.view.inputmethod.InputMethodSubtype.InputMethodSubtypeBuilder setIsAsciiCapable(boolean); method public android.view.inputmethod.InputMethodSubtype.InputMethodSubtypeBuilder setIsAuxiliary(boolean); method public android.view.inputmethod.InputMethodSubtype.InputMethodSubtypeBuilder setLanguageTag(String); + method @FlaggedApi("android.view.inputmethod.ime_switcher_revamp_api") @NonNull public android.view.inputmethod.InputMethodSubtype.InputMethodSubtypeBuilder setLayoutLabelNonLocalized(@NonNull CharSequence); + method @FlaggedApi("android.view.inputmethod.ime_switcher_revamp_api") @NonNull public android.view.inputmethod.InputMethodSubtype.InputMethodSubtypeBuilder setLayoutLabelResource(@StringRes int); method public android.view.inputmethod.InputMethodSubtype.InputMethodSubtypeBuilder setOverridesImplicitlyEnabledSubtype(boolean); method @NonNull public android.view.inputmethod.InputMethodSubtype.InputMethodSubtypeBuilder setPhysicalKeyboardHint(@Nullable android.icu.util.ULocale, @NonNull String); method public android.view.inputmethod.InputMethodSubtype.InputMethodSubtypeBuilder setSubtypeExtraValue(String); @@ -62048,6 +62325,11 @@ package android.window { method public void markSyncReady(); } + @FlaggedApi("com.android.window.flags.predictive_back_system_override_callback") public final class SystemOnBackInvokedCallbacks { + method @FlaggedApi("com.android.window.flags.predictive_back_system_override_callback") @NonNull public static android.window.OnBackInvokedCallback finishAndRemoveTaskCallback(@NonNull android.app.Activity); + method @FlaggedApi("com.android.window.flags.predictive_back_system_override_callback") @NonNull public static android.window.OnBackInvokedCallback moveTaskToBackCallback(@NonNull android.app.Activity); + } + @FlaggedApi("com.android.window.flags.trusted_presentation_listener_for_window") public final class TrustedPresentationThresholds implements android.os.Parcelable { ctor @FlaggedApi("com.android.window.flags.trusted_presentation_listener_for_window") public TrustedPresentationThresholds(@FloatRange(from=0.0f, fromInclusive=false, to=1.0f) float, @FloatRange(from=0.0f, fromInclusive=false, to=1.0f) float, @IntRange(from=1) int); method @FlaggedApi("com.android.window.flags.trusted_presentation_listener_for_window") public int describeContents(); diff --git a/core/api/system-current.txt b/core/api/system-current.txt index 047a0df164b14a73884b5f0c7046ef2d3128d433..8954f8e70157af48efb492e9de0e57553ad819bc 100644 --- a/core/api/system-current.txt +++ b/core/api/system-current.txt @@ -138,6 +138,7 @@ package android { field public static final String DISABLE_SYSTEM_SOUND_EFFECTS = "android.permission.DISABLE_SYSTEM_SOUND_EFFECTS"; field public static final String DISPATCH_PROVISIONING_MESSAGE = "android.permission.DISPATCH_PROVISIONING_MESSAGE"; field public static final String DOMAIN_VERIFICATION_AGENT = "android.permission.DOMAIN_VERIFICATION_AGENT"; + field @FlaggedApi("com.android.art.flags.executable_method_file_offsets") public static final String DYNAMIC_INSTRUMENTATION = "android.permission.DYNAMIC_INSTRUMENTATION"; field @FlaggedApi("com.android.window.flags.untrusted_embedding_any_app_permission") public static final String EMBED_ANY_APP_IN_UNTRUSTED_MODE = "android.permission.EMBED_ANY_APP_IN_UNTRUSTED_MODE"; field @FlaggedApi("android.content.pm.emergency_install_permission") public static final String EMERGENCY_INSTALL_PACKAGES = "android.permission.EMERGENCY_INSTALL_PACKAGES"; field public static final String ENTER_CAR_MODE_PRIORITIZED = "android.permission.ENTER_CAR_MODE_PRIORITIZED"; @@ -389,6 +390,7 @@ package android { field public static final String START_CROSS_PROFILE_ACTIVITIES = "android.permission.START_CROSS_PROFILE_ACTIVITIES"; field public static final String START_REVIEW_PERMISSION_DECISIONS = "android.permission.START_REVIEW_PERMISSION_DECISIONS"; field public static final String START_TASKS_FROM_RECENTS = "android.permission.START_TASKS_FROM_RECENTS"; + field @FlaggedApi("android.os.vibrator.vendor_vibration_effects") public static final String START_VIBRATION_SESSIONS = "android.permission.START_VIBRATION_SESSIONS"; field public static final String STATUS_BAR_SERVICE = "android.permission.STATUS_BAR_SERVICE"; field public static final String STOP_APP_SWITCHES = "android.permission.STOP_APP_SWITCHES"; field public static final String SUBSTITUTE_NOTIFICATION_APP_NAME = "android.permission.SUBSTITUTE_NOTIFICATION_APP_NAME"; @@ -696,6 +698,7 @@ package android.app { field public static final String OPSTR_PLAY_AUDIO = "android:play_audio"; field public static final String OPSTR_POST_NOTIFICATION = "android:post_notification"; field public static final String OPSTR_PROJECT_MEDIA = "android:project_media"; + field @FlaggedApi("android.permission.flags.ranging_permission_enabled") public static final String OPSTR_RANGING = "android:ranging"; field @FlaggedApi("android.view.contentprotection.flags.rapid_clear_notifications_by_listener_app_op_enabled") public static final String OPSTR_RAPID_CLEAR_NOTIFICATIONS_BY_LISTENER = "android:rapid_clear_notifications_by_listener"; field public static final String OPSTR_READ_CLIPBOARD = "android:read_clipboard"; field @FlaggedApi("android.permission.flags.replace_body_sensor_permission_enabled") public static final String OPSTR_READ_HEART_RATE = "android:read_heart_rate"; @@ -704,6 +707,7 @@ package android.app { field public static final String OPSTR_READ_MEDIA_IMAGES = "android:read_media_images"; field public static final String OPSTR_READ_MEDIA_VIDEO = "android:read_media_video"; field public static final String OPSTR_READ_MEDIA_VISUAL_USER_SELECTED = "android:read_media_visual_user_selected"; + field @FlaggedApi("android.permission.flags.platform_oxygen_saturation_enabled") public static final String OPSTR_READ_OXYGEN_SATURATION = "android:read_oxygen_saturation"; field @FlaggedApi("android.permission.flags.platform_skin_temperature_enabled") public static final String OPSTR_READ_SKIN_TEMPERATURE = "android:read_skin_temperature"; field public static final String OPSTR_READ_WRITE_HEALTH_DATA = "android:read_write_health_data"; field public static final String OPSTR_RECEIVE_AMBIENT_TRIGGER_AUDIO = "android:receive_ambient_trigger_audio"; @@ -3558,10 +3562,12 @@ package android.companion.virtual { method @Deprecated public int getDefaultActivityPolicy(); method @Deprecated public int getDefaultNavigationPolicy(); method public int getDevicePolicy(int); + method @FlaggedApi("android.companion.virtualdevice.flags.device_aware_display_power") @NonNull public java.time.Duration getDimDuration(); method @FlaggedApi("android.companion.virtual.flags.vdm_custom_home") @Nullable public android.content.ComponentName getHomeComponent(); method @FlaggedApi("android.companion.virtual.flags.vdm_custom_ime") @Nullable public android.content.ComponentName getInputMethodComponent(); method public int getLockState(); method @Nullable public String getName(); + method @FlaggedApi("android.companion.virtualdevice.flags.device_aware_display_power") @NonNull public java.time.Duration getScreenOffTimeout(); method @NonNull public java.util.Set getUsersWithMatchingAccounts(); method @NonNull public java.util.List getVirtualSensorConfigs(); method public void writeToParcel(@NonNull android.os.Parcel, int); @@ -3579,6 +3585,7 @@ package android.companion.virtual { field @FlaggedApi("android.companion.virtualdevice.flags.activity_control_api") public static final int POLICY_TYPE_BLOCKED_ACTIVITY = 6; // 0x6 field @FlaggedApi("android.companion.virtual.flags.virtual_camera") public static final int POLICY_TYPE_CAMERA = 5; // 0x5 field @FlaggedApi("android.companion.virtual.flags.cross_device_clipboard") public static final int POLICY_TYPE_CLIPBOARD = 4; // 0x4 + field @FlaggedApi("android.companion.virtualdevice.flags.default_device_camera_access_policy") public static final int POLICY_TYPE_DEFAULT_DEVICE_CAMERA_ACCESS = 7; // 0x7 field public static final int POLICY_TYPE_RECENTS = 2; // 0x2 field public static final int POLICY_TYPE_SENSORS = 0; // 0x0 } @@ -3594,10 +3601,12 @@ package android.companion.virtual { method @Deprecated @NonNull public android.companion.virtual.VirtualDeviceParams.Builder setBlockedActivities(@NonNull java.util.Set); method @Deprecated @NonNull public android.companion.virtual.VirtualDeviceParams.Builder setBlockedCrossTaskNavigations(@NonNull java.util.Set); method @NonNull public android.companion.virtual.VirtualDeviceParams.Builder setDevicePolicy(int, int); + method @FlaggedApi("android.companion.virtualdevice.flags.device_aware_display_power") @NonNull public android.companion.virtual.VirtualDeviceParams.Builder setDimDuration(@NonNull java.time.Duration); method @FlaggedApi("android.companion.virtual.flags.vdm_custom_home") @NonNull public android.companion.virtual.VirtualDeviceParams.Builder setHomeComponent(@Nullable android.content.ComponentName); method @FlaggedApi("android.companion.virtual.flags.vdm_custom_ime") @NonNull public android.companion.virtual.VirtualDeviceParams.Builder setInputMethodComponent(@Nullable android.content.ComponentName); method @NonNull @RequiresPermission(value=android.Manifest.permission.ADD_ALWAYS_UNLOCKED_DISPLAY, conditional=true) public android.companion.virtual.VirtualDeviceParams.Builder setLockState(int); method @NonNull public android.companion.virtual.VirtualDeviceParams.Builder setName(@NonNull String); + method @FlaggedApi("android.companion.virtualdevice.flags.device_aware_display_power") @NonNull public android.companion.virtual.VirtualDeviceParams.Builder setScreenOffTimeout(@NonNull java.time.Duration); method @NonNull public android.companion.virtual.VirtualDeviceParams.Builder setUsersWithMatchingAccounts(@NonNull java.util.Set); method @NonNull public android.companion.virtual.VirtualDeviceParams.Builder setVirtualSensorCallback(@NonNull java.util.concurrent.Executor, @NonNull android.companion.virtual.sensor.VirtualSensorCallback); method @NonNull public android.companion.virtual.VirtualDeviceParams.Builder setVirtualSensorDirectChannelCallback(@NonNull java.util.concurrent.Executor, @NonNull android.companion.virtual.sensor.VirtualSensorDirectChannelCallback); @@ -5288,13 +5297,19 @@ package android.hardware.display { field public static final int VIRTUAL_DISPLAY_FLAG_TRUSTED = 1024; // 0x400 } + public abstract static class VirtualDisplay.Callback { + method @FlaggedApi("android.companion.virtualdevice.flags.device_aware_display_power") public void onRequestedBrightnessChanged(@FloatRange(from=0.0f, to=1.0f) float); + } + public final class VirtualDisplayConfig implements android.os.Parcelable { + method @FlaggedApi("android.companion.virtualdevice.flags.device_aware_display_power") @FloatRange(from=0.0f, to=1.0f) public float getDefaultBrightness(); method @FlaggedApi("android.companion.virtualdevice.flags.virtual_display_insets") @Nullable public android.view.DisplayCutout getDisplayCutout(); method @FlaggedApi("android.companion.virtual.flags.vdm_custom_home") public boolean isHomeSupported(); method @FlaggedApi("com.android.window.flags.vdm_force_app_universal_resizable_api") public boolean isIgnoreActivitySizeRestrictions(); } public static final class VirtualDisplayConfig.Builder { + method @FlaggedApi("android.companion.virtualdevice.flags.device_aware_display_power") @NonNull public android.hardware.display.VirtualDisplayConfig.Builder setDefaultBrightness(@FloatRange(from=0.0f, to=1.0f) float); method @FlaggedApi("android.companion.virtualdevice.flags.virtual_display_insets") @NonNull public android.hardware.display.VirtualDisplayConfig.Builder setDisplayCutout(@Nullable android.view.DisplayCutout); method @FlaggedApi("android.companion.virtual.flags.vdm_custom_home") @NonNull public android.hardware.display.VirtualDisplayConfig.Builder setHomeSupported(boolean); method @FlaggedApi("com.android.window.flags.vdm_force_app_universal_resizable_api") @NonNull public android.hardware.display.VirtualDisplayConfig.Builder setIgnoreActivitySizeRestrictions(boolean); @@ -7022,7 +7037,7 @@ package android.hardware.soundtrigger { method @NonNull public android.hardware.soundtrigger.SoundTrigger.RecognitionConfig.Builder setAllowMultipleTriggers(boolean); method @NonNull public android.hardware.soundtrigger.SoundTrigger.RecognitionConfig.Builder setAudioCapabilities(int); method @NonNull public android.hardware.soundtrigger.SoundTrigger.RecognitionConfig.Builder setCaptureRequested(boolean); - method @NonNull public android.hardware.soundtrigger.SoundTrigger.RecognitionConfig.Builder setData(@Nullable byte[]); + method @NonNull public android.hardware.soundtrigger.SoundTrigger.RecognitionConfig.Builder setData(@NonNull byte[]); method @NonNull public android.hardware.soundtrigger.SoundTrigger.RecognitionConfig.Builder setKeyphrases(@NonNull java.util.Collection); } @@ -7234,6 +7249,7 @@ package android.media { field @RequiresPermission(allOf={android.Manifest.permission.MODIFY_PHONE_STATE, android.Manifest.permission.MODIFY_AUDIO_ROUTING}) public static final int USAGE_CALL_ASSISTANT = 17; // 0x11 field @RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING) public static final int USAGE_EMERGENCY = 1000; // 0x3e8 field @RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING) public static final int USAGE_SAFETY = 1001; // 0x3e9 + field @FlaggedApi("android.media.audio.speaker_cleanup_usage") @RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING) public static final int USAGE_SPEAKER_CLEANUP = 1004; // 0x3ec field @RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING) public static final int USAGE_VEHICLE_STATUS = 1002; // 0x3ea } @@ -11647,8 +11663,11 @@ package android.os { public abstract class Vibrator { method @RequiresPermission(android.Manifest.permission.ACCESS_VIBRATOR_STATE) public void addVibratorStateListener(@NonNull android.os.Vibrator.OnVibratorStateChangedListener); method @RequiresPermission(android.Manifest.permission.ACCESS_VIBRATOR_STATE) public void addVibratorStateListener(@NonNull java.util.concurrent.Executor, @NonNull android.os.Vibrator.OnVibratorStateChangedListener); + method @FlaggedApi("android.os.vibrator.vendor_vibration_effects") public boolean areVendorEffectsSupported(); + method @FlaggedApi("android.os.vibrator.vendor_vibration_effects") public boolean areVendorSessionsSupported(); method @RequiresPermission(android.Manifest.permission.ACCESS_VIBRATOR_STATE) public boolean isVibrating(); method @RequiresPermission(android.Manifest.permission.ACCESS_VIBRATOR_STATE) public void removeVibratorStateListener(@NonNull android.os.Vibrator.OnVibratorStateChangedListener); + method @FlaggedApi("android.os.vibrator.vendor_vibration_effects") @RequiresPermission(allOf={android.Manifest.permission.VIBRATE, android.Manifest.permission.VIBRATE_VENDOR_EFFECTS, android.Manifest.permission.START_VIBRATION_SESSIONS}) public void startVendorSession(@NonNull android.os.VibrationAttributes, @Nullable String, @Nullable android.os.CancellationSignal, @NonNull java.util.concurrent.Executor, @NonNull android.os.vibrator.VendorVibrationSession.Callback); } public static interface Vibrator.OnVibratorStateChangedListener { @@ -11800,6 +11819,28 @@ package android.os.storage { } +package android.os.vibrator { + + @FlaggedApi("android.os.vibrator.vendor_vibration_effects") public final class VendorVibrationSession implements java.lang.AutoCloseable { + method public void cancel(); + method public void close(); + method @RequiresPermission(android.Manifest.permission.VIBRATE) public void vibrate(@NonNull android.os.VibrationEffect, @Nullable String); + field public static final int STATUS_CANCELED = 4; // 0x4 + field public static final int STATUS_IGNORED = 2; // 0x2 + field public static final int STATUS_SUCCESS = 1; // 0x1 + field public static final int STATUS_UNKNOWN = 0; // 0x0 + field public static final int STATUS_UNKNOWN_ERROR = 5; // 0x5 + field public static final int STATUS_UNSUPPORTED = 3; // 0x3 + } + + public static interface VendorVibrationSession.Callback { + method public void onFinished(int); + method public void onFinishing(); + method public void onStarted(@NonNull android.os.vibrator.VendorVibrationSession); + } + +} + package android.os.vibrator.persistence { @FlaggedApi("android.os.vibrator.vibration_xml_apis") public final class ParsedVibration { @@ -18292,7 +18333,12 @@ package android.telephony.satellite { method @FlaggedApi("com.android.internal.telephony.flags.oem_enabled_satellite_flag") @RequiresPermission(android.Manifest.permission.SATELLITE_COMMUNICATION) public void unregisterForModemStateChanged(@NonNull android.telephony.satellite.SatelliteModemStateCallback); method @FlaggedApi("com.android.internal.telephony.flags.oem_enabled_satellite_flag") @RequiresPermission(android.Manifest.permission.SATELLITE_COMMUNICATION) public void unregisterForNtnSignalStrengthChanged(@NonNull android.telephony.satellite.NtnSignalStrengthCallback); method @FlaggedApi("com.android.internal.telephony.flags.oem_enabled_satellite_flag") @RequiresPermission(android.Manifest.permission.SATELLITE_COMMUNICATION) public void unregisterForProvisionStateChanged(@NonNull android.telephony.satellite.SatelliteProvisionStateCallback); + field @FlaggedApi("com.android.internal.telephony.flags.satellite_system_apis") public static final int DATAGRAM_TYPE_CHECK_PENDING_INCOMING_SMS = 7; // 0x7 + field @FlaggedApi("com.android.internal.telephony.flags.satellite_system_apis") public static final int DATAGRAM_TYPE_KEEP_ALIVE = 3; // 0x3 + field @FlaggedApi("com.android.internal.telephony.flags.satellite_system_apis") public static final int DATAGRAM_TYPE_LAST_SOS_MESSAGE_NO_HELP_NEEDED = 5; // 0x5 + field @FlaggedApi("com.android.internal.telephony.flags.satellite_system_apis") public static final int DATAGRAM_TYPE_LAST_SOS_MESSAGE_STILL_NEED_HELP = 4; // 0x4 field @FlaggedApi("com.android.internal.telephony.flags.oem_enabled_satellite_flag") public static final int DATAGRAM_TYPE_LOCATION_SHARING = 2; // 0x2 + field @FlaggedApi("com.android.internal.telephony.flags.satellite_system_apis") public static final int DATAGRAM_TYPE_SMS = 6; // 0x6 field @FlaggedApi("com.android.internal.telephony.flags.oem_enabled_satellite_flag") public static final int DATAGRAM_TYPE_SOS_MESSAGE = 1; // 0x1 field @FlaggedApi("com.android.internal.telephony.flags.oem_enabled_satellite_flag") public static final int DATAGRAM_TYPE_UNKNOWN = 0; // 0x0 field @FlaggedApi("com.android.internal.telephony.flags.oem_enabled_satellite_flag") public static final int DEVICE_HOLD_POSITION_LANDSCAPE_LEFT = 2; // 0x2 @@ -18312,6 +18358,7 @@ package android.telephony.satellite { field @FlaggedApi("com.android.internal.telephony.flags.oem_enabled_satellite_flag") public static final int NT_RADIO_TECHNOLOGY_UNKNOWN = 0; // 0x0 field @FlaggedApi("com.android.internal.telephony.flags.carrier_enabled_satellite_flag") public static final int SATELLITE_COMMUNICATION_RESTRICTION_REASON_ENTITLEMENT = 2; // 0x2 field @FlaggedApi("com.android.internal.telephony.flags.carrier_enabled_satellite_flag") public static final int SATELLITE_COMMUNICATION_RESTRICTION_REASON_GEOLOCATION = 1; // 0x1 + field @FlaggedApi("com.android.internal.telephony.flags.satellite_system_apis") public static final int SATELLITE_COMMUNICATION_RESTRICTION_REASON_USER = 0; // 0x0 field @FlaggedApi("com.android.internal.telephony.flags.oem_enabled_satellite_flag") public static final int SATELLITE_DATAGRAM_TRANSFER_STATE_IDLE = 0; // 0x0 field @FlaggedApi("com.android.internal.telephony.flags.oem_enabled_satellite_flag") public static final int SATELLITE_DATAGRAM_TRANSFER_STATE_RECEIVE_FAILED = 7; // 0x7 field @FlaggedApi("com.android.internal.telephony.flags.oem_enabled_satellite_flag") public static final int SATELLITE_DATAGRAM_TRANSFER_STATE_RECEIVE_NONE = 6; // 0x6 @@ -18325,6 +18372,8 @@ package android.telephony.satellite { field @FlaggedApi("com.android.internal.telephony.flags.oem_enabled_satellite_flag") public static final int SATELLITE_MODEM_STATE_CONNECTED = 7; // 0x7 field @FlaggedApi("com.android.internal.telephony.flags.oem_enabled_satellite_flag") public static final int SATELLITE_MODEM_STATE_DATAGRAM_RETRYING = 3; // 0x3 field @FlaggedApi("com.android.internal.telephony.flags.oem_enabled_satellite_flag") public static final int SATELLITE_MODEM_STATE_DATAGRAM_TRANSFERRING = 2; // 0x2 + field @FlaggedApi("com.android.internal.telephony.flags.satellite_system_apis") public static final int SATELLITE_MODEM_STATE_DISABLING_SATELLITE = 9; // 0x9 + field @FlaggedApi("com.android.internal.telephony.flags.satellite_system_apis") public static final int SATELLITE_MODEM_STATE_ENABLING_SATELLITE = 8; // 0x8 field @FlaggedApi("com.android.internal.telephony.flags.oem_enabled_satellite_flag") public static final int SATELLITE_MODEM_STATE_IDLE = 0; // 0x0 field @FlaggedApi("com.android.internal.telephony.flags.oem_enabled_satellite_flag") public static final int SATELLITE_MODEM_STATE_LISTENING = 1; // 0x1 field @FlaggedApi("com.android.internal.telephony.flags.oem_enabled_satellite_flag") public static final int SATELLITE_MODEM_STATE_NOT_CONNECTED = 6; // 0x6 @@ -18332,11 +18381,16 @@ package android.telephony.satellite { field @FlaggedApi("com.android.internal.telephony.flags.oem_enabled_satellite_flag") public static final int SATELLITE_MODEM_STATE_UNAVAILABLE = 5; // 0x5 field @FlaggedApi("com.android.internal.telephony.flags.oem_enabled_satellite_flag") public static final int SATELLITE_MODEM_STATE_UNKNOWN = -1; // 0xffffffff field @FlaggedApi("com.android.internal.telephony.flags.oem_enabled_satellite_flag") public static final int SATELLITE_RESULT_ACCESS_BARRED = 16; // 0x10 + field @FlaggedApi("com.android.internal.telephony.flags.satellite_system_apis") public static final int SATELLITE_RESULT_DISABLE_IN_PROGRESS = 28; // 0x1c + field @FlaggedApi("com.android.internal.telephony.flags.satellite_system_apis") public static final int SATELLITE_RESULT_EMERGENCY_CALL_IN_PROGRESS = 27; // 0x1b + field @FlaggedApi("com.android.internal.telephony.flags.satellite_system_apis") public static final int SATELLITE_RESULT_ENABLE_IN_PROGRESS = 29; // 0x1d field @FlaggedApi("com.android.internal.telephony.flags.oem_enabled_satellite_flag") public static final int SATELLITE_RESULT_ERROR = 1; // 0x1 field @FlaggedApi("com.android.internal.telephony.flags.oem_enabled_satellite_flag") public static final int SATELLITE_RESULT_ILLEGAL_STATE = 23; // 0x17 field @FlaggedApi("com.android.internal.telephony.flags.oem_enabled_satellite_flag") public static final int SATELLITE_RESULT_INVALID_ARGUMENTS = 8; // 0x8 field @FlaggedApi("com.android.internal.telephony.flags.oem_enabled_satellite_flag") public static final int SATELLITE_RESULT_INVALID_MODEM_STATE = 7; // 0x7 field @FlaggedApi("com.android.internal.telephony.flags.oem_enabled_satellite_flag") public static final int SATELLITE_RESULT_INVALID_TELEPHONY_STATE = 6; // 0x6 + field @FlaggedApi("com.android.internal.telephony.flags.satellite_system_apis") public static final int SATELLITE_RESULT_LOCATION_DISABLED = 25; // 0x19 + field @FlaggedApi("com.android.internal.telephony.flags.satellite_system_apis") public static final int SATELLITE_RESULT_LOCATION_NOT_AVAILABLE = 26; // 0x1a field @FlaggedApi("com.android.internal.telephony.flags.oem_enabled_satellite_flag") public static final int SATELLITE_RESULT_MODEM_BUSY = 22; // 0x16 field @FlaggedApi("com.android.internal.telephony.flags.oem_enabled_satellite_flag") public static final int SATELLITE_RESULT_MODEM_ERROR = 4; // 0x4 field @FlaggedApi("com.android.internal.telephony.flags.oem_enabled_satellite_flag") public static final int SATELLITE_RESULT_MODEM_TIMEOUT = 24; // 0x18 diff --git a/core/api/test-current.txt b/core/api/test-current.txt index 98d6f58e6bcf73ecff69e64cc66f47509297545b..3ca55b932e196820747e3d74263217f744e14d32 100644 --- a/core/api/test-current.txt +++ b/core/api/test-current.txt @@ -402,6 +402,7 @@ package android.app { method @FlaggedApi("android.service.notification.notification_classification") @NonNull public java.util.Set getUnsupportedAdjustmentTypes(); method public boolean isNotificationPolicyAccessGrantedForPackage(@NonNull String); method @FlaggedApi("android.app.modes_api") public boolean removeAutomaticZenRule(@NonNull String, boolean); + method @FlaggedApi("android.service.notification.notification_classification") public void setAssistantAdjustmentKeyTypeState(int, boolean); method @FlaggedApi("android.app.api_rich_ongoing") public void setCanPostPromotedNotifications(@NonNull String, int, boolean); method @RequiresPermission(android.Manifest.permission.MANAGE_NOTIFICATION_LISTENERS) public void setNotificationListenerAccessGranted(@NonNull android.content.ComponentName, boolean, boolean); method @RequiresPermission(android.Manifest.permission.MANAGE_TOAST_RATE_LIMITING) public void setToastRateLimitingEnabled(boolean); @@ -3246,6 +3247,14 @@ 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); + } + +} + package android.service.voice { public class AlwaysOnHotwordDetector implements android.service.voice.HotwordDetector { @@ -3728,7 +3737,7 @@ package android.view { method public final int getDisplayId(); method public final void setDisplayId(int); field public static final int FLAG_IS_ACCESSIBILITY_EVENT = 2048; // 0x800 - field public static final int LAST_KEYCODE = 318; // 0x13e + field public static final int LAST_KEYCODE = 337; // 0x151 } public final class KeyboardShortcutGroup implements android.os.Parcelable { diff --git a/core/java/Android.bp b/core/java/Android.bp index 9875efe043619cc0114dec3829b9f71c57a56bfa..cf5ebbaa37b4b34223fd04b488e7aa108da252a7 100644 --- a/core/java/Android.bp +++ b/core/java/Android.bp @@ -28,6 +28,7 @@ filegroup { exclude_srcs: [ "android/os/*MessageQueue/**/*.java", "android/ranging/**/*.java", + ":dynamic_instrumentation_manager_aidl_sources", ], visibility: ["//frameworks/base"], } @@ -119,6 +120,17 @@ filegroup { srcs: ["android/tracing/TraceReportParams.aidl"], } +filegroup { + name: "dynamic_instrumentation_manager_aidl_sources", + srcs: ["android/os/instrumentation/*.aidl"], +} + +aidl_interface { + name: "dynamic_instrumentation_manager_aidl", + srcs: [":dynamic_instrumentation_manager_aidl_sources"], + unstable: true, +} + filegroup { name: "framework-internal-display-sources", srcs: ["com/android/internal/display/BrightnessSynchronizer.java"], @@ -206,6 +218,7 @@ filegroup { "android/os/Temperature.aidl", "android/os/CoolingDevice.aidl", "android/os/IThermalEventListener.aidl", + "android/os/IThermalHeadroomListener.aidl", "android/os/IThermalStatusListener.aidl", "android/os/IThermalService.aidl", "android/os/IPowerManager.aidl", @@ -684,16 +697,31 @@ gen_readonly_feature_apis = select(release_flag("RELEASE_USE_SYSTEM_FEATURE_BUIL // 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 { 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 + - // For now, only export "android.hardware.type.*" system features APIs. - // TODO(b/203143243): Use an intermediate soong var that aggregates all declared - // RELEASE_SYSTEM_FEATURE_* declarations into a single arg. - " --feature-apis=AUTOMOTIVE,WATCH,TELEVISION,EMBEDDED,PC" + - " > $(out)", + " --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", ], diff --git a/core/java/android/adaptiveauth/OWNERS b/core/java/android/adaptiveauth/OWNERS index 0218a7835586681a06590c0c02f6e9f4081067ee..bc8efa92c16fc13f49932747a686b2477fd8e630 100644 --- a/core/java/android/adaptiveauth/OWNERS +++ b/core/java/android/adaptiveauth/OWNERS @@ -1 +1 @@ -include /services/core/java/com/android/server/adaptiveauth/OWNERS \ No newline at end of file +include /services/core/java/com/android/server/security/adaptiveauthentication/OWNERS \ No newline at end of file diff --git a/core/java/android/app/Activity.java b/core/java/android/app/Activity.java index 7a1c759a3ec44ad767f8d8641bf93d3ff25a1e67..3fccc17e1bf12741a0758ea475e2a9ce39319dfb 100644 --- a/core/java/android/app/Activity.java +++ b/core/java/android/app/Activity.java @@ -30,6 +30,7 @@ import static com.android.sdksandbox.flags.Flags.sandboxActivitySdkBasedContext; import static java.lang.Character.MIN_VALUE; +import android.Manifest; import android.annotation.AnimRes; import android.annotation.CallSuper; import android.annotation.CallbackExecutor; @@ -3193,6 +3194,16 @@ public class Activity extends ContextThemeWrapper return ActivityTaskManager.getMaxNumPictureInPictureActions(this); } + private boolean isImplicitEnterPipProhibited() { + PackageManager pm = getPackageManager(); + if (android.app.Flags.enableTvImplicitEnterPipRestriction()) { + return pm.hasSystemFeature(PackageManager.FEATURE_LEANBACK) + && pm.checkPermission(Manifest.permission.TV_IMPLICIT_ENTER_PIP, + getPackageName()) == PackageManager.PERMISSION_DENIED; + } + return false; + } + /** * @return Whether this device supports picture-in-picture. */ @@ -9192,6 +9203,8 @@ public class Activity extends ContextThemeWrapper } dispatchActivityPreResumed(); + mCanEnterPictureInPicture = true; + mFragments.execPendingActions(); mLastNonConfigurationInstances = null; @@ -9243,6 +9256,11 @@ public class Activity extends ContextThemeWrapper Trace.traceBegin(Trace.TRACE_TAG_WINDOW_MANAGER, "performPause:" + mComponent.getClassName()); } + + if (isImplicitEnterPipProhibited()) { + mCanEnterPictureInPicture = false; + } + dispatchActivityPrePaused(); mDoReportFullyDrawn = false; mFragments.dispatchPause(); @@ -9265,6 +9283,10 @@ public class Activity extends ContextThemeWrapper final void performUserLeaving() { onUserInteraction(); + + if (isImplicitEnterPipProhibited()) { + mCanEnterPictureInPicture = false; + } onUserLeaveHint(); } diff --git a/core/java/android/app/ActivityManager.java b/core/java/android/app/ActivityManager.java index 36fc65a76d53a67608ef7c2861fd2ab16f65859f..b447897733e148d2ddc1a4081eede9368e9737d5 100644 --- a/core/java/android/app/ActivityManager.java +++ b/core/java/android/app/ActivityManager.java @@ -2764,14 +2764,19 @@ public class ActivityManager { /** * 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() { @@ -2793,7 +2798,7 @@ public class ActivityManager { lastSnapshotData.taskSize = source.readTypedObject(Point.CREATOR); lastSnapshotData.contentInsets = source.readTypedObject(Rect.CREATOR); lastSnapshotData.bufferSize = source.readTypedObject(Point.CREATOR); - super.readFromParcel(source); + super.readTaskFromParcel(source); } @Override @@ -2804,7 +2809,7 @@ public class ActivityManager { dest.writeTypedObject(lastSnapshotData.taskSize, flags); dest.writeTypedObject(lastSnapshotData.contentInsets, flags); dest.writeTypedObject(lastSnapshotData.bufferSize, flags); - super.writeToParcel(dest, flags); + super.writeTaskToParcel(dest, flags); } public static final @android.annotation.NonNull Creator CREATOR @@ -2988,13 +2993,13 @@ public class ActivityManager { public void readFromParcel(Parcel source) { id = source.readInt(); - super.readFromParcel(source); + super.readTaskFromParcel(source); } @Override public void writeToParcel(Parcel dest, int flags) { dest.writeInt(id); - super.writeToParcel(dest, flags); + super.writeTaskToParcel(dest, flags); } public static final @android.annotation.NonNull Creator CREATOR = new Creator() { diff --git a/core/java/android/app/ActivityTaskManager.java b/core/java/android/app/ActivityTaskManager.java index 799df1f9227a20ca3e5ff1127d91da9cc4977b79..16dcf2ad7e45745e3fa8dfc22f50fd2e232d0130 100644 --- a/core/java/android/app/ActivityTaskManager.java +++ b/core/java/android/app/ActivityTaskManager.java @@ -534,10 +534,9 @@ public class ActivityTaskManager { dest.writeIntArray(childTaskUserIds); dest.writeInt(visible ? 1 : 0); dest.writeInt(position); - super.writeToParcel(dest, flags); + super.writeTaskToParcel(dest, flags); } - @Override void readFromParcel(Parcel source) { bounds = source.readTypedObject(Rect.CREATOR); childTaskIds = source.createIntArray(); @@ -546,7 +545,7 @@ public class ActivityTaskManager { childTaskUserIds = source.createIntArray(); visible = source.readInt() > 0; position = source.readInt(); - super.readFromParcel(source); + super.readTaskFromParcel(source); } public static final @NonNull Creator CREATOR = new Creator<>() { diff --git a/core/java/android/app/ActivityThread.java b/core/java/android/app/ActivityThread.java index ca98da76b78f3de34a73f430a24f115c55508712..60b8f80d8f2dcc47cdd08c5fe62436169cf38781 100644 --- a/core/java/android/app/ActivityThread.java +++ b/core/java/android/app/ActivityThread.java @@ -3100,6 +3100,19 @@ public final class ActivityThread extends ClientTransactionHandler mResourcesManager = ResourcesManager.getInstance(); } + /** + * Creates and initialize a new system activity thread, to be used for testing. This does not + * call {@link #attach}, so it does not modify static state. + */ + @VisibleForTesting + @NonNull + public static ActivityThread createSystemActivityThreadForTesting() { + final var thread = new ActivityThread(); + thread.mSystemThread = true; + initializeSystemThread(thread); + return thread; + } + @UnsupportedAppUsage public ApplicationThread getApplicationThread() { @@ -6806,6 +6819,16 @@ public final class ActivityThread extends ClientTransactionHandler LoadedApk.makePaths(this, resApk.getApplicationInfo(), oldPaths); resApk.updateApplicationInfo(ai, oldPaths); } + if (android.content.res.Flags.systemContextHandleAppInfoChanged() && mSystemThread) { + final var systemContext = getSystemContext(); + if (systemContext.getPackageName().equals(ai.packageName)) { + // The system package is not tracked directly, but still needs to receive updates to + // its application info. + final ArrayList oldPaths = new ArrayList<>(); + LoadedApk.makePaths(this, systemContext.getApplicationInfo(), oldPaths); + systemContext.mPackageInfo.updateApplicationInfo(ai, oldPaths); + } + } ResourcesImpl beforeImpl = getApplication().getResources().getImpl(); @@ -8560,17 +8583,7 @@ public final class ActivityThread extends ClientTransactionHandler // we can't display an alert, we just want to die die die. android.ddm.DdmHandleAppName.setAppName("system_process", UserHandle.myUserId()); - try { - mInstrumentation = new Instrumentation(); - mInstrumentation.basicInit(this); - ContextImpl context = ContextImpl.createAppContext( - this, getSystemContext().mPackageInfo); - mInitialApplication = context.mPackageInfo.makeApplicationInner(true, null); - mInitialApplication.onCreate(); - } catch (Exception e) { - throw new RuntimeException( - "Unable to instantiate Application():" + e.toString(), e); - } + initializeSystemThread(this); } ViewRootImpl.ConfigChangedCallback configChangedCallback = (Configuration globalConfig) -> { @@ -8595,6 +8608,28 @@ public final class ActivityThread extends ClientTransactionHandler ViewRootImpl.addConfigCallback(configChangedCallback); } + /** + * Initializes the given system activity thread, setting up its instrumentation and initial + * application. This only has an effect if the given thread is a {@link #mSystemThread}. + * + * @param thread the given system activity thread to initialize. + */ + private static void initializeSystemThread(@NonNull ActivityThread thread) { + if (!thread.mSystemThread) { + return; + } + try { + thread.mInstrumentation = new Instrumentation(); + thread.mInstrumentation.basicInit(thread); + ContextImpl context = ContextImpl.createAppContext( + thread, thread.getSystemContext().mPackageInfo); + thread.mInitialApplication = context.mPackageInfo.makeApplicationInner(true, null); + thread.mInitialApplication.onCreate(); + } catch (Exception e) { + throw new RuntimeException("Unable to instantiate Application():" + e, e); + } + } + @UnsupportedAppUsage public static ActivityThread systemMain() { ThreadedRenderer.initForSystemProcess(); diff --git a/core/java/android/app/AppCompatCallbacks.java b/core/java/android/app/AppCompatCallbacks.java index 4bfa3b340ec91a5262d013a2b7a467c154dcebab..cf01f50c80268f521dfbbfe8605f23a235d9d4ca 100644 --- a/core/java/android/app/AppCompatCallbacks.java +++ b/core/java/android/app/AppCompatCallbacks.java @@ -28,6 +28,7 @@ import java.util.Arrays; * * @hide */ +@android.ravenwood.annotation.RavenwoodKeepWholeClass public final class AppCompatCallbacks implements Compatibility.BehaviorChangeDelegate { private final long[] mDisabledChanges; private final long[] mLoggableChanges; diff --git a/core/java/android/app/AppCompatTaskInfo.java b/core/java/android/app/AppCompatTaskInfo.java index 8370c2e522f34e527a5689b95c4cd44bf44837c9..009cd7249dcdb0d252ae16a631f3bdaa590b885c 100644 --- a/core/java/android/app/AppCompatTaskInfo.java +++ b/core/java/android/app/AppCompatTaskInfo.java @@ -101,7 +101,6 @@ public class AppCompatTaskInfo implements Parcelable { @Retention(RetentionPolicy.SOURCE) @IntDef(flag = true, value = { FLAG_UNDEFINED, - FLAG_BASE, FLAG_LETTERBOX_EDU_ENABLED, FLAG_ELIGIBLE_FOR_LETTERBOX_EDU, FLAG_LETTERBOXED, @@ -115,6 +114,10 @@ public class AppCompatTaskInfo implements Parcelable { }) public @interface TopActivityFlag {} + /** + * A combination of {@link TopActivityFlag}s that have been enabled through + * {@link #setTopActivityFlag}. + */ @TopActivityFlag private int mTopActivityFlags; @@ -167,10 +170,11 @@ public class AppCompatTaskInfo implements Parcelable { } /** - * @return {@code true} if top activity is pillarboxed. + * @return {@code true} if the top activity bounds are letterboxed with width <= height. */ - public boolean isTopActivityPillarboxed() { - return topActivityLetterboxWidth < topActivityLetterboxHeight; + public boolean isTopActivityPillarboxShaped() { + return isTopActivityLetterboxed() + && topActivityLetterboxWidth <= topActivityLetterboxHeight; } /** diff --git a/core/java/android/app/AppOpsManager.java b/core/java/android/app/AppOpsManager.java index 2b0e86c3205c2c76a29782c1e42e3ca010873837..fd70f4fc3f257fdde624e6273cb342bdb506065f 100644 --- a/core/java/android/app/AppOpsManager.java +++ b/core/java/android/app/AppOpsManager.java @@ -63,6 +63,7 @@ import android.os.Handler; import android.os.HandlerExecutor; import android.os.HandlerThread; import android.os.IBinder; +import android.os.IpcDataCache; import android.os.Looper; import android.os.PackageTagsList; import android.os.Parcel; @@ -78,12 +79,14 @@ import android.permission.PermissionGroupUsage; import android.permission.PermissionUsageHelper; import android.permission.flags.Flags; import android.provider.DeviceConfig; +import android.text.TextUtils; import android.util.ArrayMap; import android.util.ArraySet; import android.util.LongSparseArray; import android.util.LongSparseLongArray; import android.util.Pools; import android.util.SparseArray; +import android.util.SparseBooleanArray; import com.android.internal.annotations.GuardedBy; import com.android.internal.annotations.Immutable; @@ -910,159 +913,157 @@ public class AppOpsManager { /** @hide No operation specified. */ @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553) - public static final int OP_NONE = AppProtoEnums.APP_OP_NONE; + public static final int OP_NONE = AppOpEnums.APP_OP_NONE; /** @hide Access to coarse location information. */ @UnsupportedAppUsage @TestApi - public static final int OP_COARSE_LOCATION = AppProtoEnums.APP_OP_COARSE_LOCATION; + public static final int OP_COARSE_LOCATION = AppOpEnums.APP_OP_COARSE_LOCATION; /** @hide Access to fine location information. */ @UnsupportedAppUsage - public static final int OP_FINE_LOCATION = AppProtoEnums.APP_OP_FINE_LOCATION; + public static final int OP_FINE_LOCATION = AppOpEnums.APP_OP_FINE_LOCATION; /** @hide Causing GPS to run. */ @UnsupportedAppUsage - public static final int OP_GPS = AppProtoEnums.APP_OP_GPS; + public static final int OP_GPS = AppOpEnums.APP_OP_GPS; /** @hide */ @UnsupportedAppUsage - public static final int OP_VIBRATE = AppProtoEnums.APP_OP_VIBRATE; + public static final int OP_VIBRATE = AppOpEnums.APP_OP_VIBRATE; /** @hide */ @UnsupportedAppUsage - public static final int OP_READ_CONTACTS = AppProtoEnums.APP_OP_READ_CONTACTS; + public static final int OP_READ_CONTACTS = AppOpEnums.APP_OP_READ_CONTACTS; /** @hide */ @UnsupportedAppUsage - public static final int OP_WRITE_CONTACTS = AppProtoEnums.APP_OP_WRITE_CONTACTS; + public static final int OP_WRITE_CONTACTS = AppOpEnums.APP_OP_WRITE_CONTACTS; /** @hide */ @UnsupportedAppUsage - public static final int OP_READ_CALL_LOG = AppProtoEnums.APP_OP_READ_CALL_LOG; + public static final int OP_READ_CALL_LOG = AppOpEnums.APP_OP_READ_CALL_LOG; /** @hide */ @UnsupportedAppUsage - public static final int OP_WRITE_CALL_LOG = AppProtoEnums.APP_OP_WRITE_CALL_LOG; + public static final int OP_WRITE_CALL_LOG = AppOpEnums.APP_OP_WRITE_CALL_LOG; /** @hide */ @UnsupportedAppUsage - public static final int OP_READ_CALENDAR = AppProtoEnums.APP_OP_READ_CALENDAR; + public static final int OP_READ_CALENDAR = AppOpEnums.APP_OP_READ_CALENDAR; /** @hide */ @UnsupportedAppUsage - public static final int OP_WRITE_CALENDAR = AppProtoEnums.APP_OP_WRITE_CALENDAR; + public static final int OP_WRITE_CALENDAR = AppOpEnums.APP_OP_WRITE_CALENDAR; /** @hide */ @UnsupportedAppUsage - public static final int OP_WIFI_SCAN = AppProtoEnums.APP_OP_WIFI_SCAN; + public static final int OP_WIFI_SCAN = AppOpEnums.APP_OP_WIFI_SCAN; /** @hide */ @UnsupportedAppUsage - public static final int OP_POST_NOTIFICATION = AppProtoEnums.APP_OP_POST_NOTIFICATION; + public static final int OP_POST_NOTIFICATION = AppOpEnums.APP_OP_POST_NOTIFICATION; /** @hide */ @UnsupportedAppUsage - public static final int OP_NEIGHBORING_CELLS = AppProtoEnums.APP_OP_NEIGHBORING_CELLS; + public static final int OP_NEIGHBORING_CELLS = AppOpEnums.APP_OP_NEIGHBORING_CELLS; /** @hide */ @UnsupportedAppUsage - public static final int OP_CALL_PHONE = AppProtoEnums.APP_OP_CALL_PHONE; + public static final int OP_CALL_PHONE = AppOpEnums.APP_OP_CALL_PHONE; /** @hide */ @UnsupportedAppUsage - public static final int OP_READ_SMS = AppProtoEnums.APP_OP_READ_SMS; + public static final int OP_READ_SMS = AppOpEnums.APP_OP_READ_SMS; /** @hide */ @UnsupportedAppUsage - public static final int OP_WRITE_SMS = AppProtoEnums.APP_OP_WRITE_SMS; + public static final int OP_WRITE_SMS = AppOpEnums.APP_OP_WRITE_SMS; /** @hide */ @UnsupportedAppUsage - public static final int OP_RECEIVE_SMS = AppProtoEnums.APP_OP_RECEIVE_SMS; + public static final int OP_RECEIVE_SMS = AppOpEnums.APP_OP_RECEIVE_SMS; /** @hide */ @UnsupportedAppUsage - public static final int OP_RECEIVE_EMERGECY_SMS = - AppProtoEnums.APP_OP_RECEIVE_EMERGENCY_SMS; + public static final int OP_RECEIVE_EMERGECY_SMS = AppOpEnums.APP_OP_RECEIVE_EMERGENCY_SMS; /** @hide */ @UnsupportedAppUsage - public static final int OP_RECEIVE_MMS = AppProtoEnums.APP_OP_RECEIVE_MMS; + public static final int OP_RECEIVE_MMS = AppOpEnums.APP_OP_RECEIVE_MMS; /** @hide */ @UnsupportedAppUsage - public static final int OP_RECEIVE_WAP_PUSH = AppProtoEnums.APP_OP_RECEIVE_WAP_PUSH; + public static final int OP_RECEIVE_WAP_PUSH = AppOpEnums.APP_OP_RECEIVE_WAP_PUSH; /** @hide */ @UnsupportedAppUsage - public static final int OP_SEND_SMS = AppProtoEnums.APP_OP_SEND_SMS; + public static final int OP_SEND_SMS = AppOpEnums.APP_OP_SEND_SMS; /** @hide */ - public static final int OP_MANAGE_ONGOING_CALLS = AppProtoEnums.APP_OP_MANAGE_ONGOING_CALLS; + public static final int OP_MANAGE_ONGOING_CALLS = AppOpEnums.APP_OP_MANAGE_ONGOING_CALLS; /** @hide */ @UnsupportedAppUsage - public static final int OP_READ_ICC_SMS = AppProtoEnums.APP_OP_READ_ICC_SMS; + public static final int OP_READ_ICC_SMS = AppOpEnums.APP_OP_READ_ICC_SMS; /** @hide */ @UnsupportedAppUsage - public static final int OP_WRITE_ICC_SMS = AppProtoEnums.APP_OP_WRITE_ICC_SMS; + public static final int OP_WRITE_ICC_SMS = AppOpEnums.APP_OP_WRITE_ICC_SMS; /** @hide */ @UnsupportedAppUsage - public static final int OP_WRITE_SETTINGS = AppProtoEnums.APP_OP_WRITE_SETTINGS; + public static final int OP_WRITE_SETTINGS = AppOpEnums.APP_OP_WRITE_SETTINGS; /** @hide Required to draw on top of other apps. */ @UnsupportedAppUsage @TestApi - public static final int OP_SYSTEM_ALERT_WINDOW = AppProtoEnums.APP_OP_SYSTEM_ALERT_WINDOW; + public static final int OP_SYSTEM_ALERT_WINDOW = AppOpEnums.APP_OP_SYSTEM_ALERT_WINDOW; /** @hide */ @UnsupportedAppUsage - public static final int OP_ACCESS_NOTIFICATIONS = - AppProtoEnums.APP_OP_ACCESS_NOTIFICATIONS; + public static final int OP_ACCESS_NOTIFICATIONS = AppOpEnums.APP_OP_ACCESS_NOTIFICATIONS; /** @hide */ @UnsupportedAppUsage - public static final int OP_CAMERA = AppProtoEnums.APP_OP_CAMERA; + public static final int OP_CAMERA = AppOpEnums.APP_OP_CAMERA; /** @hide */ @UnsupportedAppUsage @TestApi - public static final int OP_RECORD_AUDIO = AppProtoEnums.APP_OP_RECORD_AUDIO; + public static final int OP_RECORD_AUDIO = AppOpEnums.APP_OP_RECORD_AUDIO; /** @hide */ @UnsupportedAppUsage - public static final int OP_PLAY_AUDIO = AppProtoEnums.APP_OP_PLAY_AUDIO; + public static final int OP_PLAY_AUDIO = AppOpEnums.APP_OP_PLAY_AUDIO; /** @hide */ @UnsupportedAppUsage - public static final int OP_READ_CLIPBOARD = AppProtoEnums.APP_OP_READ_CLIPBOARD; + public static final int OP_READ_CLIPBOARD = AppOpEnums.APP_OP_READ_CLIPBOARD; /** @hide */ @UnsupportedAppUsage - public static final int OP_WRITE_CLIPBOARD = AppProtoEnums.APP_OP_WRITE_CLIPBOARD; + public static final int OP_WRITE_CLIPBOARD = AppOpEnums.APP_OP_WRITE_CLIPBOARD; /** @hide */ @UnsupportedAppUsage - public static final int OP_TAKE_MEDIA_BUTTONS = AppProtoEnums.APP_OP_TAKE_MEDIA_BUTTONS; + public static final int OP_TAKE_MEDIA_BUTTONS = AppOpEnums.APP_OP_TAKE_MEDIA_BUTTONS; /** @hide */ @UnsupportedAppUsage - public static final int OP_TAKE_AUDIO_FOCUS = AppProtoEnums.APP_OP_TAKE_AUDIO_FOCUS; + public static final int OP_TAKE_AUDIO_FOCUS = AppOpEnums.APP_OP_TAKE_AUDIO_FOCUS; /** @hide */ @UnsupportedAppUsage - public static final int OP_AUDIO_MASTER_VOLUME = AppProtoEnums.APP_OP_AUDIO_MASTER_VOLUME; + public static final int OP_AUDIO_MASTER_VOLUME = AppOpEnums.APP_OP_AUDIO_MASTER_VOLUME; /** @hide */ @UnsupportedAppUsage - public static final int OP_AUDIO_VOICE_VOLUME = AppProtoEnums.APP_OP_AUDIO_VOICE_VOLUME; + public static final int OP_AUDIO_VOICE_VOLUME = AppOpEnums.APP_OP_AUDIO_VOICE_VOLUME; /** @hide */ @UnsupportedAppUsage - public static final int OP_AUDIO_RING_VOLUME = AppProtoEnums.APP_OP_AUDIO_RING_VOLUME; + public static final int OP_AUDIO_RING_VOLUME = AppOpEnums.APP_OP_AUDIO_RING_VOLUME; /** @hide */ @UnsupportedAppUsage - public static final int OP_AUDIO_MEDIA_VOLUME = AppProtoEnums.APP_OP_AUDIO_MEDIA_VOLUME; + public static final int OP_AUDIO_MEDIA_VOLUME = AppOpEnums.APP_OP_AUDIO_MEDIA_VOLUME; /** @hide */ @UnsupportedAppUsage - public static final int OP_AUDIO_ALARM_VOLUME = AppProtoEnums.APP_OP_AUDIO_ALARM_VOLUME; + public static final int OP_AUDIO_ALARM_VOLUME = AppOpEnums.APP_OP_AUDIO_ALARM_VOLUME; /** @hide */ @UnsupportedAppUsage public static final int OP_AUDIO_NOTIFICATION_VOLUME = - AppProtoEnums.APP_OP_AUDIO_NOTIFICATION_VOLUME; + AppOpEnums.APP_OP_AUDIO_NOTIFICATION_VOLUME; /** @hide */ @UnsupportedAppUsage public static final int OP_AUDIO_BLUETOOTH_VOLUME = - AppProtoEnums.APP_OP_AUDIO_BLUETOOTH_VOLUME; + AppOpEnums.APP_OP_AUDIO_BLUETOOTH_VOLUME; /** @hide */ @UnsupportedAppUsage - public static final int OP_WAKE_LOCK = AppProtoEnums.APP_OP_WAKE_LOCK; + public static final int OP_WAKE_LOCK = AppOpEnums.APP_OP_WAKE_LOCK; /** @hide Continually monitoring location data. */ @UnsupportedAppUsage public static final int OP_MONITOR_LOCATION = - AppProtoEnums.APP_OP_MONITOR_LOCATION; + AppOpEnums.APP_OP_MONITOR_LOCATION; /** @hide Continually monitoring location data with a relatively high power request. */ @UnsupportedAppUsage public static final int OP_MONITOR_HIGH_POWER_LOCATION = - AppProtoEnums.APP_OP_MONITOR_HIGH_POWER_LOCATION; + AppOpEnums.APP_OP_MONITOR_HIGH_POWER_LOCATION; /** @hide Retrieve current usage stats via {@link UsageStatsManager}. */ @UnsupportedAppUsage - public static final int OP_GET_USAGE_STATS = AppProtoEnums.APP_OP_GET_USAGE_STATS; + public static final int OP_GET_USAGE_STATS = AppOpEnums.APP_OP_GET_USAGE_STATS; /** @hide */ @UnsupportedAppUsage - public static final int OP_MUTE_MICROPHONE = AppProtoEnums.APP_OP_MUTE_MICROPHONE; + public static final int OP_MUTE_MICROPHONE = AppOpEnums.APP_OP_MUTE_MICROPHONE; /** @hide */ @UnsupportedAppUsage - public static final int OP_TOAST_WINDOW = AppProtoEnums.APP_OP_TOAST_WINDOW; + public static final int OP_TOAST_WINDOW = AppOpEnums.APP_OP_TOAST_WINDOW; /** @hide Capture the device's display contents and/or audio */ @UnsupportedAppUsage - public static final int OP_PROJECT_MEDIA = AppProtoEnums.APP_OP_PROJECT_MEDIA; + public static final int OP_PROJECT_MEDIA = AppOpEnums.APP_OP_PROJECT_MEDIA; /** * Start (without additional user intervention) a VPN connection, as used by {@link * android.net.VpnService} along with as Platform VPN connections, as used by {@link @@ -1075,146 +1076,141 @@ public class AppOpsManager { * @hide */ @UnsupportedAppUsage - public static final int OP_ACTIVATE_VPN = AppProtoEnums.APP_OP_ACTIVATE_VPN; + public static final int OP_ACTIVATE_VPN = AppOpEnums.APP_OP_ACTIVATE_VPN; /** @hide Access the WallpaperManagerAPI to write wallpapers. */ @UnsupportedAppUsage - public static final int OP_WRITE_WALLPAPER = AppProtoEnums.APP_OP_WRITE_WALLPAPER; + public static final int OP_WRITE_WALLPAPER = AppOpEnums.APP_OP_WRITE_WALLPAPER; /** @hide Received the assist structure from an app. */ @UnsupportedAppUsage - public static final int OP_ASSIST_STRUCTURE = AppProtoEnums.APP_OP_ASSIST_STRUCTURE; + public static final int OP_ASSIST_STRUCTURE = AppOpEnums.APP_OP_ASSIST_STRUCTURE; /** @hide Received a screenshot from assist. */ @UnsupportedAppUsage - public static final int OP_ASSIST_SCREENSHOT = AppProtoEnums.APP_OP_ASSIST_SCREENSHOT; + public static final int OP_ASSIST_SCREENSHOT = AppOpEnums.APP_OP_ASSIST_SCREENSHOT; /** @hide Read the phone state. */ @UnsupportedAppUsage - public static final int OP_READ_PHONE_STATE = AppProtoEnums.APP_OP_READ_PHONE_STATE; + public static final int OP_READ_PHONE_STATE = AppOpEnums.APP_OP_READ_PHONE_STATE; /** @hide Add voicemail messages to the voicemail content provider. */ @UnsupportedAppUsage - public static final int OP_ADD_VOICEMAIL = AppProtoEnums.APP_OP_ADD_VOICEMAIL; + public static final int OP_ADD_VOICEMAIL = AppOpEnums.APP_OP_ADD_VOICEMAIL; /** @hide Access APIs for SIP calling over VOIP or WiFi. */ @UnsupportedAppUsage - public static final int OP_USE_SIP = AppProtoEnums.APP_OP_USE_SIP; + public static final int OP_USE_SIP = AppOpEnums.APP_OP_USE_SIP; /** @hide Intercept outgoing calls. */ @UnsupportedAppUsage - public static final int OP_PROCESS_OUTGOING_CALLS = - AppProtoEnums.APP_OP_PROCESS_OUTGOING_CALLS; + public static final int OP_PROCESS_OUTGOING_CALLS = AppOpEnums.APP_OP_PROCESS_OUTGOING_CALLS; /** @hide User the fingerprint API. */ @UnsupportedAppUsage - public static final int OP_USE_FINGERPRINT = AppProtoEnums.APP_OP_USE_FINGERPRINT; + public static final int OP_USE_FINGERPRINT = AppOpEnums.APP_OP_USE_FINGERPRINT; /** @hide Access to body sensors such as heart rate, etc. */ @UnsupportedAppUsage - public static final int OP_BODY_SENSORS = AppProtoEnums.APP_OP_BODY_SENSORS; + public static final int OP_BODY_SENSORS = AppOpEnums.APP_OP_BODY_SENSORS; /** @hide Read previously received cell broadcast messages. */ @UnsupportedAppUsage - public static final int OP_READ_CELL_BROADCASTS = AppProtoEnums.APP_OP_READ_CELL_BROADCASTS; + public static final int OP_READ_CELL_BROADCASTS = AppOpEnums.APP_OP_READ_CELL_BROADCASTS; /** @hide Inject mock location into the system. */ @UnsupportedAppUsage - public static final int OP_MOCK_LOCATION = AppProtoEnums.APP_OP_MOCK_LOCATION; + public static final int OP_MOCK_LOCATION = AppOpEnums.APP_OP_MOCK_LOCATION; /** @hide Read external storage. */ @UnsupportedAppUsage - public static final int OP_READ_EXTERNAL_STORAGE = AppProtoEnums.APP_OP_READ_EXTERNAL_STORAGE; + public static final int OP_READ_EXTERNAL_STORAGE = AppOpEnums.APP_OP_READ_EXTERNAL_STORAGE; /** @hide Write external storage. */ @UnsupportedAppUsage - public static final int OP_WRITE_EXTERNAL_STORAGE = - AppProtoEnums.APP_OP_WRITE_EXTERNAL_STORAGE; + public static final int OP_WRITE_EXTERNAL_STORAGE = AppOpEnums.APP_OP_WRITE_EXTERNAL_STORAGE; /** @hide Turned on the screen. */ @UnsupportedAppUsage - public static final int OP_TURN_SCREEN_ON = AppProtoEnums.APP_OP_TURN_SCREEN_ON; + public static final int OP_TURN_SCREEN_ON = AppOpEnums.APP_OP_TURN_SCREEN_ON; /** @hide Get device accounts. */ @UnsupportedAppUsage - public static final int OP_GET_ACCOUNTS = AppProtoEnums.APP_OP_GET_ACCOUNTS; + public static final int OP_GET_ACCOUNTS = AppOpEnums.APP_OP_GET_ACCOUNTS; /** @hide Control whether an application is allowed to run in the background. */ @UnsupportedAppUsage - public static final int OP_RUN_IN_BACKGROUND = - AppProtoEnums.APP_OP_RUN_IN_BACKGROUND; + public static final int OP_RUN_IN_BACKGROUND = AppOpEnums.APP_OP_RUN_IN_BACKGROUND; /** @hide */ @UnsupportedAppUsage public static final int OP_AUDIO_ACCESSIBILITY_VOLUME = - AppProtoEnums.APP_OP_AUDIO_ACCESSIBILITY_VOLUME; + AppOpEnums.APP_OP_AUDIO_ACCESSIBILITY_VOLUME; /** @hide Read the phone number. */ @UnsupportedAppUsage - public static final int OP_READ_PHONE_NUMBERS = AppProtoEnums.APP_OP_READ_PHONE_NUMBERS; + public static final int OP_READ_PHONE_NUMBERS = AppOpEnums.APP_OP_READ_PHONE_NUMBERS; /** @hide Request package installs through package installer */ @UnsupportedAppUsage public static final int OP_REQUEST_INSTALL_PACKAGES = - AppProtoEnums.APP_OP_REQUEST_INSTALL_PACKAGES; + AppOpEnums.APP_OP_REQUEST_INSTALL_PACKAGES; /** @hide Enter picture-in-picture. */ @UnsupportedAppUsage - public static final int OP_PICTURE_IN_PICTURE = AppProtoEnums.APP_OP_PICTURE_IN_PICTURE; + public static final int OP_PICTURE_IN_PICTURE = AppOpEnums.APP_OP_PICTURE_IN_PICTURE; /** @hide Instant app start foreground service. */ @UnsupportedAppUsage public static final int OP_INSTANT_APP_START_FOREGROUND = - AppProtoEnums.APP_OP_INSTANT_APP_START_FOREGROUND; + AppOpEnums.APP_OP_INSTANT_APP_START_FOREGROUND; /** @hide Answer incoming phone calls */ @UnsupportedAppUsage - public static final int OP_ANSWER_PHONE_CALLS = AppProtoEnums.APP_OP_ANSWER_PHONE_CALLS; + public static final int OP_ANSWER_PHONE_CALLS = AppOpEnums.APP_OP_ANSWER_PHONE_CALLS; /** @hide Run jobs when in background */ @UnsupportedAppUsage - public static final int OP_RUN_ANY_IN_BACKGROUND = AppProtoEnums.APP_OP_RUN_ANY_IN_BACKGROUND; + public static final int OP_RUN_ANY_IN_BACKGROUND = AppOpEnums.APP_OP_RUN_ANY_IN_BACKGROUND; /** @hide Change Wi-Fi connectivity state */ @UnsupportedAppUsage - public static final int OP_CHANGE_WIFI_STATE = AppProtoEnums.APP_OP_CHANGE_WIFI_STATE; + public static final int OP_CHANGE_WIFI_STATE = AppOpEnums.APP_OP_CHANGE_WIFI_STATE; /** @hide Request package deletion through package installer */ @UnsupportedAppUsage - public static final int OP_REQUEST_DELETE_PACKAGES = - AppProtoEnums.APP_OP_REQUEST_DELETE_PACKAGES; + public static final int OP_REQUEST_DELETE_PACKAGES = AppOpEnums.APP_OP_REQUEST_DELETE_PACKAGES; /** @hide Bind an accessibility service. */ @UnsupportedAppUsage public static final int OP_BIND_ACCESSIBILITY_SERVICE = - AppProtoEnums.APP_OP_BIND_ACCESSIBILITY_SERVICE; + AppOpEnums.APP_OP_BIND_ACCESSIBILITY_SERVICE; /** @hide Continue handover of a call from another app */ @UnsupportedAppUsage - public static final int OP_ACCEPT_HANDOVER = AppProtoEnums.APP_OP_ACCEPT_HANDOVER; + public static final int OP_ACCEPT_HANDOVER = AppOpEnums.APP_OP_ACCEPT_HANDOVER; /** @hide Create and Manage IPsec Tunnels */ @UnsupportedAppUsage - public static final int OP_MANAGE_IPSEC_TUNNELS = AppProtoEnums.APP_OP_MANAGE_IPSEC_TUNNELS; + public static final int OP_MANAGE_IPSEC_TUNNELS = AppOpEnums.APP_OP_MANAGE_IPSEC_TUNNELS; /** @hide Any app start foreground service. */ @UnsupportedAppUsage @TestApi - public static final int OP_START_FOREGROUND = AppProtoEnums.APP_OP_START_FOREGROUND; + public static final int OP_START_FOREGROUND = AppOpEnums.APP_OP_START_FOREGROUND; /** @hide */ @UnsupportedAppUsage - public static final int OP_BLUETOOTH_SCAN = AppProtoEnums.APP_OP_BLUETOOTH_SCAN; + public static final int OP_BLUETOOTH_SCAN = AppOpEnums.APP_OP_BLUETOOTH_SCAN; /** @hide */ - public static final int OP_BLUETOOTH_CONNECT = AppProtoEnums.APP_OP_BLUETOOTH_CONNECT; + public static final int OP_BLUETOOTH_CONNECT = AppOpEnums.APP_OP_BLUETOOTH_CONNECT; /** @hide */ - public static final int OP_BLUETOOTH_ADVERTISE = AppProtoEnums.APP_OP_BLUETOOTH_ADVERTISE; + public static final int OP_BLUETOOTH_ADVERTISE = AppOpEnums.APP_OP_BLUETOOTH_ADVERTISE; /** @hide Use the BiometricPrompt/BiometricManager APIs. */ - public static final int OP_USE_BIOMETRIC = AppProtoEnums.APP_OP_USE_BIOMETRIC; + public static final int OP_USE_BIOMETRIC = AppOpEnums.APP_OP_USE_BIOMETRIC; /** @hide Physical activity recognition. */ - public static final int OP_ACTIVITY_RECOGNITION = AppProtoEnums.APP_OP_ACTIVITY_RECOGNITION; + public static final int OP_ACTIVITY_RECOGNITION = AppOpEnums.APP_OP_ACTIVITY_RECOGNITION; /** @hide Financial app sms read. */ public static final int OP_SMS_FINANCIAL_TRANSACTIONS = - AppProtoEnums.APP_OP_SMS_FINANCIAL_TRANSACTIONS; + AppOpEnums.APP_OP_SMS_FINANCIAL_TRANSACTIONS; /** @hide Read media of audio type. */ - public static final int OP_READ_MEDIA_AUDIO = AppProtoEnums.APP_OP_READ_MEDIA_AUDIO; + public static final int OP_READ_MEDIA_AUDIO = AppOpEnums.APP_OP_READ_MEDIA_AUDIO; /** @hide Write media of audio type. */ - public static final int OP_WRITE_MEDIA_AUDIO = AppProtoEnums.APP_OP_WRITE_MEDIA_AUDIO; + public static final int OP_WRITE_MEDIA_AUDIO = AppOpEnums.APP_OP_WRITE_MEDIA_AUDIO; /** @hide Read media of video type. */ - public static final int OP_READ_MEDIA_VIDEO = AppProtoEnums.APP_OP_READ_MEDIA_VIDEO; + public static final int OP_READ_MEDIA_VIDEO = AppOpEnums.APP_OP_READ_MEDIA_VIDEO; /** @hide Write media of video type. */ - public static final int OP_WRITE_MEDIA_VIDEO = AppProtoEnums.APP_OP_WRITE_MEDIA_VIDEO; + public static final int OP_WRITE_MEDIA_VIDEO = AppOpEnums.APP_OP_WRITE_MEDIA_VIDEO; /** @hide Read media of image type. */ - public static final int OP_READ_MEDIA_IMAGES = AppProtoEnums.APP_OP_READ_MEDIA_IMAGES; + public static final int OP_READ_MEDIA_IMAGES = AppOpEnums.APP_OP_READ_MEDIA_IMAGES; /** @hide Write media of image type. */ - public static final int OP_WRITE_MEDIA_IMAGES = AppProtoEnums.APP_OP_WRITE_MEDIA_IMAGES; + public static final int OP_WRITE_MEDIA_IMAGES = AppOpEnums.APP_OP_WRITE_MEDIA_IMAGES; /** @hide Has a legacy (non-isolated) view of storage. */ - public static final int OP_LEGACY_STORAGE = AppProtoEnums.APP_OP_LEGACY_STORAGE; + public static final int OP_LEGACY_STORAGE = AppOpEnums.APP_OP_LEGACY_STORAGE; /** @hide Accessing accessibility features */ - public static final int OP_ACCESS_ACCESSIBILITY = AppProtoEnums.APP_OP_ACCESS_ACCESSIBILITY; + public static final int OP_ACCESS_ACCESSIBILITY = AppOpEnums.APP_OP_ACCESS_ACCESSIBILITY; /** @hide Read the device identifiers (IMEI / MEID, IMSI, SIM / Build serial) */ public static final int OP_READ_DEVICE_IDENTIFIERS = - AppProtoEnums.APP_OP_READ_DEVICE_IDENTIFIERS; + AppOpEnums.APP_OP_READ_DEVICE_IDENTIFIERS; /** @hide Read location metadata from media */ - public static final int OP_ACCESS_MEDIA_LOCATION = AppProtoEnums.APP_OP_ACCESS_MEDIA_LOCATION; + public static final int OP_ACCESS_MEDIA_LOCATION = AppOpEnums.APP_OP_ACCESS_MEDIA_LOCATION; /** @hide Query all apps on device, regardless of declarations in the calling app manifest */ - public static final int OP_QUERY_ALL_PACKAGES = AppProtoEnums.APP_OP_QUERY_ALL_PACKAGES; + public static final int OP_QUERY_ALL_PACKAGES = AppOpEnums.APP_OP_QUERY_ALL_PACKAGES; /** @hide Access all external storage */ - public static final int OP_MANAGE_EXTERNAL_STORAGE = - AppProtoEnums.APP_OP_MANAGE_EXTERNAL_STORAGE; + public static final int OP_MANAGE_EXTERNAL_STORAGE = AppOpEnums.APP_OP_MANAGE_EXTERNAL_STORAGE; /** @hide Communicate cross-profile within the same profile group. */ public static final int OP_INTERACT_ACROSS_PROFILES = - AppProtoEnums.APP_OP_INTERACT_ACROSS_PROFILES; + AppOpEnums.APP_OP_INTERACT_ACROSS_PROFILES; /** * Start (without additional user intervention) a Platform VPN connection, as used by {@link * android.net.VpnManager} @@ -1225,16 +1221,16 @@ public class AppOpsManager { * * @hide */ - public static final int OP_ACTIVATE_PLATFORM_VPN = AppProtoEnums.APP_OP_ACTIVATE_PLATFORM_VPN; + public static final int OP_ACTIVATE_PLATFORM_VPN = AppOpEnums.APP_OP_ACTIVATE_PLATFORM_VPN; /** @hide Controls whether or not read logs are available for incremental installations. */ - public static final int OP_LOADER_USAGE_STATS = AppProtoEnums.APP_OP_LOADER_USAGE_STATS; + public static final int OP_LOADER_USAGE_STATS = AppOpEnums.APP_OP_LOADER_USAGE_STATS; // App op deprecated/removed. - private static final int OP_DEPRECATED_1 = AppProtoEnums.APP_OP_DEPRECATED_1; + private static final int OP_DEPRECATED_1 = AppOpEnums.APP_OP_DEPRECATED_1; /** @hide Auto-revoke app permissions if app is unused for an extended period */ public static final int OP_AUTO_REVOKE_PERMISSIONS_IF_UNUSED = - AppProtoEnums.APP_OP_AUTO_REVOKE_PERMISSIONS_IF_UNUSED; + AppOpEnums.APP_OP_AUTO_REVOKE_PERMISSIONS_IF_UNUSED; /** * Whether {@link #OP_AUTO_REVOKE_PERMISSIONS_IF_UNUSED} is allowed to be changed by @@ -1243,55 +1239,55 @@ public class AppOpsManager { * @hide */ public static final int OP_AUTO_REVOKE_MANAGED_BY_INSTALLER = - AppProtoEnums.APP_OP_AUTO_REVOKE_MANAGED_BY_INSTALLER; + AppOpEnums.APP_OP_AUTO_REVOKE_MANAGED_BY_INSTALLER; /** @hide */ - public static final int OP_NO_ISOLATED_STORAGE = AppProtoEnums.APP_OP_NO_ISOLATED_STORAGE; + public static final int OP_NO_ISOLATED_STORAGE = AppOpEnums.APP_OP_NO_ISOLATED_STORAGE; /** * Phone call is using microphone * * @hide */ - public static final int OP_PHONE_CALL_MICROPHONE = AppProtoEnums.APP_OP_PHONE_CALL_MICROPHONE; + public static final int OP_PHONE_CALL_MICROPHONE = AppOpEnums.APP_OP_PHONE_CALL_MICROPHONE; /** * Phone call is using camera * * @hide */ - public static final int OP_PHONE_CALL_CAMERA = AppProtoEnums.APP_OP_PHONE_CALL_CAMERA; + public static final int OP_PHONE_CALL_CAMERA = AppOpEnums.APP_OP_PHONE_CALL_CAMERA; /** * Audio is being recorded for hotword detection. * * @hide */ - public static final int OP_RECORD_AUDIO_HOTWORD = AppProtoEnums.APP_OP_RECORD_AUDIO_HOTWORD; + public static final int OP_RECORD_AUDIO_HOTWORD = AppOpEnums.APP_OP_RECORD_AUDIO_HOTWORD; /** * Manage credentials in the system KeyChain. * * @hide */ - public static final int OP_MANAGE_CREDENTIALS = AppProtoEnums.APP_OP_MANAGE_CREDENTIALS; + public static final int OP_MANAGE_CREDENTIALS = AppOpEnums.APP_OP_MANAGE_CREDENTIALS; /** @hide */ public static final int OP_USE_ICC_AUTH_WITH_DEVICE_IDENTIFIER = - AppProtoEnums.APP_OP_USE_ICC_AUTH_WITH_DEVICE_IDENTIFIER; + AppOpEnums.APP_OP_USE_ICC_AUTH_WITH_DEVICE_IDENTIFIER; /** * App output audio is being recorded * * @hide */ - public static final int OP_RECORD_AUDIO_OUTPUT = AppProtoEnums.APP_OP_RECORD_AUDIO_OUTPUT; + public static final int OP_RECORD_AUDIO_OUTPUT = AppOpEnums.APP_OP_RECORD_AUDIO_OUTPUT; /** * App can schedule exact alarm to perform timing based background work * * @hide */ - public static final int OP_SCHEDULE_EXACT_ALARM = AppProtoEnums.APP_OP_SCHEDULE_EXACT_ALARM; + public static final int OP_SCHEDULE_EXACT_ALARM = AppOpEnums.APP_OP_SCHEDULE_EXACT_ALARM; /** * Fine location being accessed by a location source, which is @@ -1301,7 +1297,7 @@ public class AppOpsManager { * * @hide */ - public static final int OP_FINE_LOCATION_SOURCE = AppProtoEnums.APP_OP_FINE_LOCATION_SOURCE; + public static final int OP_FINE_LOCATION_SOURCE = AppOpEnums.APP_OP_FINE_LOCATION_SOURCE; /** * Coarse location being accessed by a location source, which is @@ -1311,7 +1307,7 @@ public class AppOpsManager { * * @hide */ - public static final int OP_COARSE_LOCATION_SOURCE = AppProtoEnums.APP_OP_COARSE_LOCATION_SOURCE; + public static final int OP_COARSE_LOCATION_SOURCE = AppOpEnums.APP_OP_COARSE_LOCATION_SOURCE; /** * Allow apps to create the requests to manage the media files without user confirmation. @@ -1323,13 +1319,13 @@ public class AppOpsManager { * * @hide */ - public static final int OP_MANAGE_MEDIA = AppProtoEnums.APP_OP_MANAGE_MEDIA; + public static final int OP_MANAGE_MEDIA = AppOpEnums.APP_OP_MANAGE_MEDIA; /** @hide */ - public static final int OP_UWB_RANGING = AppProtoEnums.APP_OP_UWB_RANGING; + public static final int OP_UWB_RANGING = AppOpEnums.APP_OP_UWB_RANGING; /** @hide */ - public static final int OP_NEARBY_WIFI_DEVICES = AppProtoEnums.APP_OP_NEARBY_WIFI_DEVICES; + public static final int OP_NEARBY_WIFI_DEVICES = AppOpEnums.APP_OP_NEARBY_WIFI_DEVICES; /** * Activity recognition being accessed by an activity recognition source, which @@ -1339,7 +1335,7 @@ public class AppOpsManager { * @hide */ public static final int OP_ACTIVITY_RECOGNITION_SOURCE = - AppProtoEnums.APP_OP_ACTIVITY_RECOGNITION_SOURCE; + AppOpEnums.APP_OP_ACTIVITY_RECOGNITION_SOURCE; /** * Incoming phone audio is being recorded @@ -1347,21 +1343,21 @@ public class AppOpsManager { * @hide */ public static final int OP_RECORD_INCOMING_PHONE_AUDIO = - AppProtoEnums.APP_OP_RECORD_INCOMING_PHONE_AUDIO; + AppOpEnums.APP_OP_RECORD_INCOMING_PHONE_AUDIO; /** * VPN app establishes a connection through the VpnService API. * * @hide */ - public static final int OP_ESTABLISH_VPN_SERVICE = AppProtoEnums.APP_OP_ESTABLISH_VPN_SERVICE; + public static final int OP_ESTABLISH_VPN_SERVICE = AppOpEnums.APP_OP_ESTABLISH_VPN_SERVICE; /** * VPN app establishes a connection through the VpnManager API. * * @hide */ - public static final int OP_ESTABLISH_VPN_MANAGER = AppProtoEnums.APP_OP_ESTABLISH_VPN_MANAGER; + public static final int OP_ESTABLISH_VPN_MANAGER = AppOpEnums.APP_OP_ESTABLISH_VPN_MANAGER; /** * Access restricted settings. @@ -1369,7 +1365,7 @@ public class AppOpsManager { * @hide */ public static final int OP_ACCESS_RESTRICTED_SETTINGS = - AppProtoEnums.APP_OP_ACCESS_RESTRICTED_SETTINGS; + AppOpEnums.APP_OP_ACCESS_RESTRICTED_SETTINGS; /** * Receive microphone audio from an ambient sound detection event @@ -1377,7 +1373,7 @@ public class AppOpsManager { * @hide */ public static final int OP_RECEIVE_AMBIENT_TRIGGER_AUDIO = - AppProtoEnums.APP_OP_RECEIVE_AMBIENT_TRIGGER_AUDIO; + AppOpEnums.APP_OP_RECEIVE_AMBIENT_TRIGGER_AUDIO; /** * Receive audio from near-field mic (ie. TV remote) @@ -1387,15 +1383,14 @@ public class AppOpsManager { * @hide */ public static final int OP_RECEIVE_EXPLICIT_USER_INTERACTION_AUDIO = - AppProtoEnums.APP_OP_RECEIVE_EXPLICIT_USER_INTERACTION_AUDIO; + AppOpEnums.APP_OP_RECEIVE_EXPLICIT_USER_INTERACTION_AUDIO; /** * App can schedule user-initiated jobs. * * @hide */ - public static final int OP_RUN_USER_INITIATED_JOBS = - AppProtoEnums.APP_OP_RUN_USER_INITIATED_JOBS; + public static final int OP_RUN_USER_INITIATED_JOBS = AppOpEnums.APP_OP_RUN_USER_INITIATED_JOBS; /** * Notify apps that they have been granted URI permission photos @@ -1403,7 +1398,7 @@ public class AppOpsManager { * @hide */ public static final int OP_READ_MEDIA_VISUAL_USER_SELECTED = - AppProtoEnums.APP_OP_READ_MEDIA_VISUAL_USER_SELECTED; + AppOpEnums.APP_OP_READ_MEDIA_VISUAL_USER_SELECTED; /** * Prevent an app from being suspended. @@ -1413,7 +1408,7 @@ public class AppOpsManager { * @hide */ public static final int OP_SYSTEM_EXEMPT_FROM_SUSPENSION = - AppProtoEnums.APP_OP_SYSTEM_EXEMPT_FROM_SUSPENSION; + AppOpEnums.APP_OP_SYSTEM_EXEMPT_FROM_SUSPENSION; /** * Prevent an app from dismissible notifications. Starting from Android U, notifications with @@ -1425,14 +1420,14 @@ public class AppOpsManager { * @hide */ public static final int OP_SYSTEM_EXEMPT_FROM_DISMISSIBLE_NOTIFICATIONS = - AppProtoEnums.APP_OP_SYSTEM_EXEMPT_FROM_DISMISSIBLE_NOTIFICATIONS; + AppOpEnums.APP_OP_SYSTEM_EXEMPT_FROM_DISMISSIBLE_NOTIFICATIONS; /** * An app op for reading/writing health connect data. * * @hide */ - public static final int OP_READ_WRITE_HEALTH_DATA = AppProtoEnums.APP_OP_READ_WRITE_HEALTH_DATA; + public static final int OP_READ_WRITE_HEALTH_DATA = AppOpEnums.APP_OP_READ_WRITE_HEALTH_DATA; /** * Use foreground service with the type @@ -1441,7 +1436,7 @@ public class AppOpsManager { * @hide */ public static final int OP_FOREGROUND_SERVICE_SPECIAL_USE = - AppProtoEnums.APP_OP_FOREGROUND_SERVICE_SPECIAL_USE; + AppOpEnums.APP_OP_FOREGROUND_SERVICE_SPECIAL_USE; /** * Exempt an app from all power-related restrictions, including app standby and doze. @@ -1453,7 +1448,7 @@ public class AppOpsManager { * @hide */ public static final int OP_SYSTEM_EXEMPT_FROM_POWER_RESTRICTIONS = - AppProtoEnums.APP_OP_SYSTEM_EXEMPT_FROM_POWER_RESTRICTIONS; + AppOpEnums.APP_OP_SYSTEM_EXEMPT_FROM_POWER_RESTRICTIONS; /** * Prevent an app from being placed into hibernation. @@ -1463,7 +1458,7 @@ public class AppOpsManager { * @hide */ public static final int OP_SYSTEM_EXEMPT_FROM_HIBERNATION = - AppProtoEnums.APP_OP_SYSTEM_EXEMPT_FROM_HIBERNATION; + AppOpEnums.APP_OP_SYSTEM_EXEMPT_FROM_HIBERNATION; /** * Allows an application to start an activity while running in the background. @@ -1473,7 +1468,7 @@ public class AppOpsManager { * @hide */ public static final int OP_SYSTEM_EXEMPT_FROM_ACTIVITY_BG_START_RESTRICTION = - AppProtoEnums.APP_OP_SYSTEM_EXEMPT_FROM_ACTIVITY_BG_START_RESTRICTION; + AppOpEnums.APP_OP_SYSTEM_EXEMPT_FROM_ACTIVITY_BG_START_RESTRICTION; /** * Allows an application to capture bugreport directly without consent dialog when using the @@ -1482,33 +1477,31 @@ public class AppOpsManager { * @hide */ public static final int OP_CAPTURE_CONSENTLESS_BUGREPORT_ON_USERDEBUG_BUILD = - AppProtoEnums.APP_OP_CAPTURE_CONSENTLESS_BUGREPORT_ON_USERDEBUG_BUILD; + AppOpEnums.APP_OP_CAPTURE_CONSENTLESS_BUGREPORT_ON_USERDEBUG_BUILD; // App op deprecated/removed. - private static final int OP_DEPRECATED_2 = AppProtoEnums.APP_OP_BODY_SENSORS_WRIST_TEMPERATURE; + private static final int OP_DEPRECATED_2 = AppOpEnums.APP_OP_BODY_SENSORS_WRIST_TEMPERATURE; /** * Send an intent to launch instead of posting the notification to the status bar. * * @hide */ - public static final int OP_USE_FULL_SCREEN_INTENT = AppProtoEnums.APP_OP_USE_FULL_SCREEN_INTENT; + public static final int OP_USE_FULL_SCREEN_INTENT = AppOpEnums.APP_OP_USE_FULL_SCREEN_INTENT; /** * Hides camera indicator for sandboxed detection apps that directly access the service. * * @hide */ - public static final int OP_CAMERA_SANDBOXED = - AppProtoEnums.APP_OP_CAMERA_SANDBOXED; + public static final int OP_CAMERA_SANDBOXED = AppOpEnums.APP_OP_CAMERA_SANDBOXED; /** * Hides microphone indicator for sandboxed detection apps that directly access the service. * * @hide */ - public static final int OP_RECORD_AUDIO_SANDBOXED = - AppProtoEnums.APP_OP_RECORD_AUDIO_SANDBOXED; + public static final int OP_RECORD_AUDIO_SANDBOXED = AppOpEnums.APP_OP_RECORD_AUDIO_SANDBOXED; /** * Allows the assistant app to be voice-triggered by detected hotwords from a trusted detection @@ -1517,14 +1510,14 @@ public class AppOpsManager { * @hide */ public static final int OP_RECEIVE_SANDBOX_TRIGGER_AUDIO = - AppProtoEnums.APP_OP_RECEIVE_SANDBOX_TRIGGER_AUDIO; + AppOpEnums.APP_OP_RECEIVE_SANDBOX_TRIGGER_AUDIO; /** * This op has been deprecated. * */ private static final int OP_DEPRECATED_3 = - AppProtoEnums.APP_OP_RECEIVE_SANDBOXED_DETECTION_TRAINING_DATA; + AppOpEnums.APP_OP_RECEIVE_SANDBOXED_DETECTION_TRAINING_DATA; /** * Creation of an overlay using accessibility services @@ -1532,20 +1525,20 @@ public class AppOpsManager { * @hide */ public static final int OP_CREATE_ACCESSIBILITY_OVERLAY = - AppProtoEnums.APP_OP_CREATE_ACCESSIBILITY_OVERLAY; + AppOpEnums.APP_OP_CREATE_ACCESSIBILITY_OVERLAY; /** * Indicate that the user has enabled or disabled mobile data * @hide */ public static final int OP_ENABLE_MOBILE_DATA_BY_USER = - AppProtoEnums.APP_OP_ENABLE_MOBILE_DATA_BY_USER; + AppOpEnums.APP_OP_ENABLE_MOBILE_DATA_BY_USER; /** * See {@link #OPSTR_MEDIA_ROUTING_CONTROL}. * @hide */ - public static final int OP_MEDIA_ROUTING_CONTROL = AppProtoEnums.APP_OP_MEDIA_ROUTING_CONTROL; + public static final int OP_MEDIA_ROUTING_CONTROL = AppOpEnums.APP_OP_MEDIA_ROUTING_CONTROL; /** * Op code for use by tests to avoid interfering history logs that the wider system might @@ -1553,7 +1546,7 @@ public class AppOpsManager { * * @hide */ - public static final int OP_RESERVED_FOR_TESTING = AppProtoEnums.APP_OP_RESERVED_FOR_TESTING; + public static final int OP_RESERVED_FOR_TESTING = AppOpEnums.APP_OP_RESERVED_FOR_TESTING; /** * Rapid clearing of notifications by a notification listener @@ -1562,28 +1555,28 @@ public class AppOpsManager { */ // See b/289080543 for more details public static final int OP_RAPID_CLEAR_NOTIFICATIONS_BY_LISTENER = - AppProtoEnums.APP_OP_RAPID_CLEAR_NOTIFICATIONS_BY_LISTENER; + AppOpEnums.APP_OP_RAPID_CLEAR_NOTIFICATIONS_BY_LISTENER; /** * See {@link #OPSTR_READ_SYSTEM_GRAMMATICAL_GENDER}. * @hide */ public static final int OP_READ_SYSTEM_GRAMMATICAL_GENDER = - AppProtoEnums.APP_OP_READ_SYSTEM_GRAMMATICAL_GENDER; + AppOpEnums.APP_OP_READ_SYSTEM_GRAMMATICAL_GENDER; /** * This app has been removed.. * * @hide */ - private static final int OP_DEPRECATED_4 = AppProtoEnums.APP_OP_RUN_BACKUP_JOBS; + private static final int OP_DEPRECATED_4 = AppOpEnums.APP_OP_RUN_BACKUP_JOBS; /** * Whether the app has enabled to receive the icon overlay for fetching archived apps. * * @hide */ - public static final int OP_ARCHIVE_ICON_OVERLAY = AppProtoEnums.APP_OP_ARCHIVE_ICON_OVERLAY; + public static final int OP_ARCHIVE_ICON_OVERLAY = AppOpEnums.APP_OP_ARCHIVE_ICON_OVERLAY; /** * Whether the app has enabled compatibility support for unarchival. @@ -1591,7 +1584,7 @@ public class AppOpsManager { * @hide */ public static final int OP_UNARCHIVAL_CONFIRMATION = - AppProtoEnums.APP_OP_UNARCHIVAL_CONFIRMATION; + AppOpEnums.APP_OP_UNARCHIVAL_CONFIRMATION; /** * Allows an app to access location without the traditional location permissions and while the @@ -1603,7 +1596,7 @@ public class AppOpsManager { * * @hide */ - public static final int OP_EMERGENCY_LOCATION = AppProtoEnums.APP_OP_EMERGENCY_LOCATION; + public static final int OP_EMERGENCY_LOCATION = AppOpEnums.APP_OP_EMERGENCY_LOCATION; /** * Allows apps with a NotificationListenerService to receive notifications with sensitive @@ -1613,17 +1606,27 @@ public class AppOpsManager { * @hide */ public static final int OP_RECEIVE_SENSITIVE_NOTIFICATIONS = - AppProtoEnums.APP_OP_RECEIVE_SENSITIVE_NOTIFICATIONS; + AppOpEnums.APP_OP_RECEIVE_SENSITIVE_NOTIFICATIONS; /** @hide Access to read heart rate sensor. */ - public static final int OP_READ_HEART_RATE = AppProtoEnums.APP_OP_READ_HEART_RATE; + public static final int OP_READ_HEART_RATE = AppOpEnums.APP_OP_READ_HEART_RATE; /** @hide Access to read skin temperature. */ - public static final int OP_READ_SKIN_TEMPERATURE = AppProtoEnums.APP_OP_READ_SKIN_TEMPERATURE; + public static final int OP_READ_SKIN_TEMPERATURE = AppOpEnums.APP_OP_READ_SKIN_TEMPERATURE; + + /** + * Allows an app to range with nearby devices using any ranging technology available. + * + * @hide + */ + public static final int OP_RANGING = AppOpEnums.APP_OP_RANGING; + + /** @hide Access to read oxygen saturation. */ + public static final int OP_READ_OXYGEN_SATURATION = AppOpEnums.APP_OP_READ_OXYGEN_SATURATION; /** @hide */ @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553) - public static final int _NUM_OP = 151; + public static final int _NUM_OP = 153; /** * All app ops represented as strings. @@ -1778,6 +1781,8 @@ public class AppOpsManager { OPSTR_RECEIVE_SENSITIVE_NOTIFICATIONS, OPSTR_READ_HEART_RATE, OPSTR_READ_SKIN_TEMPERATURE, + OPSTR_RANGING, + OPSTR_READ_OXYGEN_SATURATION, }) public @interface AppOpString {} @@ -2520,11 +2525,21 @@ public class AppOpsManager { @FlaggedApi(Flags.FLAG_REPLACE_BODY_SENSOR_PERMISSION_ENABLED) public static final String OPSTR_READ_HEART_RATE = "android:read_heart_rate"; + /** @hide Access to read oxygen saturation. */ + @SystemApi + @FlaggedApi(Flags.FLAG_PLATFORM_OXYGEN_SATURATION_ENABLED) + public static final String OPSTR_READ_OXYGEN_SATURATION = "android:read_oxygen_saturation"; + /** @hide Access to read skin temperature. */ @SystemApi @FlaggedApi(Flags.FLAG_PLATFORM_SKIN_TEMPERATURE_ENABLED) public static final String OPSTR_READ_SKIN_TEMPERATURE = "android:read_skin_temperature"; + /** @hide Access to ranging */ + @SystemApi + @FlaggedApi(Flags.FLAG_RANGING_PERMISSION_ENABLED) + public static final String OPSTR_RANGING = "android:ranging"; + /** {@link #sAppOpsToNote} not initialized yet for this op */ private static final byte SHOULD_COLLECT_NOTE_OP_NOT_INITIALIZED = 0; /** Should not collect noting of this app-op in {@link #sAppOpsToNote} */ @@ -2596,11 +2611,13 @@ public class AppOpsManager { OP_BLUETOOTH_ADVERTISE, OP_UWB_RANGING, OP_NEARBY_WIFI_DEVICES, + Flags.rangingPermissionEnabled() ? OP_RANGING : OP_NONE, // Notifications OP_POST_NOTIFICATION, // Health Flags.replaceBodySensorPermissionEnabled() ? OP_READ_HEART_RATE : OP_NONE, Flags.platformSkinTemperatureEnabled() ? OP_READ_SKIN_TEMPERATURE : OP_NONE, + Flags.platformOxygenSaturationEnabled() ? OP_READ_OXYGEN_SATURATION : OP_NONE, }; /** @@ -3118,6 +3135,15 @@ public class AppOpsManager { Flags.platformSkinTemperatureEnabled() ? HealthPermissions.READ_SKIN_TEMPERATURE : null) .setDefaultMode(AppOpsManager.MODE_ALLOWED).build(), + new AppOpInfo.Builder(OP_RANGING, OPSTR_RANGING, "RANGING") + .setPermission(Flags.rangingPermissionEnabled()? + Manifest.permission.RANGING : null) + .setDefaultMode(AppOpsManager.MODE_ALLOWED).build(), + new AppOpInfo.Builder(OP_READ_OXYGEN_SATURATION, OPSTR_READ_OXYGEN_SATURATION, + "READ_OXYGEN_SATURATION").setPermission( + Flags.platformOxygenSaturationEnabled() + ? HealthPermissions.READ_OXYGEN_SATURATION : null) + .setDefaultMode(AppOpsManager.MODE_ALLOWED).build(), }; // The number of longs needed to form a full bitmask of app ops @@ -7807,6 +7833,116 @@ public class AppOpsManager { } } + private static final String APP_OP_MODE_CACHING_API = "getAppOpMode"; + private static final String APP_OP_MODE_CACHING_NAME = "appOpModeCache"; + private static final int APP_OP_MODE_CACHING_SIZE = 2048; + + private static final IpcDataCache.QueryHandler sGetAppOpModeQuery = + new IpcDataCache.QueryHandler<>() { + @Override + public Integer apply(AppOpModeQuery query) { + IAppOpsService service = getService(); + try { + return service.checkOperationRawForDevice(query.op, query.uid, + query.packageName, query.attributionTag, query.virtualDeviceId); + } catch (RemoteException e) { + throw e.rethrowFromSystemServer(); + } + } + + @Override + public boolean shouldBypassCache(@NonNull AppOpModeQuery query) { + // If the flag to enable the new caching behavior is off, bypass the cache. + return !Flags.appopModeCachingEnabled(); + } + }; + + // A LRU cache on binder clients that caches AppOp mode by uid, packageName, virtualDeviceId + // and attributionTag. + private static final IpcDataCache sAppOpModeCache = + new IpcDataCache<>(APP_OP_MODE_CACHING_SIZE, IpcDataCache.MODULE_SYSTEM, + APP_OP_MODE_CACHING_API, APP_OP_MODE_CACHING_NAME, sGetAppOpModeQuery); + + // Ops that we don't want to cache due to: + // 1) Discrepancy of attributionTag support in checkOp and noteOp that determines if a package + // can bypass user restriction of an op: b/240617242. COARSE_LOCATION and FINE_LOCATION are + // the only two ops that are impacted. + private static final SparseBooleanArray OPS_WITHOUT_CACHING = new SparseBooleanArray(); + static { + OPS_WITHOUT_CACHING.put(OP_COARSE_LOCATION, true); + OPS_WITHOUT_CACHING.put(OP_FINE_LOCATION, true); + } + + private static boolean isAppOpModeCachingEnabled(int opCode) { + if (!Flags.appopModeCachingEnabled()) { + return false; + } + return !OPS_WITHOUT_CACHING.get(opCode, false); + } + + /** + * @hide + */ + public static void invalidateAppOpModeCache() { + if (Flags.appopModeCachingEnabled()) { + IpcDataCache.invalidateCache(IpcDataCache.MODULE_SYSTEM, APP_OP_MODE_CACHING_API); + } + } + + /** + * Bypass AppOpModeCache in the local process + * + * @hide + */ + public static void disableAppOpModeCache() { + if (Flags.appopModeCachingEnabled()) { + sAppOpModeCache.disableLocal(); + } + } + + private static final class AppOpModeQuery { + final int op; + final int uid; + final String packageName; + final int virtualDeviceId; + final String attributionTag; + final String methodName; + + AppOpModeQuery(int op, int uid, @Nullable String packageName, int virtualDeviceId, + @Nullable String attributionTag, @Nullable String methodName) { + this.op = op; + this.uid = uid; + this.packageName = packageName; + this.virtualDeviceId = virtualDeviceId; + this.attributionTag = attributionTag; + this.methodName = methodName; + } + + @Override + public String toString() { + return TextUtils.formatSimple("AppOpModeQuery(op=%d, uid=%d, packageName=%s, " + + "virtualDeviceId=%d, attributionTag=%s, methodName=%s", op, uid, + packageName, virtualDeviceId, attributionTag, methodName); + } + + @Override + public int hashCode() { + return Objects.hash(op, uid, packageName, virtualDeviceId, attributionTag); + } + + @Override + public boolean equals(@Nullable Object o) { + if (this == o) return true; + if (o == null) return false; + if (this.getClass() != o.getClass()) return false; + + AppOpModeQuery other = (AppOpModeQuery) o; + return op == other.op && uid == other.uid && Objects.equals(packageName, + other.packageName) && virtualDeviceId == other.virtualDeviceId + && Objects.equals(attributionTag, other.attributionTag); + } + } + AppOpsManager(Context context, IAppOpsService service) { mContext = context; mService = service; @@ -8861,12 +8997,16 @@ public class AppOpsManager { private int unsafeCheckOpRawNoThrow(int op, int uid, @NonNull String packageName, int virtualDeviceId) { try { - if (virtualDeviceId == Context.DEVICE_ID_DEFAULT) { - return mService.checkOperationRaw(op, uid, packageName, null); + int mode; + if (isAppOpModeCachingEnabled(op)) { + mode = sAppOpModeCache.query( + new AppOpModeQuery(op, uid, packageName, virtualDeviceId, null, + "unsafeCheckOpRawNoThrow")); } else { - return mService.checkOperationRawForDevice( + mode = mService.checkOperationRawForDevice( op, uid, packageName, null, virtualDeviceId); } + return mode; } catch (RemoteException e) { throw e.rethrowFromSystemServer(); } @@ -9051,7 +9191,7 @@ public class AppOpsManager { SyncNotedAppOp syncOp; if (virtualDeviceId == Context.DEVICE_ID_DEFAULT) { syncOp = mService.noteOperation(op, uid, packageName, attributionTag, - collectionMode == COLLECT_ASYNC, message, shouldCollectMessage); + collectionMode == COLLECT_ASYNC, message, shouldCollectMessage); } else { syncOp = mService.noteOperationForDevice(op, uid, packageName, attributionTag, virtualDeviceId, collectionMode == COLLECT_ASYNC, message, @@ -9294,8 +9434,21 @@ public class AppOpsManager { @UnsupportedAppUsage public int checkOp(int op, int uid, String packageName) { try { - int mode = mService.checkOperationForDevice(op, uid, packageName, - Context.DEVICE_ID_DEFAULT); + 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)); } @@ -9334,13 +9487,19 @@ public class AppOpsManager { private int checkOpNoThrow(int op, int uid, String packageName, int virtualDeviceId) { try { int mode; - if (virtualDeviceId == Context.DEVICE_ID_DEFAULT) { - mode = mService.checkOperation(op, uid, packageName); + if (isAppOpModeCachingEnabled(op)) { + mode = sAppOpModeCache.query( + new AppOpModeQuery(op, uid, packageName, virtualDeviceId, null, + "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); + } } else { mode = mService.checkOperationForDevice(op, uid, packageName, virtualDeviceId); } - - return mode == AppOpsManager.MODE_FOREGROUND ? AppOpsManager.MODE_ALLOWED : mode; + return mode; } catch (RemoteException e) { throw e.rethrowFromSystemServer(); } diff --git a/core/java/android/app/ContextImpl.java b/core/java/android/app/ContextImpl.java index 2cf718ef364fa9d4bb365c42c45542a9db806690..3ae60d71facdc37c10c265077c9647fbdf3299e6 100644 --- a/core/java/android/app/ContextImpl.java +++ b/core/java/android/app/ContextImpl.java @@ -1167,6 +1167,7 @@ class ContextImpl extends Context { @Override public void startActivityAsUser(Intent intent, Bundle options, UserHandle user) { try { + intent.collectExtraIntentKeys(); ActivityTaskManager.getService().startActivityAsUser( mMainThread.getApplicationThread(), getOpPackageName(), getAttributionTag(), intent, intent.resolveTypeIfNeeded(getContentResolver()), diff --git a/core/java/android/app/ForegroundServiceTypePolicy.java b/core/java/android/app/ForegroundServiceTypePolicy.java index d1e517bbd03c5690d0887621aeeb7d2768c59a6e..16444dc5adde877d7b257053b579a9e7d0b42285 100644 --- a/core/java/android/app/ForegroundServiceTypePolicy.java +++ b/core/java/android/app/ForegroundServiceTypePolicy.java @@ -398,6 +398,7 @@ public abstract class ForegroundServiceTypePolicy { new RegularPermission(Manifest.permission.NFC), new RegularPermission(Manifest.permission.TRANSMIT_IR), new RegularPermission(Manifest.permission.UWB_RANGING), + new RegularPermission(Manifest.permission.RANGING), new UsbDevicePermission(), new UsbAccessoryPermission(), }, false), diff --git a/core/java/android/app/INotificationManager.aidl b/core/java/android/app/INotificationManager.aidl index a97fa18a35999ff119775a401ad85312cad3ac3a..0654ac2f33ceb58fc01d6dcfb18b1d1209e8f962 100644 --- a/core/java/android/app/INotificationManager.aidl +++ b/core/java/android/app/INotificationManager.aidl @@ -267,4 +267,7 @@ interface INotificationManager void setAdjustmentTypeSupportedState(in INotificationListener token, String key, boolean supported); List getUnsupportedAdjustmentTypes(); + + int[] getAllowedAdjustmentKeyTypes(); + void setAssistantAdjustmentKeyTypeState(int type, boolean enabled); } diff --git a/core/java/android/app/Notification.java b/core/java/android/app/Notification.java index c6c0395d1b93225459472c61475f3bf0f818f7de..0381ee0e25ac7dd1d3c72636250624284b215283 100644 --- a/core/java/android/app/Notification.java +++ b/core/java/android/app/Notification.java @@ -155,7 +155,7 @@ public class Notification implements Parcelable FOREGROUND_SERVICE_IMMEDIATE, FOREGROUND_SERVICE_DEFERRED }) - public @interface ServiceNotificationPolicy {}; + public @interface ServiceNotificationPolicy {} /** * If the Notification associated with starting a foreground service has been @@ -1754,10 +1754,6 @@ public class Notification implements Parcelable private Icon mSmallIcon; @UnsupportedAppUsage private Icon mLargeIcon; - private Icon mAppIcon; - - /** Cache for whether the notification was posted by a headless system app. */ - private Boolean mBelongsToHeadlessSystemApp = null; @UnsupportedAppUsage private String mChannelId; @@ -3246,86 +3242,6 @@ public class Notification implements Parcelable && hasPromotableStyle(); } - /** - * Whether this notification was posted by a headless system app. - * - * If we don't have enough information to figure this out, this will return false. Therefore, - * false negatives are possible, but false positives should not be. - * - * @hide - */ - public boolean belongsToHeadlessSystemApp(Context context) { - Trace.beginSection("Notification#belongsToHeadlessSystemApp"); - - try { - if (mBelongsToHeadlessSystemApp != null) { - return mBelongsToHeadlessSystemApp; - } - - if (context == null) { - // Without a valid context, we don't know exactly. Let's assume it doesn't belong to - // a system app, but not cache the value. - return false; - } - - ApplicationInfo info = getApplicationInfo(context); - if (info != null) { - if ((info.flags & ApplicationInfo.FLAG_SYSTEM) == 0) { - // It's not a system app at all. - mBelongsToHeadlessSystemApp = false; - } else { - // If there's no launch intent, it's probably a headless app. - final PackageManager pm = context.getPackageManager(); - mBelongsToHeadlessSystemApp = pm.getLaunchIntentForPackage(info.packageName) - == null; - } - } else { - // If for some reason we don't have the app info, we don't know; best assume it's - // not a system app. - return false; - } - return mBelongsToHeadlessSystemApp; - } finally { - Trace.endSection(); - } - } - - /** - * Get the resource ID of the app icon from application info. - * @hide - */ - public int getHeaderAppIconRes(Context context) { - ApplicationInfo info = getApplicationInfo(context); - if (info != null) { - return info.icon; - } - return 0; - } - - /** - * Load the app icon drawable from the package manager. This could result in a binder call. - * @hide - */ - public Drawable loadHeaderAppIcon(Context context) { - Trace.beginSection("Notification#loadHeaderAppIcon"); - - try { - if (context == null) { - Log.e(TAG, "Cannot load the app icon drawable with a null context"); - return null; - } - final PackageManager pm = context.getPackageManager(); - ApplicationInfo info = getApplicationInfo(context); - if (info == null) { - Log.e(TAG, "Cannot load the app icon drawable: no application info"); - return null; - } - return pm.getApplicationIcon(info); - } finally { - Trace.endSection(); - } - } - /** * Fetch the application info from the notification, or the context if that isn't available. */ @@ -4360,55 +4276,6 @@ public class Notification implements Parcelable mSmallIcon = icon; } - /** - * The colored app icon that can replace the small icon in the notification starting in V. - * - * Before using this value, you should first check whether it's actually being used by the - * notification by calling {@link Notification#shouldUseAppIcon()}. - * - * @hide - */ - public Icon getAppIcon() { - if (mAppIcon != null) { - return mAppIcon; - } - // If the app icon hasn't been loaded yet, check if we can load it without a context. - if (extras.containsKey(EXTRA_BUILDER_APPLICATION_INFO)) { - final ApplicationInfo info = extras.getParcelable( - EXTRA_BUILDER_APPLICATION_INFO, - ApplicationInfo.class); - if (info != null) { - int appIconRes = info.icon; - if (appIconRes == 0) { - Log.w(TAG, "Failed to get the app icon: no icon in application info"); - return null; - } - mAppIcon = Icon.createWithResource(info.packageName, appIconRes); - return mAppIcon; - } else { - Log.e(TAG, "Failed to get the app icon: " - + "there's an EXTRA_BUILDER_APPLICATION_INFO in extras but it's null"); - } - } else { - Log.w(TAG, "Failed to get the app icon: no application info in extras"); - } - return null; - } - - /** - * Whether the notification is using the app icon instead of the small icon. - * @hide - */ - public boolean shouldUseAppIcon() { - if (Flags.notificationsUseAppIconInRow()) { - if (belongsToHeadlessSystemApp(/* context = */ null)) { - return false; - } - return getAppIcon() != null; - } - return false; - } - /** * The large icon shown in this notification's content view. * @see Builder#getLargeIcon() @@ -4566,19 +4433,6 @@ public class Notification implements Parcelable private static final boolean USE_ONLY_TITLE_IN_LOW_PRIORITY_SUMMARY = SystemProperties.getBoolean("notifications.only_title", true); - /** - * The lightness difference that has to be added to the primary text color to obtain the - * secondary text color when the background is light. - */ - private static final int LIGHTNESS_TEXT_DIFFERENCE_LIGHT = 20; - - /** - * The lightness difference that has to be added to the primary text color to obtain the - * secondary text color when the background is dark. - * A bit less then the above value, since it looks better on dark backgrounds. - */ - private static final int LIGHTNESS_TEXT_DIFFERENCE_DARK = -10; - private Context mContext; private Notification mN; private Bundle mUserExtras = new Bundle(); @@ -6451,36 +6305,12 @@ public class Notification implements Parcelable } private void bindSmallIcon(RemoteViews contentView, StandardTemplateParams p) { - if (Flags.notificationsUseAppIcon()) { - // Override small icon with app icon - mN.mSmallIcon = Icon.createWithResource(mContext, - mN.getHeaderAppIconRes(mContext)); - } else if (mN.mSmallIcon == null && mN.icon != 0) { + if (mN.mSmallIcon == null && mN.icon != 0) { mN.mSmallIcon = Icon.createWithResource(mContext, mN.icon); } - - boolean usingAppIcon = false; - if (Flags.notificationsUseAppIconInRow() && !mN.belongsToHeadlessSystemApp(mContext)) { - // Use the app icon in the view - int appIconRes = mN.getHeaderAppIconRes(mContext); - if (appIconRes != 0) { - mN.mAppIcon = Icon.createWithResource(mContext, appIconRes); - contentView.setImageViewIcon(R.id.icon, mN.mAppIcon); - contentView.setBoolean(R.id.icon, "setShouldShowAppIcon", true); - usingAppIcon = true; - } else { - Log.w(TAG, "bindSmallIcon: could not get the app icon"); - } - } - if (!usingAppIcon) { - contentView.setImageViewIcon(R.id.icon, mN.mSmallIcon); - } + contentView.setImageViewIcon(R.id.icon, mN.mSmallIcon); contentView.setInt(R.id.icon, "setImageLevel", mN.iconLevel); - - // Don't change color if we're using the app icon. - if (!Flags.notificationsUseAppIcon() && !usingAppIcon) { - processSmallIconColor(mN.mSmallIcon, contentView, p); - } + processSmallIconColor(mN.mSmallIcon, contentView, p); } /** diff --git a/core/java/android/app/NotificationManager.java b/core/java/android/app/NotificationManager.java index 768b70c286327634ec8c3dbd8122a2fc8b73432c..c49b02210dd45e575de4f02c87d9c086e36eaebe 100644 --- a/core/java/android/app/NotificationManager.java +++ b/core/java/android/app/NotificationManager.java @@ -1845,6 +1845,20 @@ public class NotificationManager { } } + /** + * @hide + */ + @TestApi + @FlaggedApi(android.service.notification.Flags.FLAG_NOTIFICATION_CLASSIFICATION) + public void setAssistantAdjustmentKeyTypeState(@Adjustment.Types int type, boolean enabled) { + INotificationManager service = getService(); + try { + service.setAssistantAdjustmentKeyTypeState(type, 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 a39cf84a4ebed43804b81becbe5b1731a4244a6e..1dc774285a327bd11cf4d11d7b8162391c85062a 100644 --- a/core/java/android/app/PropertyInvalidatedCache.java +++ b/core/java/android/app/PropertyInvalidatedCache.java @@ -17,6 +17,7 @@ package android.app; import static android.text.TextUtils.formatSimple; +import static com.android.internal.util.Preconditions.checkArgumentPositive; import android.annotation.NonNull; import android.annotation.Nullable; @@ -31,7 +32,10 @@ import android.os.Process; import android.os.SystemClock; import android.os.SystemProperties; import android.util.ArrayMap; +import android.util.ArraySet; import android.util.Log; +import android.util.SparseArray; +import android.util.SparseBooleanArray; import com.android.internal.annotations.GuardedBy; import com.android.internal.annotations.VisibleForTesting; @@ -40,6 +44,7 @@ import com.android.internal.os.BackgroundThread; import dalvik.annotation.optimization.CriticalNative; import dalvik.annotation.optimization.FastNative; +import dalvik.annotation.optimization.NeverCompile; import java.io.ByteArrayOutputStream; import java.io.FileOutputStream; @@ -90,9 +95,6 @@ public class PropertyInvalidatedCache { * caching on behalf of other processes. */ public boolean shouldBypassCache(@NonNull Q query) { - if(android.multiuser.Flags.propertyInvalidatedCacheBypassMismatchedUids()) { - return Binder.getCallingUid() != Process.myUid(); - } return false; } }; @@ -200,6 +202,23 @@ public class PropertyInvalidatedCache { return CACHE_KEY_PREFIX + "." + module + "." + new String(suffix); } + /** + * The list of known and legal modules. The list is not sorted. + */ + private static final String[] sValidModule = { + MODULE_SYSTEM, MODULE_BLUETOOTH, MODULE_TELEPHONY, MODULE_TEST, + }; + + /** + * Verify that the module string is in the legal list. Throw if it is not. + */ + private static void throwIfInvalidModule(@NonNull String name) { + for (int i = 0; i < sValidModule.length; i++) { + if (sValidModule[i].equals(name)) return; + } + throw new IllegalArgumentException("invalid module: " + name); + } + /** * All legal keys start with one of the following strings. */ @@ -254,8 +273,11 @@ public class PropertyInvalidatedCache { // written to global store. private static final int NONCE_BYPASS = 3; + // The largest reserved nonce value. Update this whenever a reserved nonce is added. + private static final int MAX_RESERVED_NONCE = NONCE_BYPASS; + private static boolean isReservedNonce(long n) { - return n >= NONCE_UNSET && n <= NONCE_BYPASS; + return n >= NONCE_UNSET && n <= MAX_RESERVED_NONCE; } /** @@ -293,7 +315,7 @@ public class PropertyInvalidatedCache { private long mMisses = 0; @GuardedBy("mLock") - private long[] mSkips = new long[]{ 0, 0, 0, 0 }; + private long[] mSkips = new long[MAX_RESERVED_NONCE + 1]; @GuardedBy("mLock") private long mMissOverflow = 0; @@ -370,8 +392,213 @@ public class PropertyInvalidatedCache { } } + /** + * An array of hash maps, indexed by calling UID. The class behaves a bit like a hash map + * except that it uses the calling UID internally. + */ + private class CacheMap { + + // Create a new map for a UID, using the parent's configuration for max size. + private LinkedHashMap createMap() { + return new LinkedHashMap( + 2 /* start small */, + 0.75f /* default load factor */, + true /* LRU access order */) { + @GuardedBy("mLock") + @Override + protected boolean removeEldestEntry(Map.Entry eldest) { + final int size = size(); + if (size > mHighWaterMark) { + mHighWaterMark = size; + } + if (size > mMaxEntries) { + mMissOverflow++; + return true; + } + return false; + } + }; + } + + // An array of maps, indexed by UID. + private final SparseArray> mCache = new SparseArray<>(); + + // If true, isolate the hash entries by calling UID. If this is false, allow the cache + // entries to be combined in a single hash map. + private final boolean mIsolated; + + // Collect statistics. + private final boolean mStatistics; + + // An array of booleans to indicate if a UID has been involved in a map access. A value + // exists for every UID that was ever involved during cache access. This is updated only + // if statistics are being collected. + private final SparseBooleanArray mUidSeen; + + // A hash map that ignores the UID. This is used in look-aside fashion just for hit/miss + // statistics. This is updated only if statistics are being collected. + private final ArraySet mShadowCache; + + // Shadow statistics. Only hits and misses need to be recorded. These are updated only + // if statistics are being collected. The "SelfHits" records hits when the UID is the + // process uid. + private int mShadowHits; + private int mShadowMisses; + private int mShadowSelfHits; + + // The process UID. + private final int mSelfUid; + + // True in test mode. In test mode, the cache uses Binder.getWorkSource() as the UID. + private final boolean mTestMode; + + /** + * Create a CacheMap. UID isolation is enabled if the input parameter is true and if the + * isolation feature is enabled. + */ + CacheMap(boolean isolate, boolean testMode) { + mIsolated = Flags.picIsolateCacheByUid() && isolate; + mStatistics = Flags.picIsolatedCacheStatistics() && mIsolated; + if (mStatistics) { + mUidSeen = new SparseBooleanArray(); + mShadowCache = new ArraySet<>(); + } else { + mUidSeen = null; + mShadowCache = null; + } + mSelfUid = Process.myUid(); + mTestMode = testMode; + } + + // Return the UID for this cache invocation. If uid isolation is disabled, the value of 0 + // is returned, which effectively places all entries in a single hash map. + private int callerUid() { + if (!mIsolated) { + return 0; + } else if (mTestMode) { + return Binder.getCallingWorkSourceUid(); + } else { + return Binder.getCallingUid(); + } + } + + /** + * Lookup an entry in the cache. + */ + Result get(Query query) { + final int uid = callerUid(); + + // Shadow statistics + if (mStatistics) { + if (mShadowCache.contains(query)) { + mShadowHits++; + if (uid == mSelfUid) { + mShadowSelfHits++; + } + } else { + mShadowMisses++; + } + } + + var map = mCache.get(uid); + if (map != null) { + return map.get(query); + } else { + return null; + } + } + + /** + * Remove an entry from the cache. + */ + void remove(Query query) { + final int uid = callerUid(); + if (mStatistics) { + mShadowCache.remove(query); + } + + var map = mCache.get(uid); + if (map != null) { + map.remove(query); + } + } + + /** + * Record an entry in the cache. + */ + void put(Query query, Result result) { + final int uid = callerUid(); + if (mStatistics) { + mShadowCache.add(query); + mUidSeen.put(uid, true); + } + + var map = mCache.get(uid); + if (map == null) { + map = createMap(); + mCache.put(uid, map); + } + map.put(query, result); + } + + /** + * Return the number of entries in the cache. + */ + int size() { + int total = 0; + for (int i = 0; i < mCache.size(); i++) { + var map = mCache.valueAt(i); + total += map.size(); + } + return total; + } + + /** + * Clear the entries in the cache. Update the shadow statistics. + */ + void clear() { + if (mStatistics) { + mShadowCache.clear(); + } + + mCache.clear(); + } + + // Dump basic statistics, if any are collected. Do nothing if statistics are not enabled. + void dump(PrintWriter pw) { + if (mStatistics) { + pw.println(formatSimple(" ShadowHits: %d, ShadowMisses: %d, ShadowSize: %d", + mShadowHits, mShadowMisses, mShadowCache.size())); + pw.println(formatSimple(" ShadowUids: %d, SelfUid: %d", + mUidSeen.size(), mShadowSelfHits)); + } + } + + // Dump detailed statistics + void dumpDetailed(PrintWriter pw) { + for (int i = 0; i < mCache.size(); i++) { + int uid = mCache.keyAt(i); + var map = mCache.valueAt(i); + + Set> cacheEntries = map.entrySet(); + if (cacheEntries.size() == 0) { + break; + } + + pw.println(" Contents:"); + pw.println(formatSimple(" Uid: %d\n", uid)); + for (Map.Entry entry : cacheEntries) { + String key = Objects.toString(entry.getKey()); + String value = Objects.toString(entry.getValue()); + + pw.println(formatSimple(" Key: %s\n Value: %s\n", key, value)); + } + } + } + } + @GuardedBy("mLock") - private final LinkedHashMap mCache; + private final CacheMap mCache; /** * The nonce handler for this cache. @@ -695,12 +922,10 @@ public class PropertyInvalidatedCache { // The shared memory. private volatile NonceStore mStore; - // The index of the nonce in shared memory. + // The index of the nonce in shared memory. This changes from INVALID only when the local + // object is completely initialized. private volatile int mHandle = NonceStore.INVALID_NONCE_INDEX; - // True if the string has been stored, ever. - private volatile boolean mRecorded = false; - // A short name that is saved in shared memory. This is the portion of the property name // that follows the prefix. private final String mShortName; @@ -714,48 +939,63 @@ public class PropertyInvalidatedCache { } } + // Initialize the mStore and mHandle variables. This function does nothing if the + // variables are already initialized. Synchronization ensures that initialization happens + // no more than once. The function returns the new value of mHandle. + // + // If the "update" boolean is true, then the property is registered with the nonce store + // before the associated handle is fetched. + private int initialize(boolean update) { + synchronized (mLock) { + int handle = mHandle; + if (handle == NonceStore.INVALID_NONCE_INDEX) { + if (mStore == null) { + mStore = NonceStore.getInstance(); + if (mStore == null) { + return NonceStore.INVALID_NONCE_INDEX; + } + } + if (update) { + mStore.storeName(mShortName); + } + handle = mStore.getHandleForName(mShortName); + if (handle == NonceStore.INVALID_NONCE_INDEX) { + return NonceStore.INVALID_NONCE_INDEX; + } + // The handle must be valid. + mHandle = handle; + } + return handle; + } + } + // Fetch the nonce from shared memory. If the shared memory is not available, return // UNSET. If the shared memory is available but the nonce name is not known (it may not // have been invalidated by the server yet), return UNSET. @Override long getNonceInternal() { - if (mHandle == NonceStore.INVALID_NONCE_INDEX) { - if (mStore == null) { - mStore = NonceStore.getInstance(); - if (mStore == null) { - return NONCE_UNSET; - } - } - mHandle = mStore.getHandleForName(mShortName); - if (mHandle == NonceStore.INVALID_NONCE_INDEX) { + int handle = mHandle; + if (handle == NonceStore.INVALID_NONCE_INDEX) { + handle = initialize(false); + if (handle == NonceStore.INVALID_NONCE_INDEX) { return NONCE_UNSET; } } - return mStore.getNonce(mHandle); + return mStore.getNonce(handle); } - // Set the nonce in shared mmory. If the shared memory is not available, throw an - // exception. Otherwise, if the nonce name has never been recorded, record it now and - // fetch the handle for the name. If the handle cannot be created, throw an exception. + // Set the nonce in shared memory. If the shared memory is not available or if the nonce + // cannot be registered in shared memory, throw an exception. @Override void setNonceInternal(long value) { - if (mHandle == NonceStore.INVALID_NONCE_INDEX || !mRecorded) { - if (mStore == null) { - mStore = NonceStore.getInstance(); - if (mStore == null) { - throw new IllegalStateException("setNonce: shared memory not ready"); - } - } - // Always store the name before fetching the handle. storeName() is idempotent - // but does take a little time, so this code calls it just once. - mStore.storeName(mShortName); - mRecorded = true; - mHandle = mStore.getHandleForName(mShortName); - if (mHandle == NonceStore.INVALID_NONCE_INDEX) { - throw new IllegalStateException("setNonce: shared memory store failed"); + int handle = mHandle; + if (handle == NonceStore.INVALID_NONCE_INDEX) { + handle = initialize(true); + if (handle == NonceStore.INVALID_NONCE_INDEX) { + throw new IllegalStateException("unable to assign nonce handle: " + mName); } } - mStore.setNonce(mHandle, value); + mStore.setNonce(handle, value); } } @@ -853,6 +1093,87 @@ public class PropertyInvalidatedCache { return h; } + /** + * A public argument builder to configure cache behavior. The root instance requires a + * module; this is immutable. New instances are created with member methods. It is important + * to note that the member methods create new instances: they do not modify 'this'. The api + * is allowed to be null in the record constructor to facility reuse of Args instances. + * @hide + */ + public static record Args(@NonNull String mModule, @Nullable String mApi, + int mMaxEntries, boolean mIsolateUids, boolean mTestMode) { + + // Validation: the module must be one of the known module strings and the maxEntries must + // be positive. + public Args { + throwIfInvalidModule(mModule); + checkArgumentPositive(mMaxEntries, "max cache size must be positive"); + } + + // The base constructor must include the module. Modules do not change in a source file, + // so even if the Args is reused, the module will not/should not change. The api is null, + // which is not legal, but there is no reasonable default. Clients must call the api + // method to set the field properly. + public Args(@NonNull String module) { + this(module, + null, // api + 32, // maxEntries + true, // isolateUids + false // testMode + ); + } + + public Args api(@NonNull String api) { + return new Args(mModule, api, mMaxEntries, mIsolateUids, mTestMode); + } + + public Args maxEntries(int val) { + return new Args(mModule, mApi, val, mIsolateUids, mTestMode); + } + + public Args isolateUids(boolean val) { + return new Args(mModule, mApi, mMaxEntries, val, mTestMode); + } + + public Args testMode(boolean val) { + return new Args(mModule, mApi, mMaxEntries, mIsolateUids, val); + } + } + + /** + * Make a new property invalidated cache. The key is computed from the module and api + * parameters. + * + * @param args The cache configuration. + * @param cacheName Name of this cache in debug and dumpsys + * @param computer The code to compute values that are not in the cache. + * @hide + */ + public PropertyInvalidatedCache(@NonNull Args args, @NonNull String cacheName, + @Nullable QueryHandler computer) { + mPropertyName = createPropertyName(args.mModule, args.mApi); + mCacheName = cacheName; + mNonce = getNonceHandler(mPropertyName); + mMaxEntries = args.mMaxEntries; + mCache = new CacheMap<>(args.mIsolateUids, args.mTestMode); + mComputer = (computer != null) ? computer : new DefaultComputer<>(this); + registerCache(); + } + + /** + * Burst a property name into module and api. Throw if the key is invalid. This method is + * used in to transition legacy cache constructors to the args constructor. + */ + private static Args parseProperty(@NonNull String name) { + throwIfInvalidCacheKey(name); + // Strip off the leading well-known prefix. + String base = name.substring(CACHE_KEY_PREFIX.length() + 1); + int dot = base.indexOf("."); + String module = base.substring(0, dot); + String api = base.substring(dot + 1); + return new Args(module).api(api); + } + /** * Make a new property invalidated cache. This constructor names the cache after the * property name. New clients should prefer the constructor that takes an explicit @@ -867,7 +1188,7 @@ public class PropertyInvalidatedCache { * @hide */ public PropertyInvalidatedCache(int maxEntries, @NonNull String propertyName) { - this(maxEntries, propertyName, propertyName); + this(parseProperty(propertyName).maxEntries(maxEntries), propertyName, null); } /** @@ -883,13 +1204,7 @@ public class PropertyInvalidatedCache { */ public PropertyInvalidatedCache(int maxEntries, @NonNull String propertyName, @NonNull String cacheName) { - mPropertyName = propertyName; - mCacheName = cacheName; - mNonce = getNonceHandler(mPropertyName); - mMaxEntries = maxEntries; - mComputer = new DefaultComputer<>(this); - mCache = createMap(); - registerCache(); + this(parseProperty(propertyName).maxEntries(maxEntries), cacheName, null); } /** @@ -907,35 +1222,7 @@ public class PropertyInvalidatedCache { @TestApi public PropertyInvalidatedCache(int maxEntries, @NonNull String module, @NonNull String api, @NonNull String cacheName, @NonNull QueryHandler computer) { - mPropertyName = createPropertyName(module, api); - mCacheName = cacheName; - mNonce = getNonceHandler(mPropertyName); - mMaxEntries = maxEntries; - mComputer = computer; - mCache = createMap(); - registerCache(); - } - - // Create a map. This should be called only from the constructor. - private LinkedHashMap createMap() { - return new LinkedHashMap( - 2 /* start small */, - 0.75f /* default load factor */, - true /* LRU access order */) { - @GuardedBy("mLock") - @Override - protected boolean removeEldestEntry(Map.Entry eldest) { - final int size = size(); - if (size > mHighWaterMark) { - mHighWaterMark = size; - } - if (size > mMaxEntries) { - mMissOverflow++; - return true; - } - return false; - } - }; + this(new Args(module).maxEntries(maxEntries).api(api), cacheName, computer); } /** @@ -1181,7 +1468,8 @@ public class PropertyInvalidatedCache { public @Nullable Result query(@NonNull Query query) { // Let access to mDisabled race: it's atomic anyway. long currentNonce = (!isDisabled()) ? getCurrentNonce() : NONCE_DISABLED; - if (bypass(query)) { + if (!isReservedNonce(currentNonce) + && bypass(query)) { currentNonce = NONCE_BYPASS; } for (;;) { @@ -1649,71 +1937,70 @@ public class PropertyInvalidatedCache { return false; } - /** - * helper method to check if dump should be skipped due to zero values - * @param args takes command arguments to check if -brief is present - * @return True if dump should be skipped - */ - private boolean skipDump(String[] args) { - for (String a : args) { - if (a.equals(BRIEF)) { - return (mSkips[NONCE_CORKED] + mSkips[NONCE_UNSET] + mSkips[NONCE_DISABLED] - + mSkips[NONCE_BYPASS] + mHits + mMisses) == 0; - } + @GuardedBy("mLock") + private long getSkipsLocked() { + int sum = 0; + for (int i = 0; i < mSkips.length; i++) { + sum += mSkips[i]; } - return false; + return sum; } + // Return true if this cache has had any activity. If the hits, misses, and skips are all + // zero then the client never tried to use the cache. + private boolean isActive() { + synchronized (mLock) { + return mHits + mMisses + getSkipsLocked() > 0; + } + } + + @NeverCompile private void dumpContents(PrintWriter pw, boolean detailed, String[] args) { // If the user has requested specific caches and this is not one of them, return // immediately. if (detailed && !showDetailed(args)) { return; } + // Does the user want brief output? + boolean brief = false; + for (String a : args) brief |= a.equals(BRIEF); NonceHandler.Stats stats = mNonce.getStats(); synchronized (mLock) { - if (!skipDump(args)) { - pw.println(formatSimple(" Cache Name: %s", cacheName())); - pw.println(formatSimple(" Property: %s", mPropertyName)); - final long skips = - mSkips[NONCE_CORKED] + mSkips[NONCE_UNSET] + mSkips[NONCE_DISABLED] - + mSkips[NONCE_BYPASS]; - pw.println(formatSimple( - " Hits: %d, Misses: %d, Skips: %d, Clears: %d", - mHits, mMisses, skips, mClears)); - pw.println(formatSimple( - " Skip-corked: %d, Skip-unset: %d, Skip-bypass: %d, Skip-other: %d", - mSkips[NONCE_CORKED], mSkips[NONCE_UNSET], - mSkips[NONCE_BYPASS], mSkips[NONCE_DISABLED])); - pw.println(formatSimple( - " Nonce: 0x%016x, Invalidates: %d, CorkedInvalidates: %d", - mLastSeenNonce, stats.invalidated, stats.corkedInvalidates)); - pw.println(formatSimple( - " Current Size: %d, Max Size: %d, HW Mark: %d, Overflows: %d", - mCache.size(), mMaxEntries, mHighWaterMark, mMissOverflow)); - pw.println(formatSimple(" Enabled: %s", mDisabled ? "false" : "true")); - pw.println(""); - } - - // No specific cache was requested. This is the default, and no details - // should be dumped. - if (!detailed) { - return; - } - Set> cacheEntries = mCache.entrySet(); - if (cacheEntries.size() == 0) { + if (brief && !isActive()) { return; } - pw.println(" Contents:"); - for (Map.Entry entry : cacheEntries) { - String key = Objects.toString(entry.getKey()); - String value = Objects.toString(entry.getValue()); + pw.println(formatSimple(" Cache Name: %s", cacheName())); + pw.println(formatSimple(" Property: %s", mPropertyName)); + pw.println(formatSimple( + " Hits: %d, Misses: %d, Skips: %d, Clears: %d, Uids: %d", + mHits, mMisses, getSkipsLocked(), mClears, mCache.size())); - pw.println(formatSimple(" Key: %s\n Value: %s\n", key, value)); + // Print all the skip reasons. + pw.format(" Skip-%s: %d", sNonceName[0], mSkips[0]); + for (int i = 1; i < mSkips.length; i++) { + pw.format(", Skip-%s: %d", sNonceName[i], mSkips[i]); } + pw.println(); + + pw.println(formatSimple( + " Nonce: 0x%016x, Invalidates: %d, CorkedInvalidates: %d", + mLastSeenNonce, stats.invalidated, stats.corkedInvalidates)); + pw.println(formatSimple( + " Current Size: %d, Max Size: %d, HW Mark: %d, Overflows: %d", + mCache.size(), mMaxEntries, mHighWaterMark, mMissOverflow)); + mCache.dump(pw); + pw.println(formatSimple(" Enabled: %s", mDisabled ? "false" : "true")); + + // Dump the contents of the cache. + if (detailed) { + mCache.dumpDetailed(pw); + } + + // Separator between caches. + pw.println(""); } } @@ -1723,6 +2010,7 @@ public class PropertyInvalidatedCache { * specific caches (selection is by cache name or property name); if these switches * are used then the output includes both cache statistics and cache entries. */ + @NeverCompile private static void dumpCacheInfo(@NonNull PrintWriter pw, @NonNull String[] args) { if (!sEnabled) { pw.println(" Caching is disabled in this process."); @@ -1755,6 +2043,7 @@ public class PropertyInvalidatedCache { * are used then the output includes both cache statistics and cache entries. * @hide */ + @NeverCompile public static void dumpCacheInfo(@NonNull ParcelFileDescriptor pfd, @NonNull String[] args) { // Create a PrintWriter that uses a byte array. The code can safely write to // this array without fear of blocking. The completed byte array will be sent diff --git a/core/java/android/app/StatusBarManager.java b/core/java/android/app/StatusBarManager.java index 63e039143917985d3f19aaa2e1929c642b9fb11b..b7285c38290ce38e147773eeee6fa7ac24d524a9 100644 --- a/core/java/android/app/StatusBarManager.java +++ b/core/java/android/app/StatusBarManager.java @@ -602,6 +602,15 @@ public class StatusBarManager { @LoggingOnly private static final long MEDIA_CONTROL_BLANK_TITLE = 274775190L; + /** + * Media controls based on {@link android.app.Notification.MediaStyle} notifications will have + * actions from the associated {@link androidx.media3.MediaController}, if available. + */ + @ChangeId + @EnabledSince(targetSdkVersion = Build.VERSION_CODES.CUR_DEVELOPMENT) + // TODO(b/360196209): Set target SDK to Baklava once available + private static final long MEDIA_CONTROL_MEDIA3_ACTIONS = 360196209L; + @UnsupportedAppUsage private Context mContext; private IStatusBarService mService; @@ -1269,6 +1278,21 @@ public class StatusBarManager { } } + /** + * Checks whether the media controls for a given package should use a Media3 controller + * + * @param packageName App posting media controls + * @param user Current user handle + * @return true if Media3 should be used + * + * @hide + */ + @RequiresPermission(allOf = {android.Manifest.permission.READ_COMPAT_CHANGE_CONFIG, + android.Manifest.permission.LOG_COMPAT_CHANGE}) + public static boolean useMedia3ControllerForApp(String packageName, UserHandle user) { + return CompatChanges.isChangeEnabled(MEDIA_CONTROL_MEDIA3_ACTIONS, packageName, user); + } + /** * Checks whether the supplied activity can {@link Activity#startActivityForResult(Intent, int)} * a system activity that captures content on the screen to take a screenshot. diff --git a/core/java/android/app/TaskInfo.java b/core/java/android/app/TaskInfo.java index 0a4d8f21350149e18d9882471f4b63a8eb89a968..aac963ade7269a6b6ca94f27b8d843e2ae441f8e 100644 --- a/core/java/android/app/TaskInfo.java +++ b/core/java/android/app/TaskInfo.java @@ -296,22 +296,22 @@ public class TaskInfo { public boolean isVisibleRequested; /** - * Whether this task is sleeping due to sleeping display. + * Whether the top activity is to be displayed. See {@link android.R.attr#windowNoDisplay}. * @hide */ - public boolean isSleeping; + public boolean isTopActivityNoDisplay; /** - * Whether the top activity fillsParent() is false + * Whether this task is sleeping due to sleeping display. * @hide */ - public boolean isTopActivityTransparent; + public boolean isSleeping; /** - * Whether the top activity has specified style floating. + * Whether the top activity fillsParent() is false * @hide */ - public boolean isTopActivityStyleFloating; + public boolean isTopActivityTransparent; /** * The last non-fullscreen bounds the task was launched in or resized to. @@ -364,8 +364,9 @@ public class TaskInfo { // Do nothing } - private TaskInfo(Parcel source) { - readFromParcel(source); + /** @hide */ + public TaskInfo(Parcel source) { + readTaskFromParcel(source); } /** @@ -482,13 +483,13 @@ public class TaskInfo { && isFocused == that.isFocused && isVisible == that.isVisible && isVisibleRequested == that.isVisibleRequested + && isTopActivityNoDisplay == that.isTopActivityNoDisplay && isSleeping == that.isSleeping && Objects.equals(mTopActivityLocusId, that.mTopActivityLocusId) && parentTaskId == that.parentTaskId && Objects.equals(topActivity, that.topActivity) && isTopActivityTransparent == that.isTopActivityTransparent - && isTopActivityStyleFloating == that.isTopActivityStyleFloating - && lastNonFullscreenBounds == this.lastNonFullscreenBounds + && Objects.equals(lastNonFullscreenBounds, that.lastNonFullscreenBounds) && Objects.equals(capturedLink, that.capturedLink) && capturedLinkTimestamp == that.capturedLinkTimestamp && requestedVisibleTypes == that.requestedVisibleTypes @@ -524,7 +525,7 @@ public class TaskInfo { /** * Reads the TaskInfo from a parcel. */ - void readFromParcel(Parcel source) { + void readTaskFromParcel(Parcel source) { userId = source.readInt(); taskId = source.readInt(); effectiveUid = source.readInt(); @@ -561,11 +562,11 @@ public class TaskInfo { isFocused = source.readBoolean(); isVisible = source.readBoolean(); isVisibleRequested = source.readBoolean(); + isTopActivityNoDisplay = source.readBoolean(); isSleeping = source.readBoolean(); mTopActivityLocusId = source.readTypedObject(LocusId.CREATOR); displayAreaFeatureId = source.readInt(); isTopActivityTransparent = source.readBoolean(); - isTopActivityStyleFloating = source.readBoolean(); lastNonFullscreenBounds = source.readTypedObject(Rect.CREATOR); capturedLink = source.readTypedObject(Uri.CREATOR); capturedLinkTimestamp = source.readLong(); @@ -577,8 +578,9 @@ public class TaskInfo { /** * Writes the TaskInfo to a parcel. + * @hide */ - void writeToParcel(Parcel dest, int flags) { + public void writeTaskToParcel(Parcel dest, int flags) { dest.writeInt(userId); dest.writeInt(taskId); dest.writeInt(effectiveUid); @@ -616,11 +618,11 @@ public class TaskInfo { dest.writeBoolean(isFocused); dest.writeBoolean(isVisible); dest.writeBoolean(isVisibleRequested); + dest.writeBoolean(isTopActivityNoDisplay); dest.writeBoolean(isSleeping); dest.writeTypedObject(mTopActivityLocusId, flags); dest.writeInt(displayAreaFeatureId); dest.writeBoolean(isTopActivityTransparent); - dest.writeBoolean(isTopActivityStyleFloating); dest.writeTypedObject(lastNonFullscreenBounds, flags); dest.writeTypedObject(capturedLink, flags); dest.writeLong(capturedLinkTimestamp); @@ -661,11 +663,11 @@ public class TaskInfo { + " isFocused=" + isFocused + " isVisible=" + isVisible + " isVisibleRequested=" + isVisibleRequested + + " isTopActivityNoDisplay=" + isTopActivityNoDisplay + " isSleeping=" + isSleeping + " locusId=" + mTopActivityLocusId + " displayAreaFeatureId=" + displayAreaFeatureId + " isTopActivityTransparent=" + isTopActivityTransparent - + " isTopActivityStyleFloating=" + isTopActivityStyleFloating + " lastNonFullscreenBounds=" + lastNonFullscreenBounds + " capturedLink=" + capturedLink + " capturedLinkTimestamp=" + capturedLinkTimestamp diff --git a/core/java/android/app/admin/DevicePolicyIdentifiers.java b/core/java/android/app/admin/DevicePolicyIdentifiers.java index c0e435c04d3cb72d8fe746c024074bf0ab70314f..35149b5a31357f9497538dbecdfdac4c72066129 100644 --- a/core/java/android/app/admin/DevicePolicyIdentifiers.java +++ b/core/java/android/app/admin/DevicePolicyIdentifiers.java @@ -190,6 +190,12 @@ public final class DevicePolicyIdentifiers { */ public static final String PASSWORD_COMPLEXITY_POLICY = "passwordComplexity"; + /** + * String identifier for {@link DevicePolicyManager#setMtePolicy(int)}. + */ + @FlaggedApi(android.app.admin.flags.Flags.FLAG_SET_MTE_POLICY_COEXISTENCE) + public static final String MEMORY_TAGGING_POLICY = "memoryTagging"; + /** * @hide */ diff --git a/core/java/android/app/admin/flags/flags.aconfig b/core/java/android/app/admin/flags/flags.aconfig index 3aaca25eca156866130a8fcb0d984e4194ec6a7d..be24bfa41e109b187bd9dae946dd00e52d39f4d8 100644 --- a/core/java/android/app/admin/flags/flags.aconfig +++ b/core/java/android/app/admin/flags/flags.aconfig @@ -275,6 +275,16 @@ flag { } } +flag { + name: "suspend_packages_coexistence" + namespace: "enterprise" + description: "Migrate setPackagesSuspended for unmanaged mode" + bug: "335624297" + metadata { + purpose: PURPOSE_BUGFIX + } +} + flag { name: "backup_connected_apps_settings" namespace: "enterprise" @@ -349,3 +359,18 @@ flag { description: "Enables coexistence support for Setting MTE policy." bug: "376213673" } + +flag { + name: "enable_supervision_service_sync" + is_exported: true + namespace: "enterprise" + description: "Allows DPMS to enable or disable SupervisionService based on whether the device is being managed by the supervision role holder." + bug: "376213673" +} + +flag { + name: "split_create_managed_profile_enabled" + namespace: "enterprise" + description: "Split up existing create and provision managed profile API." + bug: "375382324" +} diff --git a/core/java/android/app/appfunctions/AppFunctionException.aidl b/core/java/android/app/appfunctions/AppFunctionException.aidl new file mode 100644 index 0000000000000000000000000000000000000000..7d432243b1b214e6ac34e5bdef32a94b95cad9d4 --- /dev/null +++ b/core/java/android/app/appfunctions/AppFunctionException.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.app.appfunctions; + +import android.app.appfunctions.AppFunctionException; + +parcelable AppFunctionException; \ No newline at end of file diff --git a/core/java/android/app/appfunctions/AppFunctionException.java b/core/java/android/app/appfunctions/AppFunctionException.java new file mode 100644 index 0000000000000000000000000000000000000000..cbd1d932ab00e7d860063aced888c648d818eb3c --- /dev/null +++ b/core/java/android/app/appfunctions/AppFunctionException.java @@ -0,0 +1,261 @@ +/* + * 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.app.appfunctions; + +import static android.app.appfunctions.flags.Flags.FLAG_ENABLE_APP_FUNCTION_MANAGER; + +import android.annotation.FlaggedApi; +import android.annotation.IntDef; +import android.annotation.NonNull; +import android.annotation.Nullable; +import android.os.Bundle; +import android.os.Parcel; +import android.os.Parcelable; + +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.util.Objects; + +/** Represents an app function related errors. */ +@FlaggedApi(FLAG_ENABLE_APP_FUNCTION_MANAGER) +public final class AppFunctionException extends Exception implements Parcelable { + /** + * The caller does not have the permission to execute an app function. + * + *

This error is in the {@link #ERROR_CATEGORY_REQUEST_ERROR} category. + */ + public static final int ERROR_DENIED = 1000; + + /** + * The caller supplied invalid arguments to the execution request. + * + *

This error may be considered similar to {@link IllegalArgumentException}. + * + *

This error is in the {@link #ERROR_CATEGORY_REQUEST_ERROR} category. + */ + public static final int ERROR_INVALID_ARGUMENT = 1001; + + /** + * The caller tried to execute a disabled app function. + * + *

This error is in the {@link #ERROR_CATEGORY_REQUEST_ERROR} category. + */ + public static final int ERROR_DISABLED = 1002; + + /** + * The caller tried to execute a function that does not exist. + * + *

This error is in the {@link #ERROR_CATEGORY_REQUEST_ERROR} category. + */ + public static final int ERROR_FUNCTION_NOT_FOUND = 1003; + + /** + * An internal unexpected error coming from the system. + * + *

This error is in the {@link #ERROR_CATEGORY_SYSTEM} category. + */ + public static final int ERROR_SYSTEM_ERROR = 2000; + + /** + * The operation was cancelled. Use this error code to report that a cancellation is done after + * receiving a cancellation signal. + * + *

This error is in the {@link #ERROR_CATEGORY_SYSTEM} category. + */ + public static final int ERROR_CANCELLED = 2001; + + /** + * An unknown error occurred while processing the call in the AppFunctionService. + * + *

This error is thrown when the service is connected in the remote application but an + * unexpected error is thrown from the bound application. + * + *

This error is in the {@link #ERROR_CATEGORY_APP} category. + */ + public static final int ERROR_APP_UNKNOWN_ERROR = 3000; + + /** + * The error category is unknown. + * + *

This is the default value for {@link #getErrorCategory}. + */ + public static final int ERROR_CATEGORY_UNKNOWN = 0; + + /** + * The error is caused by the app requesting a function execution. + * + *

For example, the caller provided invalid parameters in the execution request e.g. an + * invalid function ID. + * + *

Errors in the category fall in the range 1000-1999 inclusive. + */ + public static final int ERROR_CATEGORY_REQUEST_ERROR = 1; + + /** + * The error is caused by an issue in the system. + * + *

For example, the AppFunctionService implementation is not found by the system. + * + *

Errors in the category fall in the range 2000-2999 inclusive. + */ + public static final int ERROR_CATEGORY_SYSTEM = 2; + + /** + * The error is caused by the app providing the function. + * + *

For example, the app crashed when the system is executing the request. + * + *

Errors in the category fall in the range 3000-3999 inclusive. + */ + public static final int ERROR_CATEGORY_APP = 3; + + private final int mErrorCode; + @Nullable private final String mErrorMessage; + @NonNull private final Bundle mExtras; + + /** + * @param errorCode The error code. + * @param errorMessage The error message. + */ + public AppFunctionException(@ErrorCode int errorCode, @Nullable String errorMessage) { + this(errorCode, errorMessage, Bundle.EMPTY); + } + + /** + * @param errorCode The error code. + * @param errorMessage The error message. + * @param extras The extras associated with this error. + */ + public AppFunctionException( + @ErrorCode int errorCode, @Nullable String errorMessage, @NonNull Bundle extras) { + super(errorMessage); + mErrorCode = errorCode; + mErrorMessage = errorMessage; + mExtras = Objects.requireNonNull(extras); + } + + private AppFunctionException(@NonNull Parcel in) { + mErrorCode = in.readInt(); + mErrorMessage = in.readString8(); + mExtras = Objects.requireNonNull(in.readBundle(getClass().getClassLoader())); + } + + /** Returns one of the {@code ERROR} constants. */ + @ErrorCode + public int getErrorCode() { + return mErrorCode; + } + + /** Returns the error message. */ + @Nullable + public String getErrorMessage() { + return mErrorMessage; + } + + /** + * Returns the error category. + * + *

This method categorizes errors based on their underlying cause, allowing developers to + * implement targeted error handling and provide more informative error messages to users. It + * maps ranges of error codes to specific error categories. + * + *

This method returns {@code ERROR_CATEGORY_UNKNOWN} if the error code does not belong to + * any error category. + * + *

See {@link ErrorCategory} for a complete list of error categories and their corresponding + * error code ranges. + */ + @ErrorCategory + public int getErrorCategory() { + if (mErrorCode >= 1000 && mErrorCode < 2000) { + return ERROR_CATEGORY_REQUEST_ERROR; + } + if (mErrorCode >= 2000 && mErrorCode < 3000) { + return ERROR_CATEGORY_SYSTEM; + } + if (mErrorCode >= 3000 && mErrorCode < 4000) { + return ERROR_CATEGORY_APP; + } + return ERROR_CATEGORY_UNKNOWN; + } + + /** Returns any extras associated with this error. */ + @NonNull + public Bundle getExtras() { + return mExtras; + } + + @Override + public int describeContents() { + return 0; + } + + @Override + public void writeToParcel(@NonNull Parcel dest, int flags) { + dest.writeInt(mErrorCode); + dest.writeString8(mErrorMessage); + dest.writeBundle(mExtras); + } + + /** + * Error codes. + * + * @hide + */ + @IntDef( + prefix = {"ERROR_"}, + value = { + ERROR_DENIED, + ERROR_APP_UNKNOWN_ERROR, + ERROR_FUNCTION_NOT_FOUND, + ERROR_SYSTEM_ERROR, + ERROR_INVALID_ARGUMENT, + ERROR_DISABLED, + ERROR_CANCELLED + }) + @Retention(RetentionPolicy.SOURCE) + public @interface ErrorCode {} + + /** + * Error categories. + * + * @hide + */ + @IntDef( + prefix = {"ERROR_CATEGORY_"}, + value = { + ERROR_CATEGORY_UNKNOWN, + ERROR_CATEGORY_REQUEST_ERROR, + ERROR_CATEGORY_APP, + ERROR_CATEGORY_SYSTEM + }) + @Retention(RetentionPolicy.SOURCE) + public @interface ErrorCategory {} + + @NonNull + public static final Creator CREATOR = + new Creator<>() { + @Override + public AppFunctionException createFromParcel(Parcel in) { + return new AppFunctionException(in); + } + + @Override + public AppFunctionException[] newArray(int size) { + return new AppFunctionException[size]; + } + }; +} diff --git a/core/java/android/app/appfunctions/AppFunctionManager.java b/core/java/android/app/appfunctions/AppFunctionManager.java index 5ddb590add4c01d797daf0fe1f47b53205fe913e..ed088fed41c292aabb68efac071aca757ae49f80 100644 --- a/core/java/android/app/appfunctions/AppFunctionManager.java +++ b/core/java/android/app/appfunctions/AppFunctionManager.java @@ -16,7 +16,7 @@ package android.app.appfunctions; -import static android.app.appfunctions.ExecuteAppFunctionResponse.getResultCode; +import static android.app.appfunctions.AppFunctionException.ERROR_SYSTEM_ERROR; import static android.app.appfunctions.flags.Flags.FLAG_ENABLE_APP_FUNCTION_MANAGER; import android.Manifest; @@ -39,7 +39,6 @@ import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import java.util.Objects; import java.util.concurrent.Executor; -import java.util.function.Consumer; /** * Provides access to app functions. @@ -147,16 +146,16 @@ public final class AppFunctionManager { * @param request the request to execute the app function * @param executor the executor to run the callback * @param cancellationSignal the cancellation signal to cancel the execution. - * @param callback the callback to receive the function execution result. + * @param callback the callback to receive the function execution result or error. *

If the calling app does not own the app function or does not have {@code * android.permission.EXECUTE_APP_FUNCTIONS_TRUSTED} or {@code * android.permission.EXECUTE_APP_FUNCTIONS}, the execution result will contain {@code - * ExecuteAppFunctionResponse.RESULT_DENIED}. + * AppFunctionException.ERROR_DENIED}. *

If the caller only has {@code android.permission.EXECUTE_APP_FUNCTIONS} but the * function requires {@code android.permission.EXECUTE_APP_FUNCTIONS_TRUSTED}, the execution - * result will contain {@code ExecuteAppFunctionResponse.RESULT_DENIED} + * result will contain {@code AppFunctionException.ERROR_DENIED} *

If the function requested for execution is disabled, then the execution result will - * contain {@code ExecuteAppFunctionResponse.RESULT_DISABLED} + * contain {@code AppFunctionException.ERROR_DISABLED} *

If the cancellation signal is issued, the operation is cancelled and no response is * returned to the caller. */ @@ -171,7 +170,9 @@ public final class AppFunctionManager { @NonNull ExecuteAppFunctionRequest request, @NonNull @CallbackExecutor Executor executor, @NonNull CancellationSignal cancellationSignal, - @NonNull Consumer callback) { + @NonNull + OutcomeReceiver + callback) { Objects.requireNonNull(request); Objects.requireNonNull(executor); Objects.requireNonNull(callback); @@ -186,20 +187,25 @@ public final class AppFunctionManager { aidlRequest, new IExecuteAppFunctionCallback.Stub() { @Override - public void onResult(ExecuteAppFunctionResponse result) { + public void onSuccess(ExecuteAppFunctionResponse result) { try { - executor.execute(() -> callback.accept(result)); + executor.execute(() -> callback.onResult(result)); } catch (RuntimeException e) { // Ideally shouldn't happen since errors are wrapped into - // the - // response, but we catch it here for additional safety. - callback.accept( - ExecuteAppFunctionResponse.newFailure( - getResultCode(e), - e.getMessage(), - /* extras= */ null)); + // the response, but we catch it here for additional safety. + executor.execute( + () -> + callback.onError( + new AppFunctionException( + ERROR_SYSTEM_ERROR, + e.getMessage()))); } } + + @Override + public void onError(AppFunctionException exception) { + executor.execute(() -> callback.onError(exception)); + } }); if (cancellationTransport != null) { cancellationSignal.setRemote(cancellationTransport); diff --git a/core/java/android/app/appfunctions/AppFunctionRuntimeMetadata.java b/core/java/android/app/appfunctions/AppFunctionRuntimeMetadata.java index 06d95f5270c38f67485db50adbdd4b394647a9bf..3ddda228d145a096e10f9355a7954b3b0b21f52b 100644 --- a/core/java/android/app/appfunctions/AppFunctionRuntimeMetadata.java +++ b/core/java/android/app/appfunctions/AppFunctionRuntimeMetadata.java @@ -213,9 +213,7 @@ public class AppFunctionRuntimeMetadata extends GenericDocument { setEnabled(original.getEnabled()); } - /** - * Sets an indicator specifying the function enabled state. - */ + /** Sets an indicator specifying the function enabled state. */ @NonNull public Builder setEnabled(@EnabledState int enabledState) { if (enabledState != APP_FUNCTION_STATE_DEFAULT diff --git a/core/java/android/app/appfunctions/AppFunctionService.java b/core/java/android/app/appfunctions/AppFunctionService.java index 63d187aa11efe74d149fbae37e82a94e1d13439d..85b6ab2b4e61ee46d64486d9d11d535b04aa6996 100644 --- a/core/java/android/app/appfunctions/AppFunctionService.java +++ b/core/java/android/app/appfunctions/AppFunctionService.java @@ -17,7 +17,6 @@ package android.app.appfunctions; import static android.Manifest.permission.BIND_APP_FUNCTION_SERVICE; -import static android.app.appfunctions.ExecuteAppFunctionResponse.getResultCode; import static android.app.appfunctions.flags.Flags.FLAG_ENABLE_APP_FUNCTION_MANAGER; import static android.content.pm.PackageManager.PERMISSION_DENIED; @@ -32,10 +31,8 @@ import android.os.Binder; import android.os.CancellationSignal; import android.os.IBinder; import android.os.ICancellationSignal; +import android.os.OutcomeReceiver; import android.os.RemoteException; -import android.util.Log; - -import java.util.function.Consumer; /** * Abstract base class to provide app functions to the system. @@ -80,7 +77,9 @@ public abstract class AppFunctionService extends Service { @NonNull ExecuteAppFunctionRequest request, @NonNull String callingPackage, @NonNull CancellationSignal cancellationSignal, - @NonNull Consumer callback); + @NonNull + OutcomeReceiver + callback); } /** @hide */ @@ -105,13 +104,22 @@ public abstract class AppFunctionService extends Service { request, callingPackage, buildCancellationSignal(cancellationCallback), - safeCallback::onResult); + new OutcomeReceiver<>() { + @Override + public void onResult(ExecuteAppFunctionResponse result) { + safeCallback.onResult(result); + } + + @Override + public void onError(AppFunctionException exception) { + safeCallback.onError(exception); + } + }); } catch (Exception ex) { // Apps should handle exceptions. But if they don't, report the error on // behalf of them. - safeCallback.onResult( - ExecuteAppFunctionResponse.newFailure( - getResultCode(ex), ex.getMessage(), /* extras= */ null)); + safeCallback.onError( + new AppFunctionException(toErrorCode(ex), ex.getMessage())); } } }; @@ -164,12 +172,26 @@ public abstract class AppFunctionService extends Service { * @param request The function execution request. * @param callingPackage The package name of the app that is requesting the execution. * @param cancellationSignal A signal to cancel the execution. - * @param callback A callback to report back the result. + * @param callback A callback to report back the result or error. */ @MainThread public abstract void onExecuteFunction( @NonNull ExecuteAppFunctionRequest request, @NonNull String callingPackage, @NonNull CancellationSignal cancellationSignal, - @NonNull Consumer callback); + @NonNull + OutcomeReceiver + callback); + + /** + * Returns result codes from throwable. + * + * @hide + */ + private static @AppFunctionException.ErrorCode int toErrorCode(@NonNull Throwable t) { + if (t instanceof IllegalArgumentException) { + return AppFunctionException.ERROR_INVALID_ARGUMENT; + } + return AppFunctionException.ERROR_APP_UNKNOWN_ERROR; + } } diff --git a/core/java/android/app/appfunctions/AppFunctionStaticMetadataHelper.java b/core/java/android/app/appfunctions/AppFunctionStaticMetadataHelper.java index a23f842e6eeb18974fdf68d53b0d481041aa190d..1869d22ea080707934da5c8e7d2af9787b75624e 100644 --- a/core/java/android/app/appfunctions/AppFunctionStaticMetadataHelper.java +++ b/core/java/android/app/appfunctions/AppFunctionStaticMetadataHelper.java @@ -38,7 +38,7 @@ public class AppFunctionStaticMetadataHelper { public static final String STATIC_SCHEMA_TYPE = "AppFunctionStaticMetadata"; public static final String STATIC_PROPERTY_ENABLED_BY_DEFAULT = "enabledByDefault"; public static final String STATIC_PROPERTY_RESTRICT_CALLERS_WITH_EXECUTE_APP_FUNCTIONS = - "restrictCallersWithExecuteAppFunctions"; + "restrictCallersWithExecuteAppFunctions"; public static final String APP_FUNCTION_STATIC_NAMESPACE = "app_functions"; public static final String PROPERTY_FUNCTION_ID = "functionId"; diff --git a/core/java/android/app/appfunctions/ExecuteAppFunctionRequest.java b/core/java/android/app/appfunctions/ExecuteAppFunctionRequest.java index 41bb62270e9f747a043ad121d85060fab0a2b9de..1557815a8468993cbef54039fad55a8691daf770 100644 --- a/core/java/android/app/appfunctions/ExecuteAppFunctionRequest.java +++ b/core/java/android/app/appfunctions/ExecuteAppFunctionRequest.java @@ -111,8 +111,8 @@ public final class ExecuteAppFunctionRequest implements Parcelable { * Returns the function parameters. The key is the parameter name, and the value is the * parameter value. * - *

The bundle may have missing parameters. Developers are advised to implement defensive - * handling measures. + *

The {@link GenericDocument} may have missing parameters. Developers are advised to + * implement defensive handling measures. * * @see AppFunctionManager on how to determine the expected parameters. */ diff --git a/core/java/android/app/appfunctions/ExecuteAppFunctionResponse.java b/core/java/android/app/appfunctions/ExecuteAppFunctionResponse.java index cdf02e6f5a09c9bf504af4d18b41e6b707a87e2d..acad43b782e520f2974c25fb45ca2c98f011e5af 100644 --- a/core/java/android/app/appfunctions/ExecuteAppFunctionResponse.java +++ b/core/java/android/app/appfunctions/ExecuteAppFunctionResponse.java @@ -19,16 +19,12 @@ package android.app.appfunctions; import static android.app.appfunctions.flags.Flags.FLAG_ENABLE_APP_FUNCTION_MANAGER; import android.annotation.FlaggedApi; -import android.annotation.IntDef; import android.annotation.NonNull; -import android.annotation.Nullable; import android.app.appsearch.GenericDocument; import android.os.Bundle; import android.os.Parcel; import android.os.Parcelable; -import java.lang.annotation.Retention; -import java.lang.annotation.RetentionPolicy; import java.util.Objects; /** The response to an app function execution. */ @@ -45,10 +41,7 @@ public final class ExecuteAppFunctionResponse implements Parcelable { Bundle extras = Objects.requireNonNull( parcel.readBundle(Bundle.class.getClassLoader())); - int resultCode = parcel.readInt(); - String errorMessage = parcel.readString8(); - return new ExecuteAppFunctionResponse( - resultWrapper, extras, resultCode, errorMessage); + return new ExecuteAppFunctionResponse(resultWrapper.getValue(), extras); } @Override @@ -71,113 +64,7 @@ public final class ExecuteAppFunctionResponse implements Parcelable { * *

See {@link #getResultDocument} for more information on extracting the return value. */ - public static final String PROPERTY_RETURN_VALUE = "returnValue"; - - /** - * The call was successful. - * - *

This result code does not belong in an error category. - */ - public static final int RESULT_OK = 0; - - /** - * The caller does not have the permission to execute an app function. - * - *

This error is in the {@link #ERROR_CATEGORY_REQUEST_ERROR} category. - */ - public static final int RESULT_DENIED = 1000; - - /** - * The caller supplied invalid arguments to the execution request. - * - *

This error may be considered similar to {@link IllegalArgumentException}. - * - *

This error is in the {@link #ERROR_CATEGORY_REQUEST_ERROR} category. - */ - public static final int RESULT_INVALID_ARGUMENT = 1001; - - /** - * The caller tried to execute a disabled app function. - * - *

This error is in the {@link #ERROR_CATEGORY_REQUEST_ERROR} category. - */ - public static final int RESULT_DISABLED = 1002; - - /** - * The caller tried to execute a function that does not exist. - * - *

This error is in the {@link #ERROR_CATEGORY_REQUEST_ERROR} category. - */ - public static final int RESULT_FUNCTION_NOT_FOUND = 1003; - - /** - * An internal unexpected error coming from the system. - * - *

This error is in the {@link #ERROR_CATEGORY_SYSTEM} category. - */ - public static final int RESULT_SYSTEM_ERROR = 2000; - - /** - * The operation was cancelled. Use this error code to report that a cancellation is done after - * receiving a cancellation signal. - * - *

This error is in the {@link #ERROR_CATEGORY_SYSTEM} category. - */ - public static final int RESULT_CANCELLED = 2001; - - /** - * An unknown error occurred while processing the call in the AppFunctionService. - * - *

This error is thrown when the service is connected in the remote application but an - * unexpected error is thrown from the bound application. - * - *

This error is in the {@link #ERROR_CATEGORY_APP} category. - */ - public static final int RESULT_APP_UNKNOWN_ERROR = 3000; - - /** - * The error category is unknown. - * - *

This is the default value for {@link #getErrorCategory}. - */ - public static final int ERROR_CATEGORY_UNKNOWN = 0; - - /** - * The error is caused by the app requesting a function execution. - * - *

For example, the caller provided invalid parameters in the execution request e.g. an - * invalid function ID. - * - *

Errors in the category fall in the range 1000-1999 inclusive. - */ - public static final int ERROR_CATEGORY_REQUEST_ERROR = 1; - - /** - * The error is caused by an issue in the system. - * - *

For example, the AppFunctionService implementation is not found by the system. - * - *

Errors in the category fall in the range 2000-2999 inclusive. - */ - public static final int ERROR_CATEGORY_SYSTEM = 2; - - /** - * The error is caused by the app providing the function. - * - *

For example, the app crashed when the system is executing the request. - * - *

Errors in the category fall in the range 3000-3999 inclusive. - */ - public static final int ERROR_CATEGORY_APP = 3; - - /** The result code of the app function execution. */ - @ResultCode private final int mResultCode; - - /** - * The error message associated with the result, if any. This is {@code null} if the result code - * is {@link #RESULT_OK}. - */ - @Nullable private final String mErrorMessage; + public static final String PROPERTY_RETURN_VALUE = "androidAppfunctionsReturnValue"; /** * Returns the return value of the executed function. @@ -192,103 +79,21 @@ public final class ExecuteAppFunctionResponse implements Parcelable { /** Returns the additional metadata data relevant to this function execution response. */ @NonNull private final Bundle mExtras; - private ExecuteAppFunctionResponse( - @NonNull GenericDocumentWrapper resultDocumentWrapper, - @NonNull Bundle extras, - @ResultCode int resultCode, - @Nullable String errorMessage) { - mResultDocumentWrapper = Objects.requireNonNull(resultDocumentWrapper); - mExtras = Objects.requireNonNull(extras); - mResultCode = resultCode; - mErrorMessage = errorMessage; - } - /** - * Returns result codes from throwable. - * - * @hide - */ - @FlaggedApi(FLAG_ENABLE_APP_FUNCTION_MANAGER) - static @ResultCode int getResultCode(@NonNull Throwable t) { - if (t instanceof IllegalArgumentException) { - return ExecuteAppFunctionResponse.RESULT_INVALID_ARGUMENT; - } - return ExecuteAppFunctionResponse.RESULT_APP_UNKNOWN_ERROR; - } - - /** - * Returns a successful response. - * * @param resultDocument The return value of the executed function. - * @param extras The additional metadata for this function execution response. */ - @NonNull - @FlaggedApi(FLAG_ENABLE_APP_FUNCTION_MANAGER) - public static ExecuteAppFunctionResponse newSuccess( - @NonNull GenericDocument resultDocument, @Nullable Bundle extras) { - Objects.requireNonNull(resultDocument); - Bundle actualExtras = getActualExtras(extras); - GenericDocumentWrapper resultDocumentWrapper = new GenericDocumentWrapper(resultDocument); - - return new ExecuteAppFunctionResponse( - resultDocumentWrapper, actualExtras, RESULT_OK, /* errorMessage= */ null); + public ExecuteAppFunctionResponse(@NonNull GenericDocument resultDocument) { + this(resultDocument, Bundle.EMPTY); } /** - * Returns a failure response. - * - * @param resultCode The result code of the app function execution. + * @param resultDocument The return value of the executed function. * @param extras The additional metadata for this function execution response. - * @param errorMessage The error message associated with the result, if any. - */ - @NonNull - @FlaggedApi(FLAG_ENABLE_APP_FUNCTION_MANAGER) - public static ExecuteAppFunctionResponse newFailure( - @ResultCode int resultCode, @Nullable String errorMessage, @Nullable Bundle extras) { - if (resultCode == RESULT_OK) { - throw new IllegalArgumentException("resultCode must not be RESULT_OK"); - } - Bundle actualExtras = getActualExtras(extras); - GenericDocumentWrapper emptyWrapper = - new GenericDocumentWrapper(new GenericDocument.Builder<>("", "", "").build()); - return new ExecuteAppFunctionResponse(emptyWrapper, actualExtras, resultCode, errorMessage); - } - - private static Bundle getActualExtras(@Nullable Bundle extras) { - if (extras == null) { - return Bundle.EMPTY; - } - return extras; - } - - /** - * Returns the error category of the {@link ExecuteAppFunctionResponse}. - * - *

This method categorizes errors based on their underlying cause, allowing developers to - * implement targeted error handling and provide more informative error messages to users. It - * maps ranges of result codes to specific error categories. - * - *

When constructing a {@link #newFailure} response, use the appropriate result code value to - * ensure correct categorization of the failed response. - * - *

This method returns {@code ERROR_CATEGORY_UNKNOWN} if the result code does not belong to - * any error category, for example, in the case of a successful result with {@link #RESULT_OK}. - * - *

See {@link ErrorCategory} for a complete list of error categories and their corresponding - * result code ranges. */ - @ErrorCategory - public int getErrorCategory() { - if (mResultCode >= 1000 && mResultCode < 2000) { - return ERROR_CATEGORY_REQUEST_ERROR; - } - if (mResultCode >= 2000 && mResultCode < 3000) { - return ERROR_CATEGORY_SYSTEM; - } - if (mResultCode >= 3000 && mResultCode < 4000) { - return ERROR_CATEGORY_APP; - } - return ERROR_CATEGORY_UNKNOWN; + public ExecuteAppFunctionResponse( + @NonNull GenericDocument resultDocument, @NonNull Bundle extras) { + mResultDocumentWrapper = new GenericDocumentWrapper(Objects.requireNonNull(resultDocument)); + mExtras = Objects.requireNonNull(extras); } /** @@ -296,9 +101,6 @@ public final class ExecuteAppFunctionResponse implements Parcelable { * *

The {@link #PROPERTY_RETURN_VALUE} key can be used to obtain the return value. * - *

An empty document is returned if {@link #isSuccess} is {@code false} or if the executed - * function does not produce a return value. - * *

Sample code for extracting the return value: * *

@@ -324,32 +126,6 @@ public final class ExecuteAppFunctionResponse implements Parcelable {
         return mExtras;
     }
 
-    /**
-     * Returns {@code true} if {@link #getResultCode} equals {@link
-     * ExecuteAppFunctionResponse#RESULT_OK}.
-     */
-    public boolean isSuccess() {
-        return getResultCode() == RESULT_OK;
-    }
-
-    /**
-     * Returns one of the {@code RESULT} constants defined in {@link ExecuteAppFunctionResponse}.
-     */
-    @ResultCode
-    public int getResultCode() {
-        return mResultCode;
-    }
-
-    /**
-     * Returns the error message associated with this result.
-     *
-     * 

If {@link #isSuccess} is {@code true}, the error message is always {@code null}. - */ - @Nullable - public String getErrorMessage() { - return mErrorMessage; - } - @Override public int describeContents() { return 0; @@ -359,43 +135,5 @@ public final class ExecuteAppFunctionResponse implements Parcelable { public void writeToParcel(@NonNull Parcel dest, int flags) { mResultDocumentWrapper.writeToParcel(dest, flags); dest.writeBundle(mExtras); - dest.writeInt(mResultCode); - dest.writeString8(mErrorMessage); } - - /** - * Result codes. - * - * @hide - */ - @IntDef( - prefix = {"RESULT_"}, - value = { - RESULT_OK, - RESULT_DENIED, - RESULT_APP_UNKNOWN_ERROR, - RESULT_FUNCTION_NOT_FOUND, - RESULT_SYSTEM_ERROR, - RESULT_INVALID_ARGUMENT, - RESULT_DISABLED, - RESULT_CANCELLED - }) - @Retention(RetentionPolicy.SOURCE) - public @interface ResultCode {} - - /** - * Error categories. - * - * @hide - */ - @IntDef( - prefix = {"ERROR_CATEGORY_"}, - value = { - ERROR_CATEGORY_UNKNOWN, - ERROR_CATEGORY_REQUEST_ERROR, - ERROR_CATEGORY_APP, - ERROR_CATEGORY_SYSTEM - }) - @Retention(RetentionPolicy.SOURCE) - public @interface ErrorCategory {} } diff --git a/core/java/android/app/appfunctions/GenericDocumentWrapper.java b/core/java/android/app/appfunctions/GenericDocumentWrapper.java index b29b64e44d21cea1bfd203e8a9eac33aa47848c9..541ca7458efe47bcea4a7d819318ce26717221ae 100644 --- a/core/java/android/app/appfunctions/GenericDocumentWrapper.java +++ b/core/java/android/app/appfunctions/GenericDocumentWrapper.java @@ -34,9 +34,9 @@ import java.util.Objects; *

{#link {@link Parcel#writeBlob(byte[])}} could take care of whether to pass data via binder * directly or Android shared memory if the data is large. * - *

This class performs lazy unparcelling. The `GenericDocument` is only unparcelled - * from the underlying `Parcel` when {@link #getValue()} is called. This optimization - * allows the system server to pass through the generic document, without unparcel and parcel it. + *

This class performs lazy unparcelling. The `GenericDocument` is only unparcelled from the + * underlying `Parcel` when {@link #getValue()} is called. This optimization allows the system + * server to pass through the generic document, without unparcel and parcel it. * * @hide * @see Parcel#writeBlob(byte[]) @@ -45,8 +45,11 @@ public final class GenericDocumentWrapper implements Parcelable { @Nullable @GuardedBy("mLock") private GenericDocument mGenericDocument; + @GuardedBy("mLock") - @Nullable private Parcel mParcel; + @Nullable + private Parcel mParcel; + private final Object mLock = new Object(); public static final Creator CREATOR = diff --git a/core/java/android/app/appfunctions/IExecuteAppFunctionCallback.aidl b/core/java/android/app/appfunctions/IExecuteAppFunctionCallback.aidl index 5323f9b627e3ee715839e436cf416a916b117a1e..69bbc0e5d27560eb1b1378c1cca1ba931827d44d 100644 --- a/core/java/android/app/appfunctions/IExecuteAppFunctionCallback.aidl +++ b/core/java/android/app/appfunctions/IExecuteAppFunctionCallback.aidl @@ -17,8 +17,10 @@ package android.app.appfunctions; import android.app.appfunctions.ExecuteAppFunctionResponse; +import android.app.appfunctions.AppFunctionException; /** {@hide} */ oneway interface IExecuteAppFunctionCallback { - void onResult(in ExecuteAppFunctionResponse result); + void onSuccess(in ExecuteAppFunctionResponse result); + void onError(in AppFunctionException exception); } diff --git a/core/java/android/app/appfunctions/SafeOneTimeExecuteAppFunctionCallback.java b/core/java/android/app/appfunctions/SafeOneTimeExecuteAppFunctionCallback.java index 00182447e9a808bc61104d9722d257cc7e6a6419..2426daf5c9f299df511952b0f436971aa2280c8f 100644 --- a/core/java/android/app/appfunctions/SafeOneTimeExecuteAppFunctionCallback.java +++ b/core/java/android/app/appfunctions/SafeOneTimeExecuteAppFunctionCallback.java @@ -17,17 +17,16 @@ package android.app.appfunctions; import android.annotation.NonNull; -import android.annotation.Nullable; import android.os.RemoteException; import android.util.Log; import java.util.Objects; import java.util.concurrent.atomic.AtomicBoolean; -import java.util.function.Consumer; /** * A wrapper of IExecuteAppFunctionCallback which swallows the {@link RemoteException}. This - * callback is intended for one-time use only. Subsequent calls to onResult() will be ignored. + * callback is intended for one-time use only. Subsequent calls to onResult() or onError() will be + * ignored. * * @hide */ @@ -38,44 +37,41 @@ public class SafeOneTimeExecuteAppFunctionCallback { @NonNull private final IExecuteAppFunctionCallback mCallback; - @Nullable private final Consumer mOnDispatchCallback; - public SafeOneTimeExecuteAppFunctionCallback(@NonNull IExecuteAppFunctionCallback callback) { - this(callback, /* onDispatchCallback= */ null); - } - - /** - * @param callback The callback to wrap. - * @param onDispatchCallback An optional callback invoked after the wrapped callback has been - * dispatched with a result. This callback receives the result that has been dispatched. - */ - public SafeOneTimeExecuteAppFunctionCallback( - @NonNull IExecuteAppFunctionCallback callback, - @Nullable Consumer onDispatchCallback) { mCallback = Objects.requireNonNull(callback); - mOnDispatchCallback = onDispatchCallback; } /** Invoke wrapped callback with the result. */ public void onResult(@NonNull ExecuteAppFunctionResponse result) { if (!mOnResultCalled.compareAndSet(false, true)) { - Log.w(TAG, "Ignore subsequent calls to onResult()"); + Log.w(TAG, "Ignore subsequent calls to onResult/onError()"); return; } try { - mCallback.onResult(result); + mCallback.onSuccess(result); } catch (RemoteException ex) { // Failed to notify the other end. Ignore. Log.w(TAG, "Failed to invoke the callback", ex); } - if (mOnDispatchCallback != null) { - mOnDispatchCallback.accept(result); + } + + /** Invoke wrapped callback with the error. */ + public void onError(@NonNull AppFunctionException error) { + if (!mOnResultCalled.compareAndSet(false, true)) { + Log.w(TAG, "Ignore subsequent calls to onResult/onError()"); + return; + } + try { + mCallback.onError(error); + } catch (RemoteException ex) { + // Failed to notify the other end. Ignore. + Log.w(TAG, "Failed to invoke the callback", ex); } } /** - * Disables this callback. Subsequent calls to {@link #onResult(ExecuteAppFunctionResponse)} - * will be ignored. + * Disables this callback. Subsequent calls to {@link #onResult(ExecuteAppFunctionResponse)} or + * {@link #onError(AppFunctionException)} will be ignored. */ public void disable() { mOnResultCalled.set(true); diff --git a/core/java/android/app/assist/AssistContent.java b/core/java/android/app/assist/AssistContent.java index a48868906487b1277ad22c0c1a87bcdf57a1abb3..43a46ba7885d112000775a928d3ef78dc3dd4622 100644 --- a/core/java/android/app/assist/AssistContent.java +++ b/core/java/android/app/assist/AssistContent.java @@ -1,5 +1,6 @@ package android.app.assist; +import android.annotation.FlaggedApi; import android.compat.annotation.UnsupportedAppUsage; import android.content.ClipData; import android.content.Intent; @@ -15,6 +16,20 @@ import android.os.Parcelable; * {@link android.app.Activity#onProvideAssistContent Activity.onProvideAssistContent}. */ public class AssistContent implements Parcelable { + /** + * Extra for a {@link Bundle} that provides contextual AppFunction's information about the + * content currently being viewed in the application. + *

+ * This extra can be optionally supplied in the {@link AssistContent#getExtras()} bundle. + *

+ * The schema of the {@link Bundle} in this extra is defined in the AppFunction SDK. + * + * @see android.app.appfunctions.AppFunctionManager + */ + @FlaggedApi(android.app.appfunctions.flags.Flags.FLAG_ENABLE_APP_FUNCTION_MANAGER) + public static final String EXTRA_APP_FUNCTION_DATA = + "android.app.assist.extra.APP_FUNCTION_DATA"; + @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023) private boolean mIsAppProvidedIntent = false; private boolean mIsAppProvidedWebUri = false; diff --git a/core/java/android/app/compat/ChangeIdStateCache.java b/core/java/android/app/compat/ChangeIdStateCache.java index db663f8ed4c4c08cb74fa56b323933b191fb3e0f..7d21cbf955d9117fe55f830ee7fae64c0cb3c62e 100644 --- a/core/java/android/app/compat/ChangeIdStateCache.java +++ b/core/java/android/app/compat/ChangeIdStateCache.java @@ -31,13 +31,24 @@ import com.android.internal.compat.IPlatformCompat; * Handles caching of calls to {@link com.android.internal.compat.IPlatformCompat} * @hide */ +@android.ravenwood.annotation.RavenwoodKeepWholeClass public final class ChangeIdStateCache extends PropertyInvalidatedCache { private static final String CACHE_KEY = createSystemCacheKey("is_compat_change_enabled"); private static final int MAX_ENTRIES = 2048; - private static boolean sDisabled = false; + private static boolean sDisabled = getDefaultDisabled(); private volatile IPlatformCompat mPlatformCompat; + + @android.ravenwood.annotation.RavenwoodReplace + private static boolean getDefaultDisabled() { + return false; + } + + private static boolean getDefaultDisabled$ravenwood() { + return true; // TODO(b/376676753) Disable the cache for now. + } + /** @hide */ public ChangeIdStateCache() { super(MAX_ENTRIES, CACHE_KEY); diff --git a/core/java/android/app/compat/ChangeIdStateQuery.java b/core/java/android/app/compat/ChangeIdStateQuery.java index 7598d6c90d3d8303de3cbf893fd69bcddbd465a2..26d9ab65417e78d2f43b9742d10627924be6df11 100644 --- a/core/java/android/app/compat/ChangeIdStateQuery.java +++ b/core/java/android/app/compat/ChangeIdStateQuery.java @@ -35,6 +35,7 @@ import java.util.Objects; * @hide */ @Immutable +@android.ravenwood.annotation.RavenwoodKeepWholeClass final class ChangeIdStateQuery { static final int QUERY_BY_PACKAGE_NAME = 0; diff --git a/core/java/android/app/compat/CompatChanges.java b/core/java/android/app/compat/CompatChanges.java index d7b2ab4351a4e7335cc9b05e67b44c33d2be2415..643d4c96f7b941b8df3695e68076f08555c36926 100644 --- a/core/java/android/app/compat/CompatChanges.java +++ b/core/java/android/app/compat/CompatChanges.java @@ -39,6 +39,7 @@ import java.util.Set; * @hide */ @SystemApi +@android.ravenwood.annotation.RavenwoodKeepWholeClass public final class CompatChanges { private static final ChangeIdStateCache QUERY_CACHE = new ChangeIdStateCache(); diff --git a/core/java/android/app/compat/PackageOverride.java b/core/java/android/app/compat/PackageOverride.java index ebc2945fb1a04f2e2162d82e6d69621380d64875..ffc1eec05667fcaf9185e9ce09c7981f33a0480b 100644 --- a/core/java/android/app/compat/PackageOverride.java +++ b/core/java/android/app/compat/PackageOverride.java @@ -36,6 +36,7 @@ import java.util.Objects; * @hide */ @SystemApi +@android.ravenwood.annotation.RavenwoodKeepWholeClass public final class PackageOverride { /** @hide */ diff --git a/core/java/android/app/jank/JankTracker.java b/core/java/android/app/jank/JankTracker.java new file mode 100644 index 0000000000000000000000000000000000000000..df422e0069c5a9f5a73ee07a2bd773ffffc26e29 --- /dev/null +++ b/core/java/android/app/jank/JankTracker.java @@ -0,0 +1,219 @@ +/* + * 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.app.jank; + +import android.annotation.FlaggedApi; +import android.annotation.NonNull; +import android.os.Handler; +import android.os.HandlerThread; +import android.view.AttachedSurfaceControl; +import android.view.Choreographer; +import android.view.SurfaceControl; +import android.view.View; +import android.view.ViewTreeObserver; + +import com.android.internal.annotations.VisibleForTesting; + +import java.util.ArrayList; + +/** + * This class is responsible for registering callbacks that will receive JankData batches. + * It handles managing the background thread that JankData will be processed on. As well as acting + * as an intermediary between widgets and the state tracker, routing state changes to the tracker. + * @hide + */ +@FlaggedApi(Flags.FLAG_DETAILED_APP_JANK_METRICS_API) +public class JankTracker { + + // Tracks states reported by widgets. + private StateTracker mStateTracker; + // Processes JankData batches and associates frames to widget states. + private JankDataProcessor mJankDataProcessor; + + // Background thread responsible for processing JankData batches. + private HandlerThread mHandlerThread = new HandlerThread("AppJankTracker"); + private Handler mHandler = null; + + // Needed so we know when the view is attached to a window. + private ViewTreeObserver mViewTreeObserver; + + // Handle to a registered OnJankData listener. + private SurfaceControl.OnJankDataListenerRegistration mJankDataListenerRegistration; + + // The interface to the windowing system that enables us to register for JankData. + private AttachedSurfaceControl mSurfaceControl; + // Name of the activity that is currently tracking Jank metrics. + private String mActivityName; + // The apps uid. + private int mAppUid; + // View that gives us access to ViewTreeObserver. + private View mDecorView; + + /** + * Set by the activity to enable or disable jank tracking. Activities may disable tracking if + * they are paused or not enable tracking if they are not visible or if the app category is not + * set. + */ + private boolean mTrackingEnabled = false; + /** + * Set to true once listeners are registered and JankData will start to be received. Both + * mTrackingEnabled and mListenersRegistered need to be true for JankData to be processed. + */ + private boolean mListenersRegistered = false; + + + public JankTracker(Choreographer choreographer, View decorView) { + mStateTracker = new StateTracker(choreographer); + mJankDataProcessor = new JankDataProcessor(mStateTracker); + mDecorView = decorView; + mHandlerThread.start(); + registerWindowListeners(); + } + + public void setActivityName(@NonNull String activityName) { + mActivityName = activityName; + } + + public void setAppUid(int uid) { + mAppUid = uid; + } + + /** + * Will add the widget category, id and state as a UI state to associate frames to it. + * @param widgetCategory preselected general widget category + * @param widgetId developer defined widget id if available. + * @param widgetState the current active widget state. + */ + public void addUiState(String widgetCategory, String widgetId, String widgetState) { + if (!shouldTrack()) return; + + mStateTracker.putState(widgetCategory, widgetId, widgetState); + } + + /** + * Will remove the widget category, id and state as a ui state and no longer attribute frames + * to it. + * @param widgetCategory preselected general widget category + * @param widgetId developer defined widget id if available. + * @param widgetState no longer active widget state. + */ + public void removeUiState(String widgetCategory, String widgetId, String widgetState) { + if (!shouldTrack()) return; + + mStateTracker.removeState(widgetCategory, widgetId, widgetState); + } + + /** + * Call to update a jank state to a different state. + * @param widgetCategory preselected general widget category. + * @param widgetId developer defined widget id if available. + * @param currentState current state of the widget. + * @param nextState the state the widget will be in. + */ + public void updateUiState(String widgetCategory, String widgetId, String currentState, + String nextState) { + if (!shouldTrack()) return; + + mStateTracker.updateState(widgetCategory, widgetId, currentState, nextState); + } + + /** + * Will enable jank tracking, and add the activity as a state to associate frames to. + */ + public void enableAppJankTracking() { + // Add the activity as a state, this will ensure we track frames to the activity without the + // need of a decorated widget to be used. + // TODO b/376116199 replace "NONE" with UNSPECIFIED once the API changes are merged. + mStateTracker.putState("NONE", mActivityName, "NONE"); + mTrackingEnabled = true; + } + + /** + * Will disable jank tracking, and remove the activity as a state to associate frames to. + */ + public void disableAppJankTracking() { + mTrackingEnabled = false; + // TODO b/376116199 replace "NONE" with UNSPECIFIED once the API changes are merged. + mStateTracker.removeState("NONE", mActivityName, "NONE"); + } + + /** + * Retrieve all pending widget states, this is intended for testing purposes only. + * @param stateDataList the ArrayList that will be populated with the pending states. + */ + @VisibleForTesting + public void getAllUiStates(@NonNull ArrayList stateDataList) { + mStateTracker.retrieveAllStates(stateDataList); + } + + /** + * Only intended to be used by tests, the runnable that registers the listeners may not run + * in time for tests to pass. This forces them to run immediately. + */ + @VisibleForTesting + public void forceListenerRegistration() { + mSurfaceControl = mDecorView.getRootSurfaceControl(); + registerForJankData(); + // TODO b/376116199 Check if registration is good. + mListenersRegistered = true; + } + + private void registerForJankData() { + if (mSurfaceControl == null) return; + /* + TODO b/376115668 Register for JankData batches from new JankTracking API + */ + } + + private boolean shouldTrack() { + return mTrackingEnabled && mListenersRegistered; + } + + /** + * Need to know when the decor view gets attached to the window in order to get + * AttachedSurfaceControl. In order to register a callback for OnJankDataListener + * AttachedSurfaceControl needs to be created which only happens after onWindowAttached is + * called. This is why there is a delay in posting the runnable. + */ + private void registerWindowListeners() { + if (mDecorView == null) return; + mViewTreeObserver = mDecorView.getViewTreeObserver(); + mViewTreeObserver.addOnWindowAttachListener(new ViewTreeObserver.OnWindowAttachListener() { + @Override + public void onWindowAttached() { + getHandler().postDelayed(new Runnable() { + @Override + public void run() { + forceListenerRegistration(); + } + }, 1000); + } + + @Override + public void onWindowDetached() { + // TODO b/376116199 do we un-register the callback or just not process the data. + } + }); + } + + private Handler getHandler() { + if (mHandler == null) { + mHandler = new Handler(mHandlerThread.getLooper()); + } + return mHandler; + } +} diff --git a/core/java/android/app/multitasking.aconfig b/core/java/android/app/multitasking.aconfig index 9a645192a1557ab5935ebe2bb90a6a27606a6826..c8455c1f439f35e09cd509e99709030bf987f0ea 100644 --- a/core/java/android/app/multitasking.aconfig +++ b/core/java/android/app/multitasking.aconfig @@ -8,3 +8,11 @@ flag { description: "Enables PiP UI state callback on entering" bug: "303718131" } + +flag { + name: "enable_tv_implicit_enter_pip_restriction" + is_exported: true + namespace: "tv_system_ui" + description: "Enables restrictions to PiP entry on TV for setAutoEnterEnabled and lifecycle methods" + bug: "283115999" +} diff --git a/core/java/android/app/notification.aconfig b/core/java/android/app/notification.aconfig index 0fc4291d15ab504adb2be9b60e9205c93fc0949e..ee93870be0552378f66a9e34c368328a140e6af3 100644 --- a/core/java/android/app/notification.aconfig +++ b/core/java/android/app/notification.aconfig @@ -8,8 +8,7 @@ container: "system" flag { name: "notifications_redesign_app_icons" namespace: "systemui" - description: "Notifications Redesign: Use app icons in notification rows (not to be confused with" - " notifications_use_app_icons, notifications_use_app_icon_in_row which are just experiments)." + description: "Notifications Redesign: Use app icons in notification rows" bug: "371174789" } @@ -110,31 +109,6 @@ flag { } } -# vvv Prototypes for using app icons in notifications vvv - -flag { - name: "notifications_use_app_icon" - namespace: "systemui" - description: "Experiment to replace the small icon in a notification with the app icon. This includes the status bar, AOD, shelf and notification row itself." - bug: "335211019" -} - -flag { - name: "notifications_use_app_icon_in_row" - namespace: "systemui" - description: "Experiment to replace the small icon in a notification row with the app icon." - bug: "335211019" -} - -flag { - name: "notifications_use_monochrome_app_icon" - namespace: "systemui" - description: "Experiment to replace the notification icon in the status bar and shelf with the monochrome app icon, if available." - bug: "335211019" -} - -# ^^^ Prototypes for using app icons in notifications ^^^ - flag { name: "notification_expansion_optional" namespace: "systemui" diff --git a/core/java/android/app/performance.aconfig b/core/java/android/app/performance.aconfig index f51f748bc71fbd3974eae9411c1932baad917c99..61b53f97fea1658aa7b2a789917df41f7403efc9 100644 --- a/core/java/android/app/performance.aconfig +++ b/core/java/android/app/performance.aconfig @@ -18,3 +18,20 @@ flag { description: "Enforce PropertyInvalidatedCache.setTestMode() protocol" bug: "360897450" } + +flag { + namespace: "system_performance" + name: "pic_isolate_cache_by_uid" + is_fixed_read_only: true + description: "Ensure that different UIDs use different caches" + bug: "373752556" +} + +flag { + namespace: "system_performance" + name: "pic_isolated_cache_statistics" + is_fixed_read_only: true + description: "Collects statistics for cache UID isolation strategies" + bug: "373752556" +} + diff --git a/core/java/android/app/wallpaper/WallpaperDescription.java b/core/java/android/app/wallpaper/WallpaperDescription.java index c3d6340be41f3aa8b877601128df1a92e8b93a23..8ffda7242b373ddb42366919343c21fb85ca6efb 100644 --- a/core/java/android/app/wallpaper/WallpaperDescription.java +++ b/core/java/android/app/wallpaper/WallpaperDescription.java @@ -18,8 +18,6 @@ package android.app.wallpaper; import static android.app.Flags.FLAG_LIVE_WALLPAPER_CONTENT_HANDLING; -import static java.nio.charset.StandardCharsets.UTF_8; - import android.annotation.FlaggedApi; import android.app.WallpaperInfo; import android.content.ComponentName; @@ -31,7 +29,6 @@ import android.text.Html; import android.text.Spanned; import android.text.SpannedString; import android.util.Log; -import android.util.Xml; import androidx.annotation.NonNull; import androidx.annotation.Nullable; @@ -43,8 +40,6 @@ import org.xmlpull.v1.XmlPullParser; import org.xmlpull.v1.XmlPullParserException; import java.io.IOException; -import java.io.InputStream; -import java.io.OutputStream; import java.util.ArrayList; import java.util.Arrays; import java.util.List; @@ -154,46 +149,6 @@ public final class WallpaperDescription implements Parcelable { return Objects.hash(mComponent, mId); } - ////// Stream read/write - - /** - * Writes the content of the {@link WallpaperDescription} to a {@link OutputStream}. - * - *

The content can be read by {@link #readFromStream}. This method is intended for use by - * trusted apps only, and the format is not guaranteed to be stable.

- */ - public void writeToStream(@NonNull OutputStream outputStream) throws IOException { - TypedXmlSerializer serializer = Xml.newFastSerializer(); - serializer.setOutput(outputStream, UTF_8.name()); - serializer.startTag(null, "description"); - try { - saveToXml(serializer); - } catch (XmlPullParserException e) { - throw new IOException(e); - } - serializer.endTag(null, "description"); - serializer.flush(); - } - - /** - * Reads a {@link PersistableBundle} from an {@link InputStream}. - * - *

The stream must be generated by {@link #writeToStream}. This method is intended for use by - * trusted apps only, and the format is not guaranteed to be stable.

- */ - @NonNull - public static WallpaperDescription readFromStream(@NonNull InputStream inputStream) - throws IOException { - try { - TypedXmlPullParser parser = Xml.newFastPullParser(); - parser.setInput(inputStream, UTF_8.name()); - parser.next(); - return WallpaperDescription.restoreFromXml(parser); - } catch (XmlPullParserException e) { - throw new IOException(e); - } - } - ////// XML storage /** @hide */ diff --git a/core/java/android/appwidget/flags.aconfig b/core/java/android/appwidget/flags.aconfig index 940a4d208d993e9247e36fc6e424f49b7cafc53c..ce515761551c140b1bfd95bcdac78a6c280e939e 100644 --- a/core/java/android/appwidget/flags.aconfig +++ b/core/java/android/appwidget/flags.aconfig @@ -55,7 +55,7 @@ flag { name: "remote_views_proto" namespace: "app_widgets" description: "Enable support for persisting RemoteViews previews to Protobuf" - bug: "306546610" + bug: "364420494" } flag { diff --git a/core/java/android/companion/virtual/VirtualDeviceParams.java b/core/java/android/companion/virtual/VirtualDeviceParams.java index 65f9cbefb052fdfe363ba5162527bda2aefdf1d9..2be27dabcf901e00b709d54f63b192c4837a576b 100644 --- a/core/java/android/companion/virtual/VirtualDeviceParams.java +++ b/core/java/android/companion/virtual/VirtualDeviceParams.java @@ -160,7 +160,7 @@ public final class VirtualDeviceParams implements Parcelable { */ @IntDef(prefix = "POLICY_TYPE_", value = {POLICY_TYPE_SENSORS, POLICY_TYPE_AUDIO, POLICY_TYPE_RECENTS, POLICY_TYPE_ACTIVITY, POLICY_TYPE_CLIPBOARD, POLICY_TYPE_CAMERA, - POLICY_TYPE_BLOCKED_ACTIVITY}) + POLICY_TYPE_BLOCKED_ACTIVITY, POLICY_TYPE_DEFAULT_DEVICE_CAMERA_ACCESS}) @Retention(RetentionPolicy.SOURCE) @Target({ElementType.TYPE_PARAMETER, ElementType.TYPE_USE}) public @interface PolicyType {} @@ -301,6 +301,21 @@ public final class VirtualDeviceParams implements Parcelable { @FlaggedApi(android.companion.virtualdevice.flags.Flags.FLAG_ACTIVITY_CONTROL_API) public static final int POLICY_TYPE_BLOCKED_ACTIVITY = 6; + /** + * Tells the virtual device framework how to handle camera access of the default device by apps + * running on the virtual device. + * + *
    + *
  • {@link #DEVICE_POLICY_DEFAULT}: Default device camera access will be allowed. + *
  • {@link #DEVICE_POLICY_CUSTOM}: Default device camera access will be blocked. + *
+ * + * @see Context#DEVICE_ID_DEFAULT + */ + @FlaggedApi(android.companion.virtualdevice.flags.Flags + .FLAG_DEFAULT_DEVICE_CAMERA_ACCESS_POLICY) + public static final int POLICY_TYPE_DEFAULT_DEVICE_CAMERA_ACCESS = 7; + private final int mLockState; @NonNull private final ArraySet mUsersWithMatchingAccounts; @NavigationPolicy @@ -318,6 +333,8 @@ public final class VirtualDeviceParams implements Parcelable { @Nullable private final IVirtualSensorCallback mVirtualSensorCallback; private final int mAudioPlaybackSessionId; private final int mAudioRecordingSessionId; + private final long mDimDuration; + private final long mScreenOffTimeout; private VirtualDeviceParams( @LockState int lockState, @@ -333,7 +350,9 @@ public final class VirtualDeviceParams implements Parcelable { @NonNull List virtualSensorConfigs, @Nullable IVirtualSensorCallback virtualSensorCallback, int audioPlaybackSessionId, - int audioRecordingSessionId) { + int audioRecordingSessionId, + long dimDuration, + long screenOffTimeout) { mLockState = lockState; mUsersWithMatchingAccounts = new ArraySet<>(Objects.requireNonNull(usersWithMatchingAccounts)); @@ -351,6 +370,8 @@ public final class VirtualDeviceParams implements Parcelable { mVirtualSensorCallback = virtualSensorCallback; mAudioPlaybackSessionId = audioPlaybackSessionId; mAudioRecordingSessionId = audioRecordingSessionId; + mDimDuration = dimDuration; + mScreenOffTimeout = screenOffTimeout; } @SuppressWarnings("unchecked") @@ -371,6 +392,8 @@ public final class VirtualDeviceParams implements Parcelable { mAudioRecordingSessionId = parcel.readInt(); mHomeComponent = parcel.readTypedObject(ComponentName.CREATOR); mInputMethodComponent = parcel.readTypedObject(ComponentName.CREATOR); + mDimDuration = parcel.readLong(); + mScreenOffTimeout = parcel.readLong(); } /** @@ -381,6 +404,26 @@ public final class VirtualDeviceParams implements Parcelable { return mLockState; } + /** + * Returns the dim duration for the displays of this device. + * + * @see Builder#setDimDuration(Duration) + */ + @FlaggedApi(android.companion.virtualdevice.flags.Flags.FLAG_DEVICE_AWARE_DISPLAY_POWER) + public @NonNull Duration getDimDuration() { + return Duration.ofMillis(mDimDuration); + } + + /** + * Returns the screen off timeout of the displays of this device. + * + * @see Builder#setDimDuration(Duration) + */ + @FlaggedApi(android.companion.virtualdevice.flags.Flags.FLAG_DEVICE_AWARE_DISPLAY_POWER) + public @NonNull Duration getScreenOffTimeout() { + return Duration.ofMillis(mScreenOffTimeout); + } + /** * Returns the custom component used as home on all displays owned by this virtual device that * support home activities. @@ -604,6 +647,8 @@ public final class VirtualDeviceParams implements Parcelable { dest.writeInt(mAudioRecordingSessionId); dest.writeTypedObject(mHomeComponent, flags); dest.writeTypedObject(mInputMethodComponent, flags); + dest.writeLong(mDimDuration); + dest.writeLong(mScreenOffTimeout); } @Override @@ -638,7 +683,9 @@ public final class VirtualDeviceParams implements Parcelable { && Objects.equals(mHomeComponent, that.mHomeComponent) && Objects.equals(mInputMethodComponent, that.mInputMethodComponent) && mAudioPlaybackSessionId == that.mAudioPlaybackSessionId - && mAudioRecordingSessionId == that.mAudioRecordingSessionId; + && mAudioRecordingSessionId == that.mAudioRecordingSessionId + && mDimDuration == that.mDimDuration + && mScreenOffTimeout == that.mScreenOffTimeout; } @Override @@ -647,7 +694,7 @@ public final class VirtualDeviceParams implements Parcelable { mLockState, mUsersWithMatchingAccounts, mCrossTaskNavigationExemptions, mDefaultNavigationPolicy, mActivityPolicyExemptions, mDefaultActivityPolicy, mName, mDevicePolicies, mHomeComponent, mInputMethodComponent, mAudioPlaybackSessionId, - mAudioRecordingSessionId); + mAudioRecordingSessionId, mDimDuration, mScreenOffTimeout); for (int i = 0; i < mDevicePolicies.size(); i++) { hashCode = 31 * hashCode + mDevicePolicies.keyAt(i); hashCode = 31 * hashCode + mDevicePolicies.valueAt(i); @@ -671,6 +718,8 @@ public final class VirtualDeviceParams implements Parcelable { + " mInputMethodComponent=" + mInputMethodComponent + " mAudioPlaybackSessionId=" + mAudioPlaybackSessionId + " mAudioRecordingSessionId=" + mAudioRecordingSessionId + + " mDimDuration=" + mDimDuration + + " mScreenOffTimeout=" + mScreenOffTimeout + ")"; } @@ -692,11 +741,13 @@ public final class VirtualDeviceParams implements Parcelable { pw.println(prefix + "mInputMethodComponent=" + mInputMethodComponent); pw.println(prefix + "mAudioPlaybackSessionId=" + mAudioPlaybackSessionId); pw.println(prefix + "mAudioRecordingSessionId=" + mAudioRecordingSessionId); + pw.println(prefix + "mDimDuration=" + mDimDuration); + pw.println(prefix + "mScreenOffTimeout=" + mScreenOffTimeout); } @NonNull public static final Parcelable.Creator CREATOR = - new Parcelable.Creator() { + new Parcelable.Creator<>() { public VirtualDeviceParams createFromParcel(Parcel in) { return new VirtualDeviceParams(in); } @@ -711,6 +762,8 @@ public final class VirtualDeviceParams implements Parcelable { */ public static final class Builder { + private static final Duration INFINITE_TIMEOUT = Duration.ofDays(365 * 1000); + private @LockState int mLockState = LOCK_STATE_DEFAULT; @NonNull private Set mUsersWithMatchingAccounts = Collections.emptySet(); @NonNull private Set mCrossTaskNavigationExemptions = Collections.emptySet(); @@ -733,6 +786,8 @@ public final class VirtualDeviceParams implements Parcelable { @Nullable private VirtualSensorDirectChannelCallback mVirtualSensorDirectChannelCallback; @Nullable private ComponentName mHomeComponent; @Nullable private ComponentName mInputMethodComponent; + private Duration mDimDuration = Duration.ZERO; + private Duration mScreenOffTimeout = Duration.ZERO; private static class VirtualSensorCallbackDelegate extends IVirtualSensorCallback.Stub { @NonNull @@ -809,6 +864,57 @@ public final class VirtualDeviceParams implements Parcelable { return this; } + /** + * Sets the dim duration for all trusted non-mirror displays of the device. + * + *

The system will reduce the display brightness for the specified duration if there + * has been no interaction just before the displays turn off.

+ * + *

If set, the screen off timeout must also be set to a value larger than the dim + * duration. If left unset or set to zero, then the display brightness will not be reduced. + *

+ * + * @throws IllegalArgumentException if the dim duration is negative or if the dim duration + * is longer than the screen off timeout. + * @see android.hardware.display.DisplayManager#VIRTUAL_DISPLAY_FLAG_TRUSTED + * @see android.hardware.display.DisplayManager#VIRTUAL_DISPLAY_FLAG_AUTO_MIRROR + * @see #setScreenOffTimeout + */ + @FlaggedApi(android.companion.virtualdevice.flags.Flags.FLAG_DEVICE_AWARE_DISPLAY_POWER) + @NonNull + public Builder setDimDuration(@NonNull Duration dimDuration) { + if (Objects.requireNonNull(dimDuration).compareTo(Duration.ZERO) < 0) { + throw new IllegalArgumentException("The dim duration cannot be negative"); + } + mDimDuration = dimDuration; + return this; + } + + /** + * Sets the timeout, after which all trusted non-mirror displays of the device will turn + * off, if there has been no interaction with the device. + * + *

If dim duration is set, the screen off timeout must be set to a value larger than the + * dim duration. If left unset or set to zero, then the displays will never be turned off + * due to inactivity.

+ * + * @throws IllegalArgumentException if the screen off timeout is negative or if the dim + * duration is longer than the screen off timeout. + * @see android.hardware.display.DisplayManager#VIRTUAL_DISPLAY_FLAG_TRUSTED + * @see android.hardware.display.DisplayManager#VIRTUAL_DISPLAY_FLAG_AUTO_MIRROR + * @see #setDimDuration + * @see VirtualDeviceManager.VirtualDevice#goToSleep() + */ + @FlaggedApi(android.companion.virtualdevice.flags.Flags.FLAG_DEVICE_AWARE_DISPLAY_POWER) + @NonNull + public Builder setScreenOffTimeout(@NonNull Duration screenOffTimeout) { + if (Objects.requireNonNull(screenOffTimeout).compareTo(Duration.ZERO) < 0) { + throw new IllegalArgumentException("The screen off timeout cannot be negative"); + } + mScreenOffTimeout = screenOffTimeout; + return this; + } + /** * Specifies a component to be used as home on all displays owned by this virtual device * that support home activities. @@ -1205,6 +1311,14 @@ public final class VirtualDeviceParams implements Parcelable { } } + if (mDimDuration.compareTo(mScreenOffTimeout) > 0) { + throw new IllegalArgumentException( + "The dim duration cannot be greater than the screen off timeout."); + } + if (mScreenOffTimeout.compareTo(Duration.ZERO) == 0) { + mScreenOffTimeout = INFINITE_TIMEOUT; + } + if (!Flags.crossDeviceClipboard()) { mDevicePolicies.delete(POLICY_TYPE_CLIPBOARD); } @@ -1213,6 +1327,10 @@ public final class VirtualDeviceParams implements Parcelable { mDevicePolicies.delete(POLICY_TYPE_CAMERA); } + if (!android.companion.virtualdevice.flags.Flags.defaultDeviceCameraAccessPolicy()) { + mDevicePolicies.delete(POLICY_TYPE_DEFAULT_DEVICE_CAMERA_ACCESS); + } + if (!android.companion.virtualdevice.flags.Flags.activityControlApi()) { mDevicePolicies.delete(POLICY_TYPE_BLOCKED_ACTIVITY); } @@ -1250,7 +1368,9 @@ public final class VirtualDeviceParams implements Parcelable { mVirtualSensorConfigs, virtualSensorCallbackDelegate, mAudioPlaybackSessionId, - mAudioRecordingSessionId); + mAudioRecordingSessionId, + mDimDuration.toMillis(), + mScreenOffTimeout.toMillis()); } } } diff --git a/core/java/android/companion/virtual/flags.aconfig b/core/java/android/companion/virtual/flags.aconfig index fc9c94dd5b0f236fab32033a7447d6de091a146b..3e6919bac5fa6bd8f001767a938db3869efac83c 100644 --- a/core/java/android/companion/virtual/flags.aconfig +++ b/core/java/android/companion/virtual/flags.aconfig @@ -66,13 +66,6 @@ flag { bug: "270352264" } -flag { - name: "stream_camera" - namespace: "virtual_devices" - description: "Enable streaming camera to Virtual Devices" - bug: "291740640" -} - flag { name: "persistent_device_id_api" is_exported: true diff --git a/core/java/android/companion/virtual/flags/flags.aconfig b/core/java/android/companion/virtual/flags/flags.aconfig index 9af20164a66d148e9442fdf77396e2be1d21840d..c47fe236faf0b36a62392b2fe37f956ba1047451 100644 --- a/core/java/android/companion/virtual/flags/flags.aconfig +++ b/core/java/android/companion/virtual/flags/flags.aconfig @@ -153,3 +153,10 @@ flag { bug: "371173368" is_exported: true } + +flag { + name: "vdm_settings" + namespace: "virtual_devices" + description: "Show virtual devices in Settings" + bug: "338974320" +} diff --git a/core/java/android/content/Context.java b/core/java/android/content/Context.java index 186f7b3e111c64196a20450cb2f78c3fa5ec51cb..6086f2455a31200054c7fedbc4060321c3b1d74a 100644 --- a/core/java/android/content/Context.java +++ b/core/java/android/content/Context.java @@ -6801,6 +6801,12 @@ public abstract class Context { @FlaggedApi(android.media.tv.flags.Flags.FLAG_MEDIA_QUALITY_FW) public static final String MEDIA_QUALITY_SERVICE = "media_quality"; + /** + * Service to perform operations needed for dynamic instrumentation. + * @hide + */ + public static final String DYNAMIC_INSTRUMENTATION_SERVICE = "dynamic_instrumentation"; + /** * Determine whether the given permission is allowed for a particular * process and user ID running in the system. diff --git a/core/java/android/content/pm/IOnAppsChangedListener.aidl b/core/java/android/content/pm/IOnAppsChangedListener.aidl index 830cbe0e0dd00f01ff8222b67acf10d2fab47cb1..ade58c45b02401d0d8d8ec231ca978f9eb01f693 100644 --- a/core/java/android/content/pm/IOnAppsChangedListener.aidl +++ b/core/java/android/content/pm/IOnAppsChangedListener.aidl @@ -16,6 +16,7 @@ package android.content.pm; +import android.content.pm.LauncherUserInfo; import android.content.pm.ParceledListSlice; import android.os.Bundle; import android.os.UserHandle; @@ -34,4 +35,5 @@ oneway interface IOnAppsChangedListener { void onPackagesUnsuspended(in UserHandle user, in String[] packageNames); void onShortcutChanged(in UserHandle user, String packageName, in ParceledListSlice shortcuts); void onPackageLoadingProgressChanged(in UserHandle user, String packageName, float progress); + void onUserConfigChanged(in LauncherUserInfo launcherUserInfo); } diff --git a/core/java/android/content/pm/LauncherApps.java b/core/java/android/content/pm/LauncherApps.java index 26f919f99ee9c5248e79e4fd798496edede6606e..26b835689b67595abb9f4c1aad085709d780f12d 100644 --- a/core/java/android/content/pm/LauncherApps.java +++ b/core/java/android/content/pm/LauncherApps.java @@ -182,6 +182,8 @@ public class LauncherApps { */ public static final int FLAG_CACHE_PEOPLE_TILE_SHORTCUTS = 2; + private static final String LAUNCHER_USER_INFO_EXTRA_KEY = "launcher_user_info"; + /** @hide */ @IntDef(flag = false, prefix = { "FLAG_CACHE_" }, value = { FLAG_CACHE_NOTIFICATION_SHORTCUTS, @@ -349,6 +351,19 @@ public class LauncherApps { */ public void onPackageLoadingProgressChanged(@NonNull String packageName, @NonNull UserHandle user, float progress) {} + + /** + * Indicates {@link LauncherUserInfo} configs for a user have changed. The new + * {@link LauncherUserInfo} is given as a parameter. + * + * {@link LauncherUserInfo#getUserConfig} to get the updated user configs. + * + * @param launcherUserInfo The LauncherUserInfo of the user/profile whose configs have + * changed. + */ + @FlaggedApi(android.multiuser.Flags.FLAG_ADD_LAUNCHER_USER_CONFIG) + public void onUserConfigChanged(@NonNull LauncherUserInfo launcherUserInfo) { + } } /** @@ -2168,6 +2183,21 @@ public class LauncherApps { } } } + + public void onUserConfigChanged(LauncherUserInfo launcherUserInfo) { + if (DEBUG) { + if (Flags.allowPrivateProfile() + && android.multiuser.Flags.addLauncherUserConfig()) { + Log.d(TAG, "OnUserConfigChanged for user type " + launcherUserInfo.getUserType() + + ", new userConfig: " + launcherUserInfo.getUserConfig()); + } + } + synchronized (LauncherApps.this) { + for (CallbackMessageHandler callback : mCallbacks) { + callback.postOnUserConfigChanged(launcherUserInfo); + } + } + } }; /** @@ -2224,6 +2254,7 @@ public class LauncherApps { private static final int MSG_UNSUSPENDED = 7; private static final int MSG_SHORTCUT_CHANGED = 8; private static final int MSG_LOADING_PROGRESS_CHANGED = 9; + private static final int MSG_USER_CONFIG_CHANGED = 10; private final LauncherApps.Callback mCallback; @@ -2278,6 +2309,14 @@ public class LauncherApps { mCallback.onPackageLoadingProgressChanged(info.packageName, info.user, info.mLoadingProgress); break; + case MSG_USER_CONFIG_CHANGED: + if (Flags.allowPrivateProfile() + && android.multiuser.Flags.addLauncherUserConfig()) { + mCallback.onUserConfigChanged(Objects.requireNonNull( + info.launcherExtras.getParcelable(LAUNCHER_USER_INFO_EXTRA_KEY, + LauncherUserInfo.class))); + } + break; } } @@ -2353,6 +2392,13 @@ public class LauncherApps { info.mLoadingProgress = progress; obtainMessage(MSG_LOADING_PROGRESS_CHANGED, info).sendToTarget(); } + + public void postOnUserConfigChanged(LauncherUserInfo launcherUserInfo) { + CallbackInfo info = new CallbackInfo(); + info.launcherExtras = new Bundle(); + info.launcherExtras.putParcelable(LAUNCHER_USER_INFO_EXTRA_KEY, launcherUserInfo); + obtainMessage(MSG_USER_CONFIG_CHANGED, info).sendToTarget(); + } } /** diff --git a/core/java/android/content/pm/LauncherUserInfo.java b/core/java/android/content/pm/LauncherUserInfo.java index 8426f54d475486c076cf4dbe506a1c824f5d664b..574af5902e89053dd97cfa2a751a0fa7f07f53e9 100644 --- a/core/java/android/content/pm/LauncherUserInfo.java +++ b/core/java/android/content/pm/LauncherUserInfo.java @@ -18,6 +18,7 @@ package android.content.pm; import android.annotation.FlaggedApi; import android.annotation.NonNull; +import android.os.Bundle; import android.os.Flags; import android.os.Parcel; import android.os.Parcelable; @@ -31,11 +32,25 @@ import android.os.UserManager; @FlaggedApi(Flags.FLAG_ALLOW_PRIVATE_PROFILE) public final class LauncherUserInfo implements Parcelable { + /** + * A boolean extra indicating whether the private space entrypoint should be hidden when locked. + * + * @see #getUserConfig + */ + @FlaggedApi(android.multiuser.Flags.FLAG_ADD_LAUNCHER_USER_CONFIG) + public static final String PRIVATE_SPACE_ENTRYPOINT_HIDDEN = + "private_space_entrypoint_hidden"; + private final String mUserType; // Serial number for the user, should be same as in the {@link UserInfo} object. private final int mUserSerialNumber; + // Additional configs for the user, e.g., whether to hide the private space entrypoint when + // locked. + private final Bundle mUserConfig; + + /** * Returns type of the user as defined in {@link UserManager}. e.g., * {@link UserManager.USER_TYPE_PROFILE_MANAGED} or {@link UserManager.USER_TYPE_PROFILE_ClONE} @@ -49,6 +64,17 @@ public final class LauncherUserInfo implements Parcelable { return mUserType; } + /** + * Returns additional configs for this launcher user + * + * @see #PRIVATE_SPACE_ENTRYPOINT_HIDDEN + */ + @FlaggedApi(android.multiuser.Flags.FLAG_ADD_LAUNCHER_USER_CONFIG) + @NonNull + public Bundle getUserConfig() { + return mUserConfig; + } + /** * Returns serial number of user as returned by * {@link UserManager#getSerialNumberForUser(UserHandle)} @@ -63,6 +89,7 @@ public final class LauncherUserInfo implements Parcelable { private LauncherUserInfo(@NonNull Parcel in) { mUserType = in.readString16NoHelper(); mUserSerialNumber = in.readInt(); + mUserConfig = in.readBundle(Bundle.class.getClassLoader()); } @Override @@ -70,6 +97,7 @@ public final class LauncherUserInfo implements Parcelable { public void writeToParcel(@NonNull Parcel dest, int flags) { dest.writeString16NoHelper(mUserType); dest.writeInt(mUserSerialNumber); + dest.writeBundle(mUserConfig); } @Override @@ -99,23 +127,36 @@ public final class LauncherUserInfo implements Parcelable { private final String mUserType; private final int mUserSerialNumber; + private final Bundle mUserConfig; + + + @FlaggedApi(android.multiuser.Flags.FLAG_ADD_LAUNCHER_USER_CONFIG) + public Builder(@NonNull String userType, int userSerialNumber, @NonNull Bundle config) { + this.mUserType = userType; + this.mUserSerialNumber = userSerialNumber; + this.mUserConfig = config; + } public Builder(@NonNull String userType, int userSerialNumber) { this.mUserType = userType; this.mUserSerialNumber = userSerialNumber; + this.mUserConfig = new Bundle(); } /** * Builds the LauncherUserInfo object */ - @NonNull public LauncherUserInfo build() { - return new LauncherUserInfo(this.mUserType, this.mUserSerialNumber); + @NonNull + public LauncherUserInfo build() { + return new LauncherUserInfo(this.mUserType, this.mUserSerialNumber, this.mUserConfig); } } // End builder - private LauncherUserInfo(@NonNull String userType, int userSerialNumber) { + private LauncherUserInfo(@NonNull String userType, int userSerialNumber, + @NonNull Bundle config) { this.mUserType = userType; this.mUserSerialNumber = userSerialNumber; + this.mUserConfig = config; } } diff --git a/core/java/android/content/pm/ServiceInfo.java b/core/java/android/content/pm/ServiceInfo.java index 5b0cee75e59135232b9c42ebccaca9220e612894..4285b0a2b91afd5b669d4d79284cfdd6d20ebee5 100644 --- a/core/java/android/content/pm/ServiceInfo.java +++ b/core/java/android/content/pm/ServiceInfo.java @@ -251,6 +251,7 @@ public class ServiceInfo extends ComponentInfo * {@link android.Manifest.permission#NFC}, * {@link android.Manifest.permission#TRANSMIT_IR}, * {@link android.Manifest.permission#UWB_RANGING}, + * {@link android.Manifest.permission#RANGING}, * or has been granted the access to one of the attached USB devices/accessories. */ @RequiresPermission( @@ -267,6 +268,7 @@ public class ServiceInfo extends ComponentInfo Manifest.permission.NFC, Manifest.permission.TRANSMIT_IR, Manifest.permission.UWB_RANGING, + Manifest.permission.RANGING, }, conditional = true ) diff --git a/core/java/android/content/pm/flags.aconfig b/core/java/android/content/pm/flags.aconfig index 6f70586881bed1c2190f9f6a11a0061db76bf0e5..c424229f479bd3c3ed7265ca60ab1285fdee8596 100644 --- a/core/java/android/content/pm/flags.aconfig +++ b/core/java/android/content/pm/flags.aconfig @@ -349,3 +349,12 @@ flag { bug: "364760703" is_fixed_read_only: true } + +flag { + name: "cloud_compilation_pm" + is_exported: true + namespace: "art_mainline" + description: "Feature flag to enable the Cloud Compilation support on the package manager side." + bug: "377474232" + is_fixed_read_only: true +} diff --git a/core/java/android/content/pm/multiuser.aconfig b/core/java/android/content/pm/multiuser.aconfig index 528bde80cd3d560955a680398de0097dafff93be..3d89ce12dec48283af807f8daa54ecbf39d2859f 100644 --- a/core/java/android/content/pm/multiuser.aconfig +++ b/core/java/android/content/pm/multiuser.aconfig @@ -543,3 +543,10 @@ flag { purpose: PURPOSE_BUGFIX } } + +flag { + name: "add_launcher_user_config" + namespace: "profile_experiences" + description: "Add support for LauncherUserInfo configs" + bug: "346553745" +} diff --git a/core/java/android/content/res/TEST_MAPPING b/core/java/android/content/res/TEST_MAPPING index c2febaeec73a1ca5a2bb0085969ec1d92ed618dd..e8893e47ddc8c2ff6cf1a3c8121c0f48a1573f77 100644 --- a/core/java/android/content/res/TEST_MAPPING +++ b/core/java/android/content/res/TEST_MAPPING @@ -5,6 +5,9 @@ }, { "path": "frameworks/base/core/tests/coretests/src/com/android/internal/content/res" + }, + { + "path": "platform_testing/libraries/screenshot" } ], "presubmit": [ diff --git a/core/java/android/content/res/flags.aconfig b/core/java/android/content/res/flags.aconfig index e98fc0c9d02ce8c674537cfc7c782060d841e1e1..f23c193e2da047cc7a1fb2681f65a80bafdf9961 100644 --- a/core/java/android/content/res/flags.aconfig +++ b/core/java/android/content/res/flags.aconfig @@ -83,3 +83,25 @@ flag { bug: "364035303" } +flag { + name: "system_context_handle_app_info_changed" + is_exported: true + namespace: "resource_manager" + description: "Feature flag for allowing system context to handle application info changes" + bug: "362420029" + # This flag is read at boot time. + is_fixed_read_only: true + metadata { + purpose: PURPOSE_BUGFIX + } +} + +flag { + name: "layout_readwrite_flags" + is_exported: true + namespace: "resource_manager" + description: "Feature flag for allowing read/write flags in layout files" + bug: "377974898" + # This flag is used to control aapt2 behavior. + is_fixed_read_only: true +} diff --git a/core/java/android/database/BulkCursorNative.java b/core/java/android/database/BulkCursorNative.java index 41585b3571d6f208e0bc0efa02245511104dc6f6..7d6e7ad857d13c57c8371b3e4047d3e02c04c113 100644 --- a/core/java/android/database/BulkCursorNative.java +++ b/core/java/android/database/BulkCursorNative.java @@ -215,7 +215,7 @@ final class BulkCursorProxy implements IBulkCursor { // If close() is being called from the finalizer thread, do not wait for a reply from // the remote side. final boolean fromFinalizer = - android.database.sqlite.Flags.onewayFinalizerClose() + android.database.sqlite.Flags.onewayFinalizerCloseFixed() && "FinalizerDaemon".equals(Thread.currentThread().getName()); mRemote.transact(CLOSE_TRANSACTION, data, reply, fromFinalizer ? IBinder.FLAG_ONEWAY: 0); diff --git a/core/java/android/database/CursorWindow.java b/core/java/android/database/CursorWindow.java index ef59e0af3a277d10104474ea75814381b36404bc..93ef5c3657301326974e7072d1520dc6a4be0a85 100644 --- a/core/java/android/database/CursorWindow.java +++ b/core/java/android/database/CursorWindow.java @@ -45,7 +45,7 @@ import dalvik.system.CloseGuard; *

*/ @RavenwoodKeepWholeClass -@RavenwoodRedirectionClass("CursorWindow_host") +@RavenwoodRedirectionClass("CursorWindow_ravenwood") public class CursorWindow extends SQLiteClosable implements Parcelable { private static final String STATS_TAG = "CursorWindowStats"; diff --git a/ravenwood/runtime-helper-src/framework/android/database/CursorWindow_host.java b/core/java/android/database/CursorWindow_ravenwood.java similarity index 90% rename from ravenwood/runtime-helper-src/framework/android/database/CursorWindow_host.java rename to core/java/android/database/CursorWindow_ravenwood.java index e21a9cd71a2d67c04b12f2dc71a6035535b45ba6..990ec5e9d59eb62ce5251ff8ea82759f961d2679 100644 --- a/ravenwood/runtime-helper-src/framework/android/database/CursorWindow_host.java +++ b/core/java/android/database/CursorWindow_ravenwood.java @@ -17,6 +17,7 @@ package android.database; import android.database.sqlite.SQLiteException; import android.os.Parcel; +import android.ravenwood.annotation.RavenwoodKeepWholeClass; import android.util.Base64; import java.text.DecimalFormat; @@ -26,9 +27,10 @@ import java.util.Arrays; import java.util.HashMap; import java.util.List; -public class CursorWindow_host { +@RavenwoodKeepWholeClass +class CursorWindow_ravenwood { - private static final HashMap sInstances = new HashMap<>(); + private static final HashMap sInstances = new HashMap<>(); private static long sNextId = 1; private String mName; @@ -41,7 +43,7 @@ public class CursorWindow_host { private final List mRows = new ArrayList<>(); public static long nativeCreate(String name, int cursorWindowSize) { - CursorWindow_host instance = new CursorWindow_host(); + CursorWindow_ravenwood instance = new CursorWindow_ravenwood(); instance.mName = name; long instanceId = sNextId++; sInstances.put(instanceId, instance); @@ -66,7 +68,7 @@ public class CursorWindow_host { } public static boolean nativeAllocRow(long windowPtr) { - CursorWindow_host instance = sInstances.get(windowPtr); + CursorWindow_ravenwood instance = sInstances.get(windowPtr); Row row = new Row(); row.mFields = new String[instance.mColumnNum]; row.mTypes = new int[instance.mColumnNum]; @@ -76,7 +78,7 @@ public class CursorWindow_host { } private static boolean put(long windowPtr, String value, int type, int row, int column) { - CursorWindow_host instance = sInstances.get(windowPtr); + CursorWindow_ravenwood instance = sInstances.get(windowPtr); if (row >= instance.mRows.size() || column >= instance.mColumnNum) { return false; } @@ -87,7 +89,7 @@ public class CursorWindow_host { } public static int nativeGetType(long windowPtr, int row, int column) { - CursorWindow_host instance = sInstances.get(windowPtr); + CursorWindow_ravenwood instance = sInstances.get(windowPtr); if (row >= instance.mRows.size() || column >= instance.mColumnNum) { return Cursor.FIELD_TYPE_NULL; } @@ -101,7 +103,7 @@ public class CursorWindow_host { } public static String nativeGetString(long windowPtr, int row, int column) { - CursorWindow_host instance = sInstances.get(windowPtr); + CursorWindow_ravenwood instance = sInstances.get(windowPtr); if (row >= instance.mRows.size() || column >= instance.mColumnNum) { return null; } @@ -164,7 +166,7 @@ public class CursorWindow_host { } public static void nativeWriteToParcel(long windowPtr, Parcel parcel) { - CursorWindow_host window = sInstances.get(windowPtr); + CursorWindow_ravenwood window = sInstances.get(windowPtr); parcel.writeString(window.mName); parcel.writeInt(window.mColumnNum); parcel.writeInt(window.mRows.size()); @@ -176,7 +178,7 @@ public class CursorWindow_host { public static long nativeCreateFromParcel(Parcel parcel) { long windowPtr = nativeCreate(null, 0); - CursorWindow_host window = sInstances.get(windowPtr); + CursorWindow_ravenwood window = sInstances.get(windowPtr); window.mName = parcel.readString(); window.mColumnNum = parcel.readInt(); int rowCount = parcel.readInt(); diff --git a/core/java/android/database/sqlite/flags.aconfig b/core/java/android/database/sqlite/flags.aconfig index 826b908e6775ffe945eab61f9e695553f62f9360..d43a66904af84b203da6a012368b2f1adfceaeef 100644 --- a/core/java/android/database/sqlite/flags.aconfig +++ b/core/java/android/database/sqlite/flags.aconfig @@ -2,8 +2,9 @@ package: "android.database.sqlite" container: "system" flag { - name: "oneway_finalizer_close" + name: "oneway_finalizer_close_fixed" namespace: "system_performance" + is_fixed_read_only: true description: "Make BuildCursorNative.close oneway if in the the finalizer" bug: "368221351" } diff --git a/core/java/android/hardware/DataSpace.java b/core/java/android/hardware/DataSpace.java index 611738435f7ed5f0b33b77b2b8338113ddf097cf..1cd9244333c5b1c2e66b571a3aea6f122ec4e7ee 100644 --- a/core/java/android/hardware/DataSpace.java +++ b/core/java/android/hardware/DataSpace.java @@ -420,18 +420,38 @@ public final class DataSpace { public static final int DATASPACE_HEIF = 4100; /** - * ISO/IEC TBD + * Ultra HDR * - * JPEG image with embedded recovery map following the Jpeg/R specification. + * JPEG image with embedded HDR gain map following the Ultra HDR specification and + * starting with Android version {@link android.os.Build.VERSION_CODES#VANILLA_ICE_CREAM V} + * ISO/CD 21496‐1 * - *

This value must always remain aligned with the public ImageFormat Jpeg/R definition and is - * valid with formats: - * HAL_PIXEL_FORMAT_BLOB: JPEG image encoded by Jpeg/R encoder according to ISO/IEC TBD. - * The image contains a standard SDR JPEG and a recovery map. Jpeg/R decoders can use the - * map to recover the input image.

+ *

This value is valid with formats:

+ *
    + *
  • HAL_PIXEL_FORMAT_BLOB: JPEG image encoded by Jpeg/R encoder according to + * ISO/CD 21496‐1
  • + *
+ *

+ * The image contains a standard SDR JPEG and a gain map. Ultra HDR decoders can use the + * gain map to boost the brightness of the rendered image.

*/ public static final int DATASPACE_JPEG_R = 4101; + /** + * ISO/IEC 23008-12:2024 + * + * High Efficiency Image File Format (HEIF) with embedded HDR gain map + * + *

This value is valid with formats:

+ *
    + *
  • HAL_PIXEL_FORMAT_BLOB: A HEIC image encoded by HEVC encoder + * according to ISO/IEC 23008-12:2024 that includes an HDR gain map and + * metadata according to ISO/CD 21496‐1.
  • + *
+ */ + @FlaggedApi(com.android.internal.camera.flags.Flags.FLAG_CAMERA_HEIF_GAINMAP) + public static final int DATASPACE_HEIF_ULTRAHDR = 4102; + /** @hide */ @Retention(RetentionPolicy.SOURCE) @IntDef(flag = true, value = { @@ -660,6 +680,7 @@ public final class DataSpace { DATASPACE_DEPTH, DATASPACE_DYNAMIC_DEPTH, DATASPACE_HEIF, + DATASPACE_HEIF_ULTRAHDR, DATASPACE_JPEG_R, DATASPACE_UNKNOWN, DATASPACE_SCRGB_LINEAR, diff --git a/core/java/android/hardware/camera2/CameraCharacteristics.java b/core/java/android/hardware/camera2/CameraCharacteristics.java index 16d82caa6c1ab561d91d7e5d81b42772b88a6580..a37648f7e45d85bc52589ec175449cf398f86a51 100644 --- a/core/java/android/hardware/camera2/CameraCharacteristics.java +++ b/core/java/android/hardware/camera2/CameraCharacteristics.java @@ -5774,6 +5774,122 @@ public final class CameraCharacteristics extends CameraMetadata HEIC_AVAILABLE_HEIC_STALL_DURATIONS_MAXIMUM_RESOLUTION = new Key("android.heic.availableHeicStallDurationsMaximumResolution", android.hardware.camera2.params.StreamConfigurationDuration[].class); + /** + *

The available HEIC (ISO/IEC 23008-12/24) UltraHDR stream + * configurations that this camera device supports + * (i.e. format, width, height, output/input stream).

+ *

The configurations are listed as (format, width, height, input?) tuples.

+ *

All the static, control, and dynamic metadata tags related to JPEG apply to HEIC formats. + * Configuring JPEG and HEIC streams at the same time is not supported.

+ *

Optional - The value for this key may be {@code null} on some devices.

+ *

Limited capability - + * Present on all camera devices that report being at least {@link CameraCharacteristics#INFO_SUPPORTED_HARDWARE_LEVEL_LIMITED HARDWARE_LEVEL_LIMITED} devices in the + * {@link CameraCharacteristics#INFO_SUPPORTED_HARDWARE_LEVEL android.info.supportedHardwareLevel} key

+ * + * @see CameraCharacteristics#INFO_SUPPORTED_HARDWARE_LEVEL + * @hide + */ + @FlaggedApi(Flags.FLAG_CAMERA_HEIF_GAINMAP) + public static final Key HEIC_AVAILABLE_HEIC_ULTRA_HDR_STREAM_CONFIGURATIONS = + new Key("android.heic.availableHeicUltraHdrStreamConfigurations", android.hardware.camera2.params.StreamConfiguration[].class); + + /** + *

This lists the minimum frame duration for each + * format/size combination for HEIC UltraHDR output formats.

+ *

This should correspond to the frame duration when only that + * stream is active, with all processing (typically in android.*.mode) + * set to either OFF or FAST.

+ *

When multiple streams are used in a request, the minimum frame + * duration will be max(individual stream min durations).

+ *

See {@link CaptureRequest#SENSOR_FRAME_DURATION android.sensor.frameDuration} and + * android.scaler.availableStallDurations for more details about + * calculating the max frame rate.

+ *

Units: (format, width, height, ns) x n

+ *

Optional - The value for this key may be {@code null} on some devices.

+ *

Limited capability - + * Present on all camera devices that report being at least {@link CameraCharacteristics#INFO_SUPPORTED_HARDWARE_LEVEL_LIMITED HARDWARE_LEVEL_LIMITED} devices in the + * {@link CameraCharacteristics#INFO_SUPPORTED_HARDWARE_LEVEL android.info.supportedHardwareLevel} key

+ * + * @see CameraCharacteristics#INFO_SUPPORTED_HARDWARE_LEVEL + * @see CaptureRequest#SENSOR_FRAME_DURATION + * @hide + */ + @FlaggedApi(Flags.FLAG_CAMERA_HEIF_GAINMAP) + public static final Key HEIC_AVAILABLE_HEIC_ULTRA_HDR_MIN_FRAME_DURATIONS = + new Key("android.heic.availableHeicUltraHdrMinFrameDurations", android.hardware.camera2.params.StreamConfigurationDuration[].class); + + /** + *

This lists the maximum stall duration for each + * output format/size combination for HEIC UltraHDR streams.

+ *

A stall duration is how much extra time would get added + * to the normal minimum frame duration for a repeating request + * that has streams with non-zero stall.

+ *

This functions similarly to + * android.scaler.availableStallDurations for HEIC UltraHDR + * streams.

+ *

All HEIC output stream formats may have a nonzero stall + * duration.

+ *

Units: (format, width, height, ns) x n

+ *

Optional - The value for this key may be {@code null} on some devices.

+ *

Limited capability - + * Present on all camera devices that report being at least {@link CameraCharacteristics#INFO_SUPPORTED_HARDWARE_LEVEL_LIMITED HARDWARE_LEVEL_LIMITED} devices in the + * {@link CameraCharacteristics#INFO_SUPPORTED_HARDWARE_LEVEL android.info.supportedHardwareLevel} key

+ * + * @see CameraCharacteristics#INFO_SUPPORTED_HARDWARE_LEVEL + * @hide + */ + @FlaggedApi(Flags.FLAG_CAMERA_HEIF_GAINMAP) + public static final Key HEIC_AVAILABLE_HEIC_ULTRA_HDR_STALL_DURATIONS = + new Key("android.heic.availableHeicUltraHdrStallDurations", android.hardware.camera2.params.StreamConfigurationDuration[].class); + + /** + *

The available HEIC (ISO/IEC 23008-12/24) UltraHDR stream + * configurations that this camera device supports + * (i.e. format, width, height, output/input stream) for CaptureRequests where + * {@link CaptureRequest#SENSOR_PIXEL_MODE android.sensor.pixelMode} is set to + * {@link android.hardware.camera2.CameraMetadata#SENSOR_PIXEL_MODE_MAXIMUM_RESOLUTION }.

+ *

Refer to android.heic.availableHeicStreamConfigurations for details.

+ *

Optional - The value for this key may be {@code null} on some devices.

+ * + * @see CaptureRequest#SENSOR_PIXEL_MODE + * @hide + */ + @FlaggedApi(Flags.FLAG_CAMERA_HEIF_GAINMAP) + public static final Key HEIC_AVAILABLE_HEIC_ULTRA_HDR_STREAM_CONFIGURATIONS_MAXIMUM_RESOLUTION = + new Key("android.heic.availableHeicUltraHdrStreamConfigurationsMaximumResolution", android.hardware.camera2.params.StreamConfiguration[].class); + + /** + *

This lists the minimum frame duration for each + * format/size combination for HEIC UltraHDR output formats for CaptureRequests where + * {@link CaptureRequest#SENSOR_PIXEL_MODE android.sensor.pixelMode} is set to + * {@link android.hardware.camera2.CameraMetadata#SENSOR_PIXEL_MODE_MAXIMUM_RESOLUTION }.

+ *

Refer to android.heic.availableHeicMinFrameDurations for details.

+ *

Units: (format, width, height, ns) x n

+ *

Optional - The value for this key may be {@code null} on some devices.

+ * + * @see CaptureRequest#SENSOR_PIXEL_MODE + * @hide + */ + @FlaggedApi(Flags.FLAG_CAMERA_HEIF_GAINMAP) + public static final Key HEIC_AVAILABLE_HEIC_ULTRA_HDR_MIN_FRAME_DURATIONS_MAXIMUM_RESOLUTION = + new Key("android.heic.availableHeicUltraHdrMinFrameDurationsMaximumResolution", android.hardware.camera2.params.StreamConfigurationDuration[].class); + + /** + *

This lists the maximum stall duration for each + * output format/size combination for HEIC UltraHDR streams for CaptureRequests where + * {@link CaptureRequest#SENSOR_PIXEL_MODE android.sensor.pixelMode} is set to + * {@link android.hardware.camera2.CameraMetadata#SENSOR_PIXEL_MODE_MAXIMUM_RESOLUTION }.

+ *

Refer to android.heic.availableHeicStallDurations for details.

+ *

Units: (format, width, height, ns) x n

+ *

Optional - The value for this key may be {@code null} on some devices.

+ * + * @see CaptureRequest#SENSOR_PIXEL_MODE + * @hide + */ + @FlaggedApi(Flags.FLAG_CAMERA_HEIF_GAINMAP) + public static final Key HEIC_AVAILABLE_HEIC_ULTRA_HDR_STALL_DURATIONS_MAXIMUM_RESOLUTION = + new Key("android.heic.availableHeicUltraHdrStallDurationsMaximumResolution", android.hardware.camera2.params.StreamConfigurationDuration[].class); + /** *

The direction of the camera faces relative to the vehicle body frame and the * passenger seats.

diff --git a/core/java/android/hardware/camera2/CameraMetadata.java b/core/java/android/hardware/camera2/CameraMetadata.java index 86bbd4a57a635f01306962b203540767ae424f10..2f6c6a3b02d804790e507ba7a8f17aec55cab84d 100644 --- a/core/java/android/hardware/camera2/CameraMetadata.java +++ b/core/java/android/hardware/camera2/CameraMetadata.java @@ -3370,6 +3370,32 @@ public abstract class CameraMetadata { */ public static final int CONTROL_AUTOFRAMING_AUTO = 2; + // + // Enumeration values for CaptureRequest#CONTROL_ZOOM_METHOD + // + + /** + *

The camera device automatically detects whether the application does zoom with + * {@link CaptureRequest#SCALER_CROP_REGION android.scaler.cropRegion} or {@link CaptureRequest#CONTROL_ZOOM_RATIO android.control.zoomRatio}, and in turn decides which + * metadata tag reflects the effective zoom level.

+ * + * @see CaptureRequest#CONTROL_ZOOM_RATIO + * @see CaptureRequest#SCALER_CROP_REGION + * @see CaptureRequest#CONTROL_ZOOM_METHOD + */ + @FlaggedApi(Flags.FLAG_ZOOM_METHOD) + public static final int CONTROL_ZOOM_METHOD_AUTO = 0; + + /** + *

The application intends to control zoom via {@link CaptureRequest#CONTROL_ZOOM_RATIO android.control.zoomRatio}, and + * the effective zoom level is reflected by {@link CaptureRequest#CONTROL_ZOOM_RATIO android.control.zoomRatio} in capture results.

+ * + * @see CaptureRequest#CONTROL_ZOOM_RATIO + * @see CaptureRequest#CONTROL_ZOOM_METHOD + */ + @FlaggedApi(Flags.FLAG_ZOOM_METHOD) + public static final int CONTROL_ZOOM_METHOD_ZOOM_RATIO = 1; + // // Enumeration values for CaptureRequest#EDGE_MODE // @@ -4289,6 +4315,39 @@ public abstract class CameraMetadata { */ public static final int SYNC_FRAME_NUMBER_UNKNOWN = -2; + // + // Enumeration values for CaptureResult#EXTENSION_NIGHT_MODE_INDICATOR + // + + /** + *

The camera can't accurately assess the scene's lighting to determine if a Night Mode + * Camera Extension capture would improve the photo. This can happen when the current + * camera configuration doesn't support night mode indicator detection, such as when + * the auto exposure mode is ON_AUTO_FLASH, ON_ALWAYS_FLASH, ON_AUTO_FLASH_REDEYE, or + * ON_EXTERNAL_FLASH.

+ * @see CaptureResult#EXTENSION_NIGHT_MODE_INDICATOR + */ + @FlaggedApi(Flags.FLAG_NIGHT_MODE_INDICATOR) + public static final int EXTENSION_NIGHT_MODE_INDICATOR_UNKNOWN = 0; + + /** + *

The camera has detected lighting conditions that are sufficiently bright. Night + * Mode Camera Extensions is available but may not be able to optimize the camera + * settings to take a higher quality photo.

+ * @see CaptureResult#EXTENSION_NIGHT_MODE_INDICATOR + */ + @FlaggedApi(Flags.FLAG_NIGHT_MODE_INDICATOR) + public static final int EXTENSION_NIGHT_MODE_INDICATOR_OFF = 1; + + /** + *

The camera has detected low-light conditions. It is recommended to use Night Mode + * Camera Extension to optimize the camera settings to take a high-quality photo in + * the dark.

+ * @see CaptureResult#EXTENSION_NIGHT_MODE_INDICATOR + */ + @FlaggedApi(Flags.FLAG_NIGHT_MODE_INDICATOR) + public static final int EXTENSION_NIGHT_MODE_INDICATOR_ON = 2; + /*~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~ * End generated code *~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~O@*/ diff --git a/core/java/android/hardware/camera2/CaptureRequest.java b/core/java/android/hardware/camera2/CaptureRequest.java index 8142bbe9b8386a3d8c164c7343c59c364f33f9e7..9846cac552120bb414e43b7fe1ee19271a19d500 100644 --- a/core/java/android/hardware/camera2/CaptureRequest.java +++ b/core/java/android/hardware/camera2/CaptureRequest.java @@ -21,7 +21,6 @@ import android.annotation.NonNull; import android.annotation.Nullable; import android.compat.annotation.UnsupportedAppUsage; import android.hardware.camera2.impl.CameraMetadataNative; -import android.hardware.camera2.impl.ExtensionKey; import android.hardware.camera2.impl.PublicKey; import android.hardware.camera2.impl.SyntheticKey; import android.hardware.camera2.params.OutputConfiguration; @@ -2667,6 +2666,45 @@ public final class CaptureRequest extends CameraMetadata> public static final Key CONTROL_AUTOFRAMING = new Key("android.control.autoframing", int.class); + /** + *

Whether the application uses {@link CaptureRequest#SCALER_CROP_REGION android.scaler.cropRegion} or {@link CaptureRequest#CONTROL_ZOOM_RATIO android.control.zoomRatio} + * to control zoom levels.

+ *

If set to AUTO, the camera device detects which capture request key the application uses + * to do zoom, {@link CaptureRequest#SCALER_CROP_REGION android.scaler.cropRegion} or {@link CaptureRequest#CONTROL_ZOOM_RATIO android.control.zoomRatio}. If + * the application doesn't set android.scaler.zoomRatio or sets it to 1.0 in the capture + * request, the effective zoom level is reflected in {@link CaptureRequest#SCALER_CROP_REGION android.scaler.cropRegion} in capture + * results. If {@link CaptureRequest#CONTROL_ZOOM_RATIO android.control.zoomRatio} is set to values other than 1.0, the effective + * zoom level is reflected in {@link CaptureRequest#CONTROL_ZOOM_RATIO android.control.zoomRatio}. AUTO is the default value + * for this control, and also the behavior of the OS before Android version + * {@link android.os.Build.VERSION_CODES#BAKLAVA BAKLAVA}.

+ *

If set to ZOOM_RATIO, the application explicitly specifies zoom level be controlled + * by {@link CaptureRequest#CONTROL_ZOOM_RATIO android.control.zoomRatio}, and the effective zoom level is reflected in + * {@link CaptureRequest#CONTROL_ZOOM_RATIO android.control.zoomRatio} in capture results. This addresses an ambiguity with AUTO, + * with which the camera device cannot know if the application is using cropRegion or + * zoomRatio at 1.0x.

+ *

Possible values:

+ *
    + *
  • {@link #CONTROL_ZOOM_METHOD_AUTO AUTO}
  • + *
  • {@link #CONTROL_ZOOM_METHOD_ZOOM_RATIO ZOOM_RATIO}
  • + *
+ * + *

Optional - The value for this key may be {@code null} on some devices.

+ *

Limited capability - + * Present on all camera devices that report being at least {@link CameraCharacteristics#INFO_SUPPORTED_HARDWARE_LEVEL_LIMITED HARDWARE_LEVEL_LIMITED} devices in the + * {@link CameraCharacteristics#INFO_SUPPORTED_HARDWARE_LEVEL android.info.supportedHardwareLevel} key

+ * + * @see CaptureRequest#CONTROL_ZOOM_RATIO + * @see CameraCharacteristics#INFO_SUPPORTED_HARDWARE_LEVEL + * @see CaptureRequest#SCALER_CROP_REGION + * @see #CONTROL_ZOOM_METHOD_AUTO + * @see #CONTROL_ZOOM_METHOD_ZOOM_RATIO + */ + @PublicKey + @NonNull + @FlaggedApi(Flags.FLAG_ZOOM_METHOD) + public static final Key CONTROL_ZOOM_METHOD = + new Key("android.control.zoomMethod", int.class); + /** *

Operation mode for edge * enhancement.

diff --git a/core/java/android/hardware/camera2/CaptureResult.java b/core/java/android/hardware/camera2/CaptureResult.java index ae72ca40fc5ac46158f81a47262cfb6592de54ef..674fc662aeacd98fa617de0eca04c613ae191856 100644 --- a/core/java/android/hardware/camera2/CaptureResult.java +++ b/core/java/android/hardware/camera2/CaptureResult.java @@ -22,7 +22,6 @@ import android.annotation.Nullable; import android.compat.annotation.UnsupportedAppUsage; import android.hardware.camera2.impl.CameraMetadataNative; import android.hardware.camera2.impl.CaptureResultExtras; -import android.hardware.camera2.impl.ExtensionKey; import android.hardware.camera2.impl.PublicKey; import android.hardware.camera2.impl.SyntheticKey; import android.hardware.camera2.utils.TypeReference; @@ -2914,6 +2913,45 @@ public class CaptureResult extends CameraMetadata> { public static final Key CONTROL_LOW_LIGHT_BOOST_STATE = new Key("android.control.lowLightBoostState", int.class); + /** + *

Whether the application uses {@link CaptureRequest#SCALER_CROP_REGION android.scaler.cropRegion} or {@link CaptureRequest#CONTROL_ZOOM_RATIO android.control.zoomRatio} + * to control zoom levels.

+ *

If set to AUTO, the camera device detects which capture request key the application uses + * to do zoom, {@link CaptureRequest#SCALER_CROP_REGION android.scaler.cropRegion} or {@link CaptureRequest#CONTROL_ZOOM_RATIO android.control.zoomRatio}. If + * the application doesn't set android.scaler.zoomRatio or sets it to 1.0 in the capture + * request, the effective zoom level is reflected in {@link CaptureRequest#SCALER_CROP_REGION android.scaler.cropRegion} in capture + * results. If {@link CaptureRequest#CONTROL_ZOOM_RATIO android.control.zoomRatio} is set to values other than 1.0, the effective + * zoom level is reflected in {@link CaptureRequest#CONTROL_ZOOM_RATIO android.control.zoomRatio}. AUTO is the default value + * for this control, and also the behavior of the OS before Android version + * {@link android.os.Build.VERSION_CODES#BAKLAVA BAKLAVA}.

+ *

If set to ZOOM_RATIO, the application explicitly specifies zoom level be controlled + * by {@link CaptureRequest#CONTROL_ZOOM_RATIO android.control.zoomRatio}, and the effective zoom level is reflected in + * {@link CaptureRequest#CONTROL_ZOOM_RATIO android.control.zoomRatio} in capture results. This addresses an ambiguity with AUTO, + * with which the camera device cannot know if the application is using cropRegion or + * zoomRatio at 1.0x.

+ *

Possible values:

+ *
    + *
  • {@link #CONTROL_ZOOM_METHOD_AUTO AUTO}
  • + *
  • {@link #CONTROL_ZOOM_METHOD_ZOOM_RATIO ZOOM_RATIO}
  • + *
+ * + *

Optional - The value for this key may be {@code null} on some devices.

+ *

Limited capability - + * Present on all camera devices that report being at least {@link CameraCharacteristics#INFO_SUPPORTED_HARDWARE_LEVEL_LIMITED HARDWARE_LEVEL_LIMITED} devices in the + * {@link CameraCharacteristics#INFO_SUPPORTED_HARDWARE_LEVEL android.info.supportedHardwareLevel} key

+ * + * @see CaptureRequest#CONTROL_ZOOM_RATIO + * @see CameraCharacteristics#INFO_SUPPORTED_HARDWARE_LEVEL + * @see CaptureRequest#SCALER_CROP_REGION + * @see #CONTROL_ZOOM_METHOD_AUTO + * @see #CONTROL_ZOOM_METHOD_ZOOM_RATIO + */ + @PublicKey + @NonNull + @FlaggedApi(Flags.FLAG_ZOOM_METHOD) + public static final Key CONTROL_ZOOM_METHOD = + new Key("android.control.zoomMethod", int.class); + /** *

Operation mode for edge * enhancement.

@@ -6016,6 +6054,38 @@ public class CaptureResult extends CameraMetadata> { public static final Key EXTENSION_STRENGTH = new Key("android.extension.strength", int.class); + /** + *

Indicates when to activate Night Mode Camera Extension for high-quality + * still captures in low-light conditions.

+ *

Provides awareness to the application when the current scene can benefit from using a + * Night Mode Camera Extension to take a high-quality photo.

+ *

Support for this capture result can be queried via + * {@link android.hardware.camera2.CameraCharacteristics#getAvailableCaptureResultKeys }.

+ *

If the device supports this capability then it will also support + * {@link android.hardware.camera2.CameraExtensionCharacteristics#EXTENSION_NIGHT NIGHT} + * and will be available in both + * {@link android.hardware.camera2.CameraCaptureSession sessions} and + * {@link android.hardware.camera2.CameraExtensionSession sessions}.

+ *

The value will be {@code UNKNOWN} in the following auto exposure modes: ON_AUTO_FLASH, + * ON_ALWAYS_FLASH, ON_AUTO_FLASH_REDEYE, or ON_EXTERNAL_FLASH.

+ *

Possible values:

+ *
    + *
  • {@link #EXTENSION_NIGHT_MODE_INDICATOR_UNKNOWN UNKNOWN}
  • + *
  • {@link #EXTENSION_NIGHT_MODE_INDICATOR_OFF OFF}
  • + *
  • {@link #EXTENSION_NIGHT_MODE_INDICATOR_ON ON}
  • + *
+ * + *

Optional - The value for this key may be {@code null} on some devices.

+ * @see #EXTENSION_NIGHT_MODE_INDICATOR_UNKNOWN + * @see #EXTENSION_NIGHT_MODE_INDICATOR_OFF + * @see #EXTENSION_NIGHT_MODE_INDICATOR_ON + */ + @PublicKey + @NonNull + @FlaggedApi(Flags.FLAG_NIGHT_MODE_INDICATOR) + public static final Key EXTENSION_NIGHT_MODE_INDICATOR = + new Key("android.extension.nightModeIndicator", int.class); + /*~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~ * End generated code *~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~O@*/ diff --git a/core/java/android/hardware/camera2/impl/CameraMetadataNative.java b/core/java/android/hardware/camera2/impl/CameraMetadataNative.java index ef7f3f8ab58bd73ee40adfcbc7924b887c7f34dd..1cc085658bfa30b8f408e3cd3b261b8361ea4d38 100644 --- a/core/java/android/hardware/camera2/impl/CameraMetadataNative.java +++ b/core/java/android/hardware/camera2/impl/CameraMetadataNative.java @@ -437,7 +437,7 @@ public class CameraMetadataNative implements Parcelable { } @Override - public void writeToParcel(Parcel dest, int flags) { + public synchronized void writeToParcel(Parcel dest, int flags) { nativeWriteToParcel(dest, mMetadataPtr); } @@ -479,7 +479,7 @@ public class CameraMetadataNative implements Parcelable { return getBase(key); } - public void readFromParcel(Parcel in) { + public synchronized void readFromParcel(Parcel in) { nativeReadFromParcel(in, mMetadataPtr); updateNativeAllocation(); } @@ -592,28 +592,33 @@ public class CameraMetadataNative implements Parcelable { } private T getBase(Key key) { - int tag; - if (key.hasTag()) { - tag = key.getTag(); - } else { - tag = nativeGetTagFromKeyLocal(mMetadataPtr, key.getName()); - key.cacheTag(tag); - } - byte[] values = readValues(tag); - if (values == null) { - // If the key returns null, use the fallback key if exists. - // This is to support old key names for the newly published keys. - if (key.mFallbackName == null) { - return null; + int tag, nativeType; + byte[] values = null; + synchronized (this) { + if (key.hasTag()) { + tag = key.getTag(); + } else { + tag = nativeGetTagFromKeyLocal(mMetadataPtr, key.getName()); + key.cacheTag(tag); } - tag = nativeGetTagFromKeyLocal(mMetadataPtr, key.mFallbackName); values = readValues(tag); if (values == null) { - return null; + // If the key returns null, use the fallback key if exists. + // This is to support old key names for the newly published keys. + if (key.mFallbackName == null) { + return null; + } + tag = nativeGetTagFromKeyLocal(mMetadataPtr, key.mFallbackName); + values = readValues(tag); + if (values == null) { + return null; + } } - } - int nativeType = nativeGetTypeFromTagLocal(mMetadataPtr, tag); + nativeType = nativeGetTypeFromTagLocal(mMetadataPtr, tag); + } + // This block of code doesn't need to be synchronized since we aren't writing or reading + // from the metadata buffer for this instance of CameraMetadataNative. Marshaler marshaler = getMarshalerForKey(key, nativeType); ByteBuffer buffer = ByteBuffer.wrap(values).order(ByteOrder.nativeOrder()); return marshaler.unmarshal(buffer); @@ -1385,6 +1390,9 @@ public class CameraMetadataNative implements Parcelable { /*jpegRconfiguration*/ null, /*jpegRminduration*/ null, /*jpegRstallduration*/ null, + /*heicUltraHDRconfiguration*/ null, + /*heicUltraHDRminduration*/ null, + /*heicUltraHDRstallduration*/ null, /*highspeedvideoconfigurations*/ null, /*inputoutputformatsmap*/ null, listHighResolution, supportsPrivate[i]); break; @@ -1402,6 +1410,9 @@ public class CameraMetadataNative implements Parcelable { /*jpegRconfiguration*/ null, /*jpegRminduration*/ null, /*jpegRstallduration*/ null, + /*heicUltraHDRconfiguration*/ null, + /*heicUltraHDRminduration*/ null, + /*heicUltraHDRstallduration*/ null, highSpeedVideoConfigurations, /*inputoutputformatsmap*/ null, listHighResolution, supportsPrivate[i]); break; @@ -1419,6 +1430,9 @@ public class CameraMetadataNative implements Parcelable { /*jpegRconfiguration*/ null, /*jpegRminduration*/ null, /*jpegRstallduration*/ null, + /*heicUltraHDRcconfiguration*/ null, + /*heicUltraHDRminduration*/ null, + /*heicUltraHDRstallduration*/ null, /*highSpeedVideoConfigurations*/ null, inputOutputFormatsMap, listHighResolution, supportsPrivate[i]); break; @@ -1436,6 +1450,9 @@ public class CameraMetadataNative implements Parcelable { /*jpegRconfiguration*/ null, /*jpegRminduration*/ null, /*jpegRstallduration*/ null, + /*heicUltraHDRcconfiguration*/ null, + /*heicUltraHDRminduration*/ null, + /*heicUltraHDRstallduration*/ null, /*highSpeedVideoConfigurations*/ null, /*inputOutputFormatsMap*/ null, listHighResolution, supportsPrivate[i]); } @@ -1607,6 +1624,17 @@ public class CameraMetadataNative implements Parcelable { CameraCharacteristics.HEIC_AVAILABLE_HEIC_MIN_FRAME_DURATIONS); StreamConfigurationDuration[] heicStallDurations = getBase( CameraCharacteristics.HEIC_AVAILABLE_HEIC_STALL_DURATIONS); + StreamConfiguration[] heicUltraHDRConfigurations = null; + StreamConfigurationDuration[] heicUltraHDRMinFrameDurations = null; + StreamConfigurationDuration[] heicUltraHDRStallDurations = null; + if (Flags.cameraHeifGainmap()) { + heicUltraHDRConfigurations = getBase( + CameraCharacteristics.HEIC_AVAILABLE_HEIC_ULTRA_HDR_STREAM_CONFIGURATIONS); + heicUltraHDRMinFrameDurations = getBase( + CameraCharacteristics.HEIC_AVAILABLE_HEIC_ULTRA_HDR_MIN_FRAME_DURATIONS); + heicUltraHDRStallDurations = getBase( + CameraCharacteristics.HEIC_AVAILABLE_HEIC_ULTRA_HDR_STALL_DURATIONS); + } StreamConfiguration[] jpegRConfigurations = getBase( CameraCharacteristics.JPEGR_AVAILABLE_JPEG_R_STREAM_CONFIGURATIONS); StreamConfigurationDuration[] jpegRMinFrameDurations = getBase( @@ -1625,7 +1653,8 @@ public class CameraMetadataNative implements Parcelable { dynamicDepthStallDurations, heicConfigurations, heicMinFrameDurations, heicStallDurations, jpegRConfigurations, jpegRMinFrameDurations, jpegRStallDurations, - highSpeedVideoConfigurations, inputOutputFormatsMap, + heicUltraHDRConfigurations, heicUltraHDRMinFrameDurations, + heicUltraHDRStallDurations, highSpeedVideoConfigurations, inputOutputFormatsMap, listHighResolution); } @@ -1662,6 +1691,17 @@ public class CameraMetadataNative implements Parcelable { CameraCharacteristics.HEIC_AVAILABLE_HEIC_MIN_FRAME_DURATIONS_MAXIMUM_RESOLUTION); StreamConfigurationDuration[] heicStallDurations = getBase( CameraCharacteristics.HEIC_AVAILABLE_HEIC_STALL_DURATIONS_MAXIMUM_RESOLUTION); + StreamConfiguration[] heicUltraHDRConfigurations = null; + StreamConfigurationDuration[] heicUltraHDRMinFrameDurations = null; + StreamConfigurationDuration[] heicUltraHDRStallDurations = null; + if (Flags.cameraHeifGainmap()) { + heicUltraHDRConfigurations = getBase( + CameraCharacteristics.HEIC_AVAILABLE_HEIC_ULTRA_HDR_STREAM_CONFIGURATIONS_MAXIMUM_RESOLUTION); + heicUltraHDRMinFrameDurations = getBase( + CameraCharacteristics.HEIC_AVAILABLE_HEIC_ULTRA_HDR_MIN_FRAME_DURATIONS_MAXIMUM_RESOLUTION); + heicUltraHDRStallDurations = getBase( + CameraCharacteristics.HEIC_AVAILABLE_HEIC_ULTRA_HDR_STALL_DURATIONS_MAXIMUM_RESOLUTION); + } StreamConfiguration[] jpegRConfigurations = getBase( CameraCharacteristics.JPEGR_AVAILABLE_JPEG_R_STREAM_CONFIGURATIONS_MAXIMUM_RESOLUTION); StreamConfigurationDuration[] jpegRMinFrameDurations = getBase( @@ -1681,7 +1721,8 @@ public class CameraMetadataNative implements Parcelable { dynamicDepthStallDurations, heicConfigurations, heicMinFrameDurations, heicStallDurations, jpegRConfigurations, jpegRMinFrameDurations, jpegRStallDurations, - highSpeedVideoConfigurations, inputOutputFormatsMap, + heicUltraHDRConfigurations, heicUltraHDRMinFrameDurations, + heicUltraHDRStallDurations, highSpeedVideoConfigurations, inputOutputFormatsMap, listHighResolution, false); } @@ -1909,8 +1950,12 @@ public class CameraMetadataNative implements Parcelable { setBase(key.getNativeKey(), value); } - private void setBase(Key key, T value) { - int tag; + // The whole method needs to be synchronized since we're making + // multiple calls to the native layer. From one call to the other (within setBase) + // we expect the metadata's properties such as vendor id etc to + // stay the same and as a result the whole method should be synchronized for safety. + private synchronized void setBase(Key key, T value) { + int tag, nativeType; if (key.hasTag()) { tag = key.getTag(); } else { @@ -1923,7 +1968,7 @@ public class CameraMetadataNative implements Parcelable { return; } // else update the entry to a new value - int nativeType = nativeGetTypeFromTagLocal(mMetadataPtr, tag); + nativeType = nativeGetTypeFromTagLocal(mMetadataPtr, tag); Marshaler marshaler = getMarshalerForKey(key, nativeType); int size = marshaler.calculateMarshalSize(value); @@ -2126,7 +2171,7 @@ public class CameraMetadataNative implements Parcelable { return true; } - private void updateNativeAllocation() { + private synchronized void updateNativeAllocation() { long currentBufferSize = nativeGetBufferSize(mMetadataPtr); if (currentBufferSize != mBufferSize) { @@ -2209,6 +2254,11 @@ public class CameraMetadataNative implements Parcelable { @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553) private long mMetadataPtr; // native std::shared_ptr* + // FastNative doesn't work with synchronized methods and we can do synchronization + // wherever needed in the java layer (caller). At some places in java such as + // setBase() / getBase(), we do need to synchronize the whole method, so leaving + // synchronized out for these native methods. + @FastNative private static native long nativeAllocate(); @FastNative @@ -2218,28 +2268,41 @@ public class CameraMetadataNative implements Parcelable { @FastNative private static native void nativeUpdate(long dst, long src); - private static synchronized native void nativeWriteToParcel(Parcel dest, long ptr); - private static synchronized native void nativeReadFromParcel(Parcel source, long ptr); - private static synchronized native void nativeSwap(long ptr, long otherPtr) + @FastNative + private static native void nativeWriteToParcel(Parcel dest, long ptr); + @FastNative + private static native void nativeReadFromParcel(Parcel source, long ptr); + @FastNative + private static native void nativeSwap(long ptr, long otherPtr) throws NullPointerException; @FastNative private static native void nativeSetVendorId(long ptr, long vendorId); - private static synchronized native void nativeClose(long ptr); - private static synchronized native boolean nativeIsEmpty(long ptr); - private static synchronized native int nativeGetEntryCount(long ptr); - private static synchronized native long nativeGetBufferSize(long ptr); + @FastNative + private static native void nativeClose(long ptr); + @FastNative + private static native boolean nativeIsEmpty(long ptr); + @FastNative + private static native int nativeGetEntryCount(long ptr); + @FastNative + private static native long nativeGetBufferSize(long ptr); @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553) - private static synchronized native byte[] nativeReadValues(int tag, long ptr); - private static synchronized native void nativeWriteValues(int tag, byte[] src, long ptr); - private static synchronized native void nativeDump(long ptr) throws IOException; // dump to LOGD + @FastNative + private static native byte[] nativeReadValues(int tag, long ptr); + @FastNative + private static native void nativeWriteValues(int tag, byte[] src, long ptr); + @FastNative + private static native void nativeDump(long ptr) throws IOException; // dump to LOGD - private static synchronized native ArrayList nativeGetAllVendorKeys(long ptr, Class keyClass); + @FastNative + private static native ArrayList nativeGetAllVendorKeys(long ptr, Class keyClass); @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553) - private static synchronized native int nativeGetTagFromKeyLocal(long ptr, String keyName) + @FastNative + private static native int nativeGetTagFromKeyLocal(long ptr, String keyName) throws IllegalArgumentException; @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553) - private static synchronized native int nativeGetTypeFromTagLocal(long ptr, int tag) + @FastNative + private static native int nativeGetTypeFromTagLocal(long ptr, int tag) throws IllegalArgumentException; @FastNative private static native int nativeGetTagFromKey(String keyName, long vendorId) @@ -2257,7 +2320,7 @@ public class CameraMetadataNative implements Parcelable { * @throws NullPointerException if other was null * @hide */ - public void swap(CameraMetadataNative other) { + public synchronized void swap(CameraMetadataNative other) { nativeSwap(mMetadataPtr, other.mMetadataPtr); mCameraId = other.mCameraId; mHasMandatoryConcurrentStreams = other.mHasMandatoryConcurrentStreams; @@ -2272,14 +2335,14 @@ public class CameraMetadataNative implements Parcelable { * * @hide */ - public void setVendorId(long vendorId) { + public synchronized void setVendorId(long vendorId) { nativeSetVendorId(mMetadataPtr, vendorId); } /** * @hide */ - public int getEntryCount() { + public synchronized int getEntryCount() { return nativeGetEntryCount(mMetadataPtr); } @@ -2288,7 +2351,7 @@ public class CameraMetadataNative implements Parcelable { * * @hide */ - public boolean isEmpty() { + public synchronized boolean isEmpty() { return nativeIsEmpty(mMetadataPtr); } @@ -2307,7 +2370,7 @@ public class CameraMetadataNative implements Parcelable { * * @hide */ - public ArrayList getAllVendorKeys(Class keyClass) { + public synchronized ArrayList getAllVendorKeys(Class keyClass) { if (keyClass == null) { throw new NullPointerException(); } @@ -2362,7 +2425,7 @@ public class CameraMetadataNative implements Parcelable { * * @hide */ - public void writeValues(int tag, byte[] src) { + public synchronized void writeValues(int tag, byte[] src) { nativeWriteValues(tag, src, mMetadataPtr); } @@ -2377,7 +2440,7 @@ public class CameraMetadataNative implements Parcelable { * @return {@code null} if there were 0 entries for this tag, a byte[] otherwise. * @hide */ - public byte[] readValues(int tag) { + public synchronized byte[] readValues(int tag) { // TODO: Optimization. Native code returns a ByteBuffer instead. return nativeReadValues(tag, mMetadataPtr); } @@ -2390,7 +2453,7 @@ public class CameraMetadataNative implements Parcelable { * * @hide */ - public void dumpToLog() { + public synchronized void dumpToLog() { try { nativeDump(mMetadataPtr); } catch (IOException e) { diff --git a/core/java/android/hardware/camera2/params/StreamConfigurationMap.java b/core/java/android/hardware/camera2/params/StreamConfigurationMap.java index e3dbb2bbbf909e06381f80a1641978b7675b33bd..ec028bf6dcbba0b17bca63f761bff58ae29ba458 100644 --- a/core/java/android/hardware/camera2/params/StreamConfigurationMap.java +++ b/core/java/android/hardware/camera2/params/StreamConfigurationMap.java @@ -20,6 +20,7 @@ import static com.android.internal.util.Preconditions.checkArrayElementsNotNull; import android.graphics.ImageFormat; import android.graphics.PixelFormat; +import android.hardware.DataSpace; import android.hardware.camera2.CameraCharacteristics; import android.hardware.camera2.CameraDevice; import android.hardware.camera2.CameraMetadata; @@ -31,6 +32,8 @@ 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.Objects; @@ -100,6 +103,12 @@ public final class StreamConfigurationMap { * {@link StreamConfigurationDuration} * @param jpegRStallDurations a non-{@code null} array of Jpeg/R * {@link StreamConfigurationDuration} + * @param heicUltraHDRConfigurations a non-{@code null} array of Heic UltraHDR + * {@link StreamConfiguration} + * @param heicUltraHDRMinFrameDurations a non-{@code null} array of Heic UltraHDR + * {@link StreamConfigurationDuration} + * @param heicUltraHDRStallDurations a non-{@code null} array of Heic UltraHDR + * {@link StreamConfigurationDuration} * @param highSpeedVideoConfigurations an array of {@link HighSpeedVideoConfiguration}, null if * camera device does not support high speed video recording * @param listHighResolution a flag indicating whether the device supports BURST_CAPTURE @@ -125,6 +134,9 @@ public final class StreamConfigurationMap { StreamConfiguration[] jpegRConfigurations, StreamConfigurationDuration[] jpegRMinFrameDurations, StreamConfigurationDuration[] jpegRStallDurations, + StreamConfiguration[] heicUltraHDRConfigurations, + StreamConfigurationDuration[] heicUltraHDRMinFrameDurations, + StreamConfigurationDuration[] heicUltraHDRStallDurations, HighSpeedVideoConfiguration[] highSpeedVideoConfigurations, ReprocessFormatsMap inputOutputFormatsMap, boolean listHighResolution) { @@ -134,8 +146,9 @@ public final class StreamConfigurationMap { dynamicDepthStallDurations, heicConfigurations, heicMinFrameDurations, heicStallDurations, jpegRConfigurations, jpegRMinFrameDurations, jpegRStallDurations, - highSpeedVideoConfigurations, inputOutputFormatsMap, listHighResolution, - /*enforceImplementationDefined*/ true); + heicUltraHDRConfigurations, heicUltraHDRMinFrameDurations, + heicUltraHDRStallDurations, highSpeedVideoConfigurations, inputOutputFormatsMap, + listHighResolution, /*enforceImplementationDefined*/ true); } /** @@ -168,6 +181,12 @@ public final class StreamConfigurationMap { * {@link StreamConfigurationDuration} * @param jpegRStallDurations a non-{@code null} array of Jpeg/R * {@link StreamConfigurationDuration} + * @param heicUltraHDRConfigurations an array of Heic UltraHDR + * {@link StreamConfiguration}, {@code null} if camera doesn't support the format + * @param heicUltraHDRMinFrameDurations an array of Heic UltraHDR + * {@link StreamConfigurationDuration}, {@code null} if camera doesn't support the format + * @param heicUltraHDRStallDurations an array of Heic UltraHDR + * {@link StreamConfigurationDuration}, {@code null} if camera doesn't support the format * @param highSpeedVideoConfigurations an array of {@link HighSpeedVideoConfiguration}, null if * camera device does not support high speed video recording * @param listHighResolution a flag indicating whether the device supports BURST_CAPTURE @@ -195,6 +214,9 @@ public final class StreamConfigurationMap { StreamConfiguration[] jpegRConfigurations, StreamConfigurationDuration[] jpegRMinFrameDurations, StreamConfigurationDuration[] jpegRStallDurations, + StreamConfiguration[] heicUltraHDRConfigurations, + StreamConfigurationDuration[] heicUltraHDRMinFrameDurations, + StreamConfigurationDuration[] heicUltraHDRStallDurations, HighSpeedVideoConfiguration[] highSpeedVideoConfigurations, ReprocessFormatsMap inputOutputFormatsMap, boolean listHighResolution, @@ -259,6 +281,18 @@ public final class StreamConfigurationMap { "heicStallDurations"); } + if (heicUltraHDRConfigurations == null || (!Flags.cameraHeifGainmap())) { + mHeicUltraHDRConfigurations = new StreamConfiguration[0]; + mHeicUltraHDRMinFrameDurations = new StreamConfigurationDuration[0]; + mHeicUltraHDRStallDurations = new StreamConfigurationDuration[0]; + } else { + mHeicUltraHDRConfigurations = checkArrayElementsNotNull(heicUltraHDRConfigurations, + "heicUltraHDRConfigurations"); + mHeicUltraHDRMinFrameDurations = checkArrayElementsNotNull( + heicUltraHDRMinFrameDurations, "heicUltraHDRMinFrameDurations"); + mHeicUltraHDRStallDurations = checkArrayElementsNotNull(heicUltraHDRStallDurations, + "heicUltraHDRStallDurations"); + } if (jpegRConfigurations == null) { mJpegRConfigurations = new StreamConfiguration[0]; @@ -336,6 +370,19 @@ public final class StreamConfigurationMap { mHeicOutputFormats.get(config.getFormat()) + 1); } + if (Flags.cameraHeifGainmap()) { + // For each Heic UlrtaHDR format, track how many sizes there are available to configure + for (StreamConfiguration config : mHeicUltraHDRConfigurations) { + if (!config.isOutput()) { + // Ignoring input Heic UltraHDR configs + continue; + } + + mHeicUltraHDROutputFormats.put(config.getFormat(), + mHeicUltraHDROutputFormats.get(config.getFormat()) + 1); + } + } + // For each Jpeg/R format, track how many sizes there are available to configure for (StreamConfiguration config : mJpegRConfigurations) { if (!config.isOutput()) { @@ -483,6 +530,11 @@ public final class StreamConfigurationMap { int internalFormat = imageFormatToInternal(format); int dataspace = imageFormatToDataspace(format); + if (Flags.cameraHeifGainmap()) { + if (dataspace == DataSpace.DATASPACE_HEIF_ULTRAHDR) { + return mHeicUltraHDROutputFormats.indexOfKey(internalFormat) >= 0; + } + } if (dataspace == HAL_DATASPACE_DEPTH) { return mDepthOutputFormats.indexOfKey(internalFormat) >= 0; } else if (dataspace == HAL_DATASPACE_DYNAMIC_DEPTH) { @@ -607,6 +659,11 @@ public final class StreamConfigurationMap { surfaceDataspace == HAL_DATASPACE_HEIF ? mHeicConfigurations : surfaceDataspace == HAL_DATASPACE_JPEG_R ? mJpegRConfigurations : mConfigurations; + if (Flags.cameraHeifGainmap()) { + if (surfaceDataspace == DataSpace.DATASPACE_HEIF_ULTRAHDR) { + configs = mHeicUltraHDRConfigurations; + } + } for (StreamConfiguration config : configs) { if (config.getFormat() == surfaceFormat && config.isOutput()) { // Matching format, either need exact size match, or a flexible consumer @@ -646,6 +703,11 @@ public final class StreamConfigurationMap { dataspace == HAL_DATASPACE_HEIF ? mHeicConfigurations : dataspace == HAL_DATASPACE_JPEG_R ? mJpegRConfigurations : mConfigurations; + if (Flags.cameraHeifGainmap()) { + if (dataspace == DataSpace.DATASPACE_HEIF_ULTRAHDR ) { + configs = mHeicUltraHDRConfigurations; + } + } for (StreamConfiguration config : configs) { if ((config.getFormat() == internalFormat) && config.isOutput() && config.getSize().equals(size)) { @@ -1176,6 +1238,10 @@ public final class StreamConfigurationMap { Arrays.equals(mHeicConfigurations, other.mHeicConfigurations) && Arrays.equals(mHeicMinFrameDurations, other.mHeicMinFrameDurations) && Arrays.equals(mHeicStallDurations, other.mHeicStallDurations) && + Arrays.equals(mHeicUltraHDRConfigurations, other.mHeicUltraHDRConfigurations) && + Arrays.equals(mHeicUltraHDRMinFrameDurations, + other.mHeicUltraHDRMinFrameDurations) && + Arrays.equals(mHeicUltraHDRStallDurations, other.mHeicUltraHDRStallDurations) && Arrays.equals(mJpegRConfigurations, other.mJpegRConfigurations) && Arrays.equals(mJpegRMinFrameDurations, other.mJpegRMinFrameDurations) && Arrays.equals(mJpegRStallDurations, other.mJpegRStallDurations) && @@ -1197,8 +1263,9 @@ public final class StreamConfigurationMap { mDynamicDepthConfigurations, mDynamicDepthMinFrameDurations, mDynamicDepthStallDurations, mHeicConfigurations, mHeicMinFrameDurations, mHeicStallDurations, - mJpegRConfigurations, mJpegRMinFrameDurations, mJpegRStallDurations, - mHighSpeedVideoConfigurations); + mHeicUltraHDRConfigurations, mHeicUltraHDRMinFrameDurations, + mHeicUltraHDRStallDurations, mJpegRConfigurations, mJpegRMinFrameDurations, + mJpegRStallDurations, mHighSpeedVideoConfigurations); } // Check that the argument is supported by #getOutputFormats or #getInputFormats @@ -1209,6 +1276,13 @@ public final class StreamConfigurationMap { int internalDataspace = imageFormatToDataspace(format); if (output) { + if (Flags.cameraHeifGainmap()) { + if (internalDataspace == DataSpace.DATASPACE_HEIF_ULTRAHDR) { + if (mHeicUltraHDROutputFormats.indexOfKey(internalFormat) >= 0) { + return format; + } + } + } if (internalDataspace == HAL_DATASPACE_DEPTH) { if (mDepthOutputFormats.indexOfKey(internalFormat) >= 0) { return format; @@ -1429,6 +1503,7 @@ public final class StreamConfigurationMap { *
  • ImageFormat.DEPTH_POINT_CLOUD => HAL_PIXEL_FORMAT_BLOB *
  • ImageFormat.DEPTH_JPEG => HAL_PIXEL_FORMAT_BLOB *
  • ImageFormat.HEIC => HAL_PIXEL_FORMAT_BLOB + *
  • ImageFormat.HEIC_ULTRAHDR => HAL_PIXEL_FORMAT_BLOB *
  • ImageFormat.JPEG_R => HAL_PIXEL_FORMAT_BLOB *
  • ImageFormat.DEPTH16 => HAL_PIXEL_FORMAT_Y16 * @@ -1451,6 +1526,11 @@ public final class StreamConfigurationMap { * if {@code format} was {@code HAL_PIXEL_FORMAT_IMPLEMENTATION_DEFINED} */ static int imageFormatToInternal(int format) { + if (Flags.cameraHeifGainmap()) { + if (format == ImageFormat.HEIC_ULTRAHDR) { + return HAL_PIXEL_FORMAT_BLOB; + } + } switch (format) { case ImageFormat.JPEG: case ImageFormat.DEPTH_POINT_CLOUD: @@ -1480,6 +1560,7 @@ public final class StreamConfigurationMap { *
  • ImageFormat.DEPTH16 => HAL_DATASPACE_DEPTH *
  • ImageFormat.DEPTH_JPEG => HAL_DATASPACE_DYNAMIC_DEPTH *
  • ImageFormat.HEIC => HAL_DATASPACE_HEIF + *
  • ImageFormat.HEIC_ULTRAHDR => DATASPACE_HEIF_ULTRAHDR *
  • ImageFormat.JPEG_R => HAL_DATASPACE_JPEG_R *
  • ImageFormat.YUV_420_888 => HAL_DATASPACE_JFIF *
  • ImageFormat.RAW_SENSOR => HAL_DATASPACE_ARBITRARY @@ -1508,6 +1589,11 @@ public final class StreamConfigurationMap { * if {@code format} was {@code HAL_PIXEL_FORMAT_IMPLEMENTATION_DEFINED} */ static int imageFormatToDataspace(int format) { + if (Flags.cameraHeifGainmap()) { + if (format == ImageFormat.HEIC_ULTRAHDR) { + return DataSpace.DATASPACE_HEIF_ULTRAHDR; + } + } switch (format) { case ImageFormat.JPEG: return HAL_DATASPACE_V0_JFIF; @@ -1584,13 +1670,21 @@ public final class StreamConfigurationMap { dataspace == HAL_DATASPACE_JPEG_R ? mJpegROutputFormats : highRes ? mHighResOutputFormats : mOutputFormats; - + boolean isDataSpaceHeifUltraHDR = false; + if (Flags.cameraHeifGainmap()) { + if (dataspace == DataSpace.DATASPACE_HEIF_ULTRAHDR) { + formatsMap = mHeicUltraHDROutputFormats; + isDataSpaceHeifUltraHDR = true; + } + } int sizesCount = formatsMap.get(format); if ( ((!output || (dataspace == HAL_DATASPACE_DEPTH || dataspace == HAL_DATASPACE_JPEG_R || dataspace == HAL_DATASPACE_DYNAMIC_DEPTH || - dataspace == HAL_DATASPACE_HEIF)) && sizesCount == 0) || + dataspace == HAL_DATASPACE_HEIF || + isDataSpaceHeifUltraHDR)) && sizesCount == 0) || (output && (dataspace != HAL_DATASPACE_DEPTH && dataspace != HAL_DATASPACE_JPEG_R && dataspace != HAL_DATASPACE_DYNAMIC_DEPTH && + !isDataSpaceHeifUltraHDR && dataspace != HAL_DATASPACE_HEIF) && mAllOutputFormats.get(format) == 0)) { return null; @@ -1604,12 +1698,14 @@ public final class StreamConfigurationMap { (dataspace == HAL_DATASPACE_DYNAMIC_DEPTH) ? mDynamicDepthConfigurations : (dataspace == HAL_DATASPACE_HEIF) ? mHeicConfigurations : (dataspace == HAL_DATASPACE_JPEG_R) ? mJpegRConfigurations : + (isDataSpaceHeifUltraHDR) ? mHeicUltraHDRConfigurations : mConfigurations; StreamConfigurationDuration[] minFrameDurations = (dataspace == HAL_DATASPACE_DEPTH) ? mDepthMinFrameDurations : (dataspace == HAL_DATASPACE_DYNAMIC_DEPTH) ? mDynamicDepthMinFrameDurations : (dataspace == HAL_DATASPACE_HEIF) ? mHeicMinFrameDurations : (dataspace == HAL_DATASPACE_JPEG_R) ? mJpegRMinFrameDurations : + (isDataSpaceHeifUltraHDR) ? mHeicUltraHDRMinFrameDurations : mMinFrameDurations; for (StreamConfiguration config : configurations) { @@ -1639,7 +1735,8 @@ public final class StreamConfigurationMap { // Dynamic depth streams can have both fast and also high res modes. if ((sizeIndex != sizesCount) && (dataspace == HAL_DATASPACE_DYNAMIC_DEPTH || - dataspace == HAL_DATASPACE_HEIF) || (dataspace == HAL_DATASPACE_JPEG_R)) { + dataspace == HAL_DATASPACE_HEIF) || (dataspace == HAL_DATASPACE_JPEG_R) || + isDataSpaceHeifUltraHDR) { if (sizeIndex > sizesCount) { throw new AssertionError( @@ -1682,6 +1779,11 @@ public final class StreamConfigurationMap { if (mHeicOutputFormats.size() > 0) { formats[i++] = ImageFormat.HEIC; } + if (Flags.cameraHeifGainmap()) { + if (mHeicUltraHDROutputFormats.size() > 0) { + formats[i++] = ImageFormat.HEIC_ULTRAHDR; + } + } if (mJpegROutputFormats.size() > 0) { formats[i++] = ImageFormat.JPEG_R; } @@ -1725,12 +1827,19 @@ public final class StreamConfigurationMap { * @see #DURATION_STALL * */ private StreamConfigurationDuration[] getDurations(int duration, int dataspace) { + boolean isDataSpaceHeifUltraHDR = false; + if (Flags.cameraHeifGainmap()) { + if (dataspace == DataSpace.DATASPACE_HEIF_ULTRAHDR) { + isDataSpaceHeifUltraHDR = true; + } + } switch (duration) { case DURATION_MIN_FRAME: return (dataspace == HAL_DATASPACE_DEPTH) ? mDepthMinFrameDurations : (dataspace == HAL_DATASPACE_DYNAMIC_DEPTH) ? mDynamicDepthMinFrameDurations : (dataspace == HAL_DATASPACE_HEIF) ? mHeicMinFrameDurations : + isDataSpaceHeifUltraHDR ? mHeicUltraHDRMinFrameDurations : (dataspace == HAL_DATASPACE_JPEG_R) ? mJpegRMinFrameDurations : mMinFrameDurations; @@ -1738,6 +1847,7 @@ public final class StreamConfigurationMap { return (dataspace == HAL_DATASPACE_DEPTH) ? mDepthStallDurations : (dataspace == HAL_DATASPACE_DYNAMIC_DEPTH) ? mDynamicDepthStallDurations : (dataspace == HAL_DATASPACE_HEIF) ? mHeicStallDurations : + isDataSpaceHeifUltraHDR ? mHeicUltraHDRStallDurations : (dataspace == HAL_DATASPACE_JPEG_R) ? mJpegRStallDurations : mStallDurations; default: @@ -1754,6 +1864,7 @@ public final class StreamConfigurationMap { size += mDynamicDepthOutputFormats.size(); size += mHeicOutputFormats.size(); size += mJpegROutputFormats.size(); + size += mHeicUltraHDROutputFormats.size(); } return size; @@ -1774,11 +1885,18 @@ public final class StreamConfigurationMap { } private boolean isSupportedInternalConfiguration(int format, int dataspace, Size size) { + boolean isDataSpaceHeifUltraHDR = false; + if (Flags.cameraHeifGainmap()) { + if (dataspace == DataSpace.DATASPACE_HEIF_ULTRAHDR) { + isDataSpaceHeifUltraHDR = true; + } + } StreamConfiguration[] configurations = (dataspace == HAL_DATASPACE_DEPTH) ? mDepthConfigurations : (dataspace == HAL_DATASPACE_DYNAMIC_DEPTH) ? mDynamicDepthConfigurations : (dataspace == HAL_DATASPACE_HEIF) ? mHeicConfigurations : (dataspace == HAL_DATASPACE_JPEG_R) ? mJpegRConfigurations : + isDataSpaceHeifUltraHDR ? mHeicUltraHDRConfigurations : mConfigurations; for (int i = 0; i < configurations.length; i++) { @@ -1954,6 +2072,11 @@ public final class StreamConfigurationMap { * @hide */ public static String formatToString(int format) { + if (Flags.cameraHeifGainmap()) { + if (format == ImageFormat.HEIC_ULTRAHDR) { + return "HEIC_ULTRAHDR"; + } + } switch (format) { case ImageFormat.YV12: return "YV12"; @@ -2078,6 +2201,10 @@ public final class StreamConfigurationMap { private final StreamConfigurationDuration[] mHeicMinFrameDurations; private final StreamConfigurationDuration[] mHeicStallDurations; + private final StreamConfiguration[] mHeicUltraHDRConfigurations; + private final StreamConfigurationDuration[] mHeicUltraHDRMinFrameDurations; + private final StreamConfigurationDuration[] mHeicUltraHDRStallDurations; + private final StreamConfiguration[] mJpegRConfigurations; private final StreamConfigurationDuration[] mJpegRMinFrameDurations; private final StreamConfigurationDuration[] mJpegRStallDurations; @@ -2103,6 +2230,8 @@ public final class StreamConfigurationMap { private final SparseIntArray mDynamicDepthOutputFormats = new SparseIntArray(); /** internal format -> num heic output sizes mapping, for HAL_DATASPACE_HEIF */ private final SparseIntArray mHeicOutputFormats = new SparseIntArray(); + /** internal format -> num heic output sizes mapping, for DATASPACE_HEIF_GAINMAP */ + private final SparseIntArray mHeicUltraHDROutputFormats = new SparseIntArray(); /** internal format -> num Jpeg/R output sizes mapping, for HAL_DATASPACE_JPEG_R */ private final SparseIntArray mJpegROutputFormats = new SparseIntArray(); diff --git a/core/java/android/hardware/display/BrightnessInfo.java b/core/java/android/hardware/display/BrightnessInfo.java index 6a96a54d93baabc0cf3f1874a9f1f2da17daed5b..529ee91cbfdf0f866bdcbf554a123fd20f7f3f3a 100644 --- a/core/java/android/hardware/display/BrightnessInfo.java +++ b/core/java/android/hardware/display/BrightnessInfo.java @@ -113,16 +113,24 @@ public final class BrightnessInfo implements Parcelable { */ public final int brightnessMaxReason; + /** + * Whether the current brightness value is overridden by the application window via + * {@link android.view.WindowManager.LayoutParams#screenBrightness}. + */ + public final boolean isBrightnessOverrideByWindow; + public BrightnessInfo(float brightness, float brightnessMinimum, float brightnessMaximum, @HighBrightnessMode int highBrightnessMode, float highBrightnessTransitionPoint, @BrightnessMaxReason int brightnessMaxReason) { this(brightness, brightness, brightnessMinimum, brightnessMaximum, highBrightnessMode, - highBrightnessTransitionPoint, brightnessMaxReason); + highBrightnessTransitionPoint, brightnessMaxReason, + false /* isBrightnessOverrideByWindow */); } public BrightnessInfo(float brightness, float adjustedBrightness, float brightnessMinimum, float brightnessMaximum, @HighBrightnessMode int highBrightnessMode, - float highBrightnessTransitionPoint, @BrightnessMaxReason int brightnessMaxReason) { + float highBrightnessTransitionPoint, @BrightnessMaxReason int brightnessMaxReason, + boolean isBrightnessOverrideByWindow) { this.brightness = brightness; this.adjustedBrightness = adjustedBrightness; this.brightnessMinimum = brightnessMinimum; @@ -130,6 +138,7 @@ public final class BrightnessInfo implements Parcelable { this.highBrightnessMode = highBrightnessMode; this.highBrightnessTransitionPoint = highBrightnessTransitionPoint; this.brightnessMaxReason = brightnessMaxReason; + this.isBrightnessOverrideByWindow = isBrightnessOverrideByWindow; } /** @@ -178,6 +187,7 @@ public final class BrightnessInfo implements Parcelable { dest.writeInt(highBrightnessMode); dest.writeFloat(highBrightnessTransitionPoint); dest.writeInt(brightnessMaxReason); + dest.writeBoolean(isBrightnessOverrideByWindow); } public static final @android.annotation.NonNull Creator CREATOR = @@ -201,6 +211,7 @@ public final class BrightnessInfo implements Parcelable { highBrightnessMode = source.readInt(); highBrightnessTransitionPoint = source.readFloat(); brightnessMaxReason = source.readInt(); + isBrightnessOverrideByWindow = source.readBoolean(); } } diff --git a/core/java/android/hardware/display/DisplayManager.java b/core/java/android/hardware/display/DisplayManager.java index a81bcbcce9c9138157d0a57ab666ab8d9be9bc16..28da644dd837710f5796427a4e39427e34fc5fdf 100644 --- a/core/java/android/hardware/display/DisplayManager.java +++ b/core/java/android/hardware/display/DisplayManager.java @@ -16,6 +16,7 @@ package android.hardware.display; +import static android.Manifest.permission.MANAGE_DISPLAYS; import static android.view.Display.DEFAULT_DISPLAY; import static android.view.Display.HdrCapabilities.HdrType; import static android.view.Display.INVALID_DISPLAY; @@ -575,13 +576,21 @@ public final class DisplayManager { EVENT_FLAG_DISPLAY_ADDED, EVENT_FLAG_DISPLAY_CHANGED, EVENT_FLAG_DISPLAY_REMOVED, - EVENT_FLAG_DISPLAY_BRIGHTNESS, - EVENT_FLAG_HDR_SDR_RATIO_CHANGED, - EVENT_FLAG_DISPLAY_CONNECTION_CHANGED, }) @Retention(RetentionPolicy.SOURCE) public @interface EventFlag {} + /** + * @hide + */ + @LongDef(flag = true, prefix = {"PRIVATE_EVENT_FLAG_"}, value = { + PRIVATE_EVENT_FLAG_DISPLAY_BRIGHTNESS, + PRIVATE_EVENT_FLAG_HDR_SDR_RATIO_CHANGED, + PRIVATE_EVENT_FLAG_DISPLAY_CONNECTION_CHANGED, + }) + @Retention(RetentionPolicy.SOURCE) + public @interface PrivateEventFlag {} + /** * Event type for when a new display is added. * @@ -618,7 +627,7 @@ public final class DisplayManager { * * @hide */ - public static final long EVENT_FLAG_DISPLAY_BRIGHTNESS = 1L << 3; + public static final long PRIVATE_EVENT_FLAG_DISPLAY_BRIGHTNESS = 1L << 0; /** * Event flag to register for a display's hdr/sdr ratio changes. This notification is sent @@ -631,14 +640,16 @@ public final class DisplayManager { * * @hide */ - public static final long EVENT_FLAG_HDR_SDR_RATIO_CHANGED = 1L << 4; + public static final long PRIVATE_EVENT_FLAG_HDR_SDR_RATIO_CHANGED = 1L << 1; /** * Event flag to register for a display's connection changed. * + * @see #registerDisplayListener(DisplayListener, Handler, long) * @hide */ - public static final long EVENT_FLAG_DISPLAY_CONNECTION_CHANGED = 1L << 5; + public static final long PRIVATE_EVENT_FLAG_DISPLAY_CONNECTION_CHANGED = 1L << 2; + /** @hide */ public DisplayManager(Context context) { @@ -774,20 +785,49 @@ public final class DisplayManager { * @param listener The listener to register. * @param handler The handler on which the listener should be invoked, or null * if the listener should be invoked on the calling thread's looper. - * @param eventFlagsMask A bitmask of the event types for which this listener is subscribed. + * @param eventFlags A bitmask of the event types for which this listener is subscribed. + * + * @see #EVENT_FLAG_DISPLAY_ADDED + * @see #EVENT_FLAG_DISPLAY_CHANGED + * @see #EVENT_FLAG_DISPLAY_REMOVED + * @see #registerDisplayListener(DisplayListener, Handler) + * @see #unregisterDisplayListener + * + * @hide + */ + public void registerDisplayListener(@NonNull DisplayListener listener, + @Nullable Handler handler, @EventFlag long eventFlags) { + mGlobal.registerDisplayListener(listener, handler, + mGlobal.mapFlagsToInternalEventFlag(eventFlags, 0), + ActivityThread.currentPackageName()); + } + + /** + * Registers a display listener to receive notifications about given display event types. + * + * @param listener The listener to register. + * @param handler The handler on which the listener should be invoked, or null + * if the listener should be invoked on the calling thread's looper. + * @param eventFlags A bitmask of the event types for which this listener is subscribed. + * @param privateEventFlags A bitmask of the private event types for which this listener + * is subscribed. * * @see #EVENT_FLAG_DISPLAY_ADDED * @see #EVENT_FLAG_DISPLAY_CHANGED * @see #EVENT_FLAG_DISPLAY_REMOVED - * @see #EVENT_FLAG_DISPLAY_BRIGHTNESS + * @see #PRIVATE_EVENT_FLAG_DISPLAY_BRIGHTNESS + * @see #PRIVATE_EVENT_FLAG_DISPLAY_CONNECTION_CHANGED + * @see #PRIVATE_EVENT_FLAG_HDR_SDR_RATIO_CHANGED * @see #registerDisplayListener(DisplayListener, Handler) * @see #unregisterDisplayListener * * @hide */ public void registerDisplayListener(@NonNull DisplayListener listener, - @Nullable Handler handler, @EventFlag long eventFlagsMask) { - mGlobal.registerDisplayListener(listener, handler, eventFlagsMask, + @Nullable Handler handler, @EventFlag long eventFlags, + @PrivateEventFlag long privateEventFlags) { + mGlobal.registerDisplayListener(listener, handler, + mGlobal.mapFlagsToInternalEventFlag(eventFlags, privateEventFlags), ActivityThread.currentPackageName()); } @@ -1724,6 +1764,29 @@ public final class DisplayManager { return mDisplayIdToMirror; } + /** + * @return The current display topology that represents the relative positions of extended + * displays. + * + * @hide + */ + @RequiresPermission(MANAGE_DISPLAYS) + @Nullable + public DisplayTopology getDisplayTopology() { + return mGlobal.getDisplayTopology(); + } + + /** + * Set the relative positions between extended displays (display topology). + * @param topology The display topology to be set + * + * @hide + */ + @RequiresPermission(MANAGE_DISPLAYS) + public void setDisplayTopology(DisplayTopology topology) { + mGlobal.setDisplayTopology(topology); + } + /** * Listens for changes in available display devices. */ diff --git a/core/java/android/hardware/display/DisplayManagerGlobal.java b/core/java/android/hardware/display/DisplayManagerGlobal.java index 3c6841cd8aeb68cbdd546d16b234cc99976aa6f1..03b44f63e3b76a038083bb38d409667dcb1f570d 100644 --- a/core/java/android/hardware/display/DisplayManagerGlobal.java +++ b/core/java/android/hardware/display/DisplayManagerGlobal.java @@ -18,12 +18,14 @@ package android.hardware.display; import static android.hardware.display.DisplayManager.EventFlag; +import static android.Manifest.permission.MANAGE_DISPLAYS; import static android.view.Display.HdrCapabilities.HdrType; import android.Manifest; import android.annotation.FlaggedApi; import android.annotation.FloatRange; import android.annotation.IntDef; +import android.annotation.LongDef; import android.annotation.NonNull; import android.annotation.Nullable; import android.annotation.RequiresPermission; @@ -118,6 +120,24 @@ public final class DisplayManagerGlobal { public static final int EVENT_DISPLAY_CONNECTED = 6; public static final int EVENT_DISPLAY_DISCONNECTED = 7; + @LongDef(prefix = {"INTERNAL_EVENT_DISPLAY"}, flag = true, value = { + INTERNAL_EVENT_FLAG_DISPLAY_ADDED, + INTERNAL_EVENT_FLAG_DISPLAY_CHANGED, + INTERNAL_EVENT_FLAG_DISPLAY_REMOVED, + INTERNAL_EVENT_FLAG_DISPLAY_BRIGHTNESS_CHANGED, + INTERNAL_EVENT_FLAG_DISPLAY_HDR_SDR_RATIO_CHANGED, + INTERNAL_EVENT_FLAG_DISPLAY_CONNECTION_CHANGED, + }) + @Retention(RetentionPolicy.SOURCE) + public @interface InternalEventFlag {} + + public static final long INTERNAL_EVENT_FLAG_DISPLAY_ADDED = 1L << 0; + public static final long INTERNAL_EVENT_FLAG_DISPLAY_CHANGED = 1L << 1; + public static final long INTERNAL_EVENT_FLAG_DISPLAY_REMOVED = 1L << 2; + public static final long INTERNAL_EVENT_FLAG_DISPLAY_BRIGHTNESS_CHANGED = 1L << 3; + public static final long INTERNAL_EVENT_FLAG_DISPLAY_HDR_SDR_RATIO_CHANGED = 1L << 4; + public static final long INTERNAL_EVENT_FLAG_DISPLAY_CONNECTION_CHANGED = 1L << 5; + @UnsupportedAppUsage private static DisplayManagerGlobal sInstance; @@ -130,7 +150,7 @@ public final class DisplayManagerGlobal { private final IDisplayManager mDm; private DisplayManagerCallback mCallback; - private @EventFlag long mRegisteredEventFlagsMask = 0; + private @InternalEventFlag long mRegisteredInternalEventFlag = 0; private final CopyOnWriteArrayList mDisplayListeners = new CopyOnWriteArrayList<>(); @@ -346,11 +366,11 @@ public final class DisplayManagerGlobal { * @param packageName of the calling package. */ public void registerDisplayListener(@NonNull DisplayListener listener, - @Nullable Handler handler, @EventFlag long eventFlagsMask, + @Nullable Handler handler, @InternalEventFlag long internalEventFlagsMask, String packageName) { Looper looper = getLooperForHandler(handler); Handler springBoard = new Handler(looper); - registerDisplayListener(listener, new HandlerExecutor(springBoard), eventFlagsMask, + registerDisplayListener(listener, new HandlerExecutor(springBoard), internalEventFlagsMask, packageName); } @@ -359,32 +379,34 @@ public final class DisplayManagerGlobal { * * @param listener The listener that will be called when display changes occur. * @param executor Executor for the thread that will be receiving the callbacks. Cannot be null. - * @param eventFlagsMask Flag of events to be listened to. + * @param internalEventFlagsMask Mask of events to be listened to. * @param packageName of the calling package. */ public void registerDisplayListener(@NonNull DisplayListener listener, - @NonNull Executor executor, @EventFlag long eventFlagsMask, String packageName) { + @NonNull Executor executor, @InternalEventFlag long internalEventFlagsMask, + String packageName) { if (listener == null) { throw new IllegalArgumentException("listener must not be null"); } - if (eventFlagsMask == 0) { + if (internalEventFlagsMask == 0) { throw new IllegalArgumentException("The set of events to listen to must not be empty."); } if (extraLogging()) { Slog.i(TAG, "Registering Display Listener: " - + Long.toBinaryString(eventFlagsMask) + ", packageName: " + packageName); + + Long.toBinaryString(internalEventFlagsMask) + + ", packageName: " + packageName); } synchronized (mLock) { int index = findDisplayListenerLocked(listener); if (index < 0) { mDisplayListeners.add(new DisplayListenerDelegate(listener, executor, - eventFlagsMask, packageName)); + internalEventFlagsMask, packageName)); registerCallbackIfNeededLocked(); } else { - mDisplayListeners.get(index).setEventFlagsMask(eventFlagsMask); + mDisplayListeners.get(index).setEventsMask(internalEventFlagsMask); } updateCallbackIfNeededLocked(); maybeLogAllDisplayListeners(); @@ -456,17 +478,17 @@ public final class DisplayManagerGlobal { return -1; } - @EventFlag - private int calculateEventFlagsMaskLocked() { - int mask = 0; + @InternalEventFlag + private long calculateEventsMaskLocked() { + long mask = 0; final int numListeners = mDisplayListeners.size(); for (int i = 0; i < numListeners; i++) { - mask |= mDisplayListeners.get(i).mEventFlagsMask; + mask |= mDisplayListeners.get(i).mInternalEventFlagsMask; } if (mDispatchNativeCallbacks) { - mask |= DisplayManager.EVENT_FLAG_DISPLAY_ADDED - | DisplayManager.EVENT_FLAG_DISPLAY_CHANGED - | DisplayManager.EVENT_FLAG_DISPLAY_REMOVED; + mask |= INTERNAL_EVENT_FLAG_DISPLAY_ADDED + | INTERNAL_EVENT_FLAG_DISPLAY_CHANGED + | INTERNAL_EVENT_FLAG_DISPLAY_REMOVED; } return mask; } @@ -479,14 +501,14 @@ public final class DisplayManagerGlobal { } private void updateCallbackIfNeededLocked() { - int mask = calculateEventFlagsMaskLocked(); + long mask = calculateEventsMaskLocked(); if (DEBUG) { - Log.d(TAG, "Flag for listener: " + mask); + Log.d(TAG, "Mask for listener: " + mask); } - if (mask != mRegisteredEventFlagsMask) { + if (mask != mRegisteredInternalEventFlag) { try { mDm.registerCallbackWithEventMask(mCallback, mask); - mRegisteredEventFlagsMask = mask; + mRegisteredInternalEventFlag = mask; } catch (RemoteException ex) { throw ex.rethrowFromSystemServer(); } @@ -1264,12 +1286,37 @@ public final class DisplayManagerGlobal { } } + /** + * @see DisplayManager#getDisplayTopology + */ + @RequiresPermission(MANAGE_DISPLAYS) + @Nullable + public DisplayTopology getDisplayTopology() { + try { + return mDm.getDisplayTopology(); + } catch (RemoteException ex) { + throw ex.rethrowFromSystemServer(); + } + } + + /** + * @see DisplayManager#setDisplayTopology + */ + @RequiresPermission(MANAGE_DISPLAYS) + public void setDisplayTopology(DisplayTopology topology) { + try { + mDm.setDisplayTopology(topology); + } catch (RemoteException ex) { + throw ex.rethrowFromSystemServer(); + } + } + private final class DisplayManagerCallback extends IDisplayManagerCallback.Stub { @Override public void onDisplayEvent(int displayId, @DisplayEvent int event) { if (DEBUG) { - Log.d(TAG, "onDisplayEvent: displayId=" + displayId + ", event=" + eventToString( - event)); + Log.d(TAG, "onDisplayEvent: displayId=" + displayId + ", event=" + + eventToString(event)); } handleDisplayEvent(displayId, event, false /* forceUpdate */); } @@ -1277,7 +1324,7 @@ public final class DisplayManagerGlobal { private static final class DisplayListenerDelegate { public final DisplayListener mListener; - public volatile long mEventFlagsMask; + public volatile long mInternalEventFlagsMask; private final DisplayInfo mDisplayInfo = new DisplayInfo(); private final Executor mExecutor; @@ -1285,10 +1332,10 @@ public final class DisplayManagerGlobal { private final String mPackageName; DisplayListenerDelegate(DisplayListener listener, @NonNull Executor executor, - @EventFlag long eventFlag, String packageName) { + @InternalEventFlag long internalEventFlag, String packageName) { mExecutor = executor; mListener = listener; - mEventFlagsMask = eventFlag; + mInternalEventFlagsMask = internalEventFlag; mPackageName = packageName; } @@ -1310,16 +1357,16 @@ public final class DisplayManagerGlobal { mGenerationId.incrementAndGet(); } - void setEventFlagsMask(@EventFlag long newEventsFlag) { - mEventFlagsMask = newEventsFlag; + void setEventsMask(@InternalEventFlag long newInternalEventFlagsMask) { + mInternalEventFlagsMask = newInternalEventFlagsMask; } - private void handleDisplayEventInner(int displayId, @DisplayEvent int eventFlagsMask, + private void handleDisplayEventInner(int displayId, @DisplayEvent int event, @Nullable DisplayInfo info, boolean forceUpdate) { if (extraLogging()) { - Slog.i(TAG, "DLD(" + eventToString(eventFlagsMask) + Slog.i(TAG, "DLD(" + eventToString(event) + ", display=" + displayId - + ", mEventsFlagMask=" + Long.toBinaryString(mEventFlagsMask) + + ", mEventsMask=" + Long.toBinaryString(mInternalEventFlagsMask) + ", mPackageName=" + mPackageName + ", displayInfo=" + info + ", listener=" + mListener.getClass() + ")"); @@ -1327,18 +1374,19 @@ public final class DisplayManagerGlobal { if (DEBUG) { Trace.beginSection( TextUtils.trimToSize( - "DLD(" + eventToString(eventFlagsMask) + "DLD(" + eventToString(event) + ", display=" + displayId + ", listener=" + mListener.getClass() + ")", 127)); } - switch (eventFlagsMask) { + switch (event) { case EVENT_DISPLAY_ADDED: - if ((mEventFlagsMask & DisplayManager.EVENT_FLAG_DISPLAY_ADDED) != 0) { + if ((mInternalEventFlagsMask & INTERNAL_EVENT_FLAG_DISPLAY_ADDED) != 0) { mListener.onDisplayAdded(displayId); } break; case EVENT_DISPLAY_CHANGED: - if ((mEventFlagsMask & DisplayManager.EVENT_FLAG_DISPLAY_CHANGED) != 0) { + if ((mInternalEventFlagsMask & INTERNAL_EVENT_FLAG_DISPLAY_CHANGED) + != 0) { if (info != null && (forceUpdate || !info.equals(mDisplayInfo))) { if (extraLogging()) { Slog.i(TAG, "Sending onDisplayChanged: Display Changed. Info: " @@ -1350,29 +1398,32 @@ public final class DisplayManagerGlobal { } break; case EVENT_DISPLAY_BRIGHTNESS_CHANGED: - if ((mEventFlagsMask & DisplayManager.EVENT_FLAG_DISPLAY_BRIGHTNESS) != 0) { + if ((mInternalEventFlagsMask + & INTERNAL_EVENT_FLAG_DISPLAY_BRIGHTNESS_CHANGED) != 0) { mListener.onDisplayChanged(displayId); } break; case EVENT_DISPLAY_REMOVED: - if ((mEventFlagsMask & DisplayManager.EVENT_FLAG_DISPLAY_REMOVED) != 0) { + if ((mInternalEventFlagsMask & INTERNAL_EVENT_FLAG_DISPLAY_REMOVED) + != 0) { mListener.onDisplayRemoved(displayId); } break; case EVENT_DISPLAY_HDR_SDR_RATIO_CHANGED: - if ((mEventFlagsMask & DisplayManager.EVENT_FLAG_HDR_SDR_RATIO_CHANGED) != 0) { + if ((mInternalEventFlagsMask + & INTERNAL_EVENT_FLAG_DISPLAY_HDR_SDR_RATIO_CHANGED) != 0) { mListener.onDisplayChanged(displayId); } break; case EVENT_DISPLAY_CONNECTED: - if ((mEventFlagsMask & DisplayManager.EVENT_FLAG_DISPLAY_CONNECTION_CHANGED) - != 0) { + if ((mInternalEventFlagsMask + & INTERNAL_EVENT_FLAG_DISPLAY_CONNECTION_CHANGED) != 0) { mListener.onDisplayConnected(displayId); } break; case EVENT_DISPLAY_DISCONNECTED: - if ((mEventFlagsMask & DisplayManager.EVENT_FLAG_DISPLAY_CONNECTION_CHANGED) - != 0) { + if ((mInternalEventFlagsMask + & INTERNAL_EVENT_FLAG_DISPLAY_CONNECTION_CHANGED) != 0) { mListener.onDisplayDisconnected(displayId); } break; @@ -1384,7 +1435,7 @@ public final class DisplayManagerGlobal { @Override public String toString() { - return "mEventFlagsMask: {" + mEventFlagsMask + "}, for " + mListener.getClass(); + return "flag: {" + mInternalEventFlagsMask + "}, for " + mListener.getClass(); } } @@ -1432,6 +1483,13 @@ public final class DisplayManagerGlobal { mExecutor.execute(mCallback::onStopped); } } + + @Override // Binder call + public void onRequestedBrightnessChanged(float brightness) { + if (mCallback != null) { + mExecutor.execute(() -> mCallback.onRequestedBrightnessChanged(brightness)); + } + } } /** @@ -1525,4 +1583,53 @@ public final class DisplayManagerGlobal { private static boolean extraLogging() { return sExtraDisplayListenerLogging; } + + + /** + * Maps the supplied public and private event flags to a unified InternalEventFlag + * @param eventFlags A bitmask of the event types for which this listener is subscribed. + * @param privateEventFlags A bitmask of the private event types for which this listener + * is subscribed. + * @return returns the bitmask of both public and private event flags unified to + * InternalEventFlag + */ + public @InternalEventFlag long mapFlagsToInternalEventFlag(@EventFlag long eventFlags, + @DisplayManager.PrivateEventFlag long privateEventFlags) { + return mapPrivateEventFlags(privateEventFlags) | mapPublicEventFlags(eventFlags); + } + + private long mapPrivateEventFlags(@DisplayManager.PrivateEventFlag long privateEventFlags) { + long baseEventMask = 0; + if ((privateEventFlags & DisplayManager.PRIVATE_EVENT_FLAG_DISPLAY_BRIGHTNESS) != 0) { + baseEventMask |= INTERNAL_EVENT_FLAG_DISPLAY_BRIGHTNESS_CHANGED; + } + + if ((privateEventFlags & DisplayManager.PRIVATE_EVENT_FLAG_HDR_SDR_RATIO_CHANGED) != 0) { + baseEventMask |= INTERNAL_EVENT_FLAG_DISPLAY_HDR_SDR_RATIO_CHANGED; + } + + if ((privateEventFlags + & DisplayManager.PRIVATE_EVENT_FLAG_DISPLAY_CONNECTION_CHANGED) != 0) { + baseEventMask |= INTERNAL_EVENT_FLAG_DISPLAY_CONNECTION_CHANGED; + } + return baseEventMask; + } + + private long mapPublicEventFlags(@EventFlag long eventFlags) { + long baseEventMask = 0; + if ((eventFlags & DisplayManager.EVENT_FLAG_DISPLAY_ADDED) != 0) { + baseEventMask |= INTERNAL_EVENT_FLAG_DISPLAY_ADDED; + } + + if ((eventFlags & DisplayManager.EVENT_FLAG_DISPLAY_CHANGED) != 0) { + baseEventMask |= INTERNAL_EVENT_FLAG_DISPLAY_CHANGED; + } + + if ((eventFlags + & DisplayManager.EVENT_FLAG_DISPLAY_REMOVED) != 0) { + baseEventMask |= INTERNAL_EVENT_FLAG_DISPLAY_REMOVED; + } + + return baseEventMask; + } } diff --git a/core/java/android/hardware/display/DisplayTopology.aidl b/core/java/android/hardware/display/DisplayTopology.aidl new file mode 100644 index 0000000000000000000000000000000000000000..e69b777a30de5cf29537f8d4a6ee580828d0cbcc --- /dev/null +++ b/core/java/android/hardware/display/DisplayTopology.aidl @@ -0,0 +1,19 @@ +/* + * 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.display; + +parcelable DisplayTopology; diff --git a/services/core/java/com/android/server/display/DisplayTopology.java b/core/java/android/hardware/display/DisplayTopology.java similarity index 73% rename from services/core/java/com/android/server/display/DisplayTopology.java rename to core/java/android/hardware/display/DisplayTopology.java index fdadafeb98c9ab28f3f4e53f73e144c87693f36f..e349b81614bc9fa2a5086d77aed8a94f60dd313e 100644 --- a/services/core/java/com/android/server/display/DisplayTopology.java +++ b/core/java/android/hardware/display/DisplayTopology.java @@ -14,25 +14,34 @@ * limitations under the License. */ -package com.android.server.display; +package android.hardware.display; -import static com.android.server.display.DisplayTopology.TreeNode.Position.POSITION_BOTTOM; -import static com.android.server.display.DisplayTopology.TreeNode.Position.POSITION_LEFT; -import static com.android.server.display.DisplayTopology.TreeNode.Position.POSITION_TOP; -import static com.android.server.display.DisplayTopology.TreeNode.Position.POSITION_RIGHT; +import static android.hardware.display.DisplayTopology.TreeNode.POSITION_BOTTOM; +import static android.hardware.display.DisplayTopology.TreeNode.POSITION_LEFT; +import static android.hardware.display.DisplayTopology.TreeNode.POSITION_RIGHT; +import static android.hardware.display.DisplayTopology.TreeNode.POSITION_TOP; +import android.annotation.IntDef; import android.annotation.Nullable; import android.graphics.RectF; +import android.os.Parcel; +import android.os.Parcelable; import android.util.IndentingPrintWriter; import android.util.Pair; import android.util.Slog; import android.view.Display; +import androidx.annotation.NonNull; + import com.android.internal.annotations.VisibleForTesting; import java.io.PrintWriter; +import java.io.StringWriter; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; import java.util.ArrayDeque; import java.util.ArrayList; +import java.util.Collections; import java.util.Comparator; import java.util.HashMap; import java.util.List; @@ -42,24 +51,59 @@ import java.util.Queue; /** * Represents the relative placement of extended displays. * Does not support concurrent calls, so a lock should be held when calling into this class. + * + * @hide */ -class DisplayTopology { +public final class DisplayTopology implements Parcelable { private static final String TAG = "DisplayTopology"; private static final float EPSILON = 0.0001f; + @android.annotation.NonNull + public static final Creator CREATOR = + new Creator<>() { + @Override + public DisplayTopology createFromParcel(Parcel source) { + return new DisplayTopology(source); + } + + @Override + public DisplayTopology[] newArray(int size) { + return new DisplayTopology[size]; + } + }; + /** * The topology tree */ @Nullable - @VisibleForTesting - TreeNode mRoot; + private TreeNode mRoot; /** * The logical display ID of the primary display that will show certain UI elements. * This is not necessarily the same as the default display. */ + private int mPrimaryDisplayId = Display.INVALID_DISPLAY; + + public DisplayTopology() {} + @VisibleForTesting - int mPrimaryDisplayId = Display.INVALID_DISPLAY; + public DisplayTopology(TreeNode root, int primaryDisplayId) { + mRoot = root; + mPrimaryDisplayId = primaryDisplayId; + } + + public DisplayTopology(Parcel source) { + this(source.readTypedObject(TreeNode.CREATOR), source.readInt()); + } + + @Nullable + public TreeNode getRoot() { + return mRoot; + } + + public int getPrimaryDisplayId() { + return mPrimaryDisplayId; + } /** * Add a display to the topology. @@ -69,7 +113,7 @@ class DisplayTopology { * @param width The width of the display * @param height The height of the display */ - void addDisplay(int displayId, float width, float height) { + public void addDisplay(int displayId, float width, float height) { addDisplay(displayId, width, height, /* shouldLog= */ true); } @@ -79,7 +123,7 @@ class DisplayTopology { * one by one. * @param displayId The logical display ID */ - void removeDisplay(int displayId) { + public void removeDisplay(int displayId) { if (findDisplay(displayId, mRoot) == null) { return; } @@ -106,11 +150,22 @@ class DisplayTopology { } } + @Override + public int describeContents() { + return 0; + } + + @Override + public void writeToParcel(@NonNull Parcel dest, int flags) { + dest.writeTypedObject(mRoot, flags); + dest.writeInt(mPrimaryDisplayId); + } + /** * Print the object's state and debug information into the given stream. * @param pw The stream to dump information to. */ - void dump(PrintWriter pw) { + public void dump(PrintWriter pw) { pw.println("DisplayTopology:"); pw.println("--------------------"); IndentingPrintWriter ipw = new IndentingPrintWriter(pw); @@ -126,13 +181,21 @@ class DisplayTopology { } } + @Override + public String toString() { + StringWriter out = new StringWriter(); + PrintWriter writer = new PrintWriter(out); + dump(writer); + return out.toString(); + } + private void addDisplay(int displayId, float width, float height, boolean shouldLog) { if (findDisplay(displayId, mRoot) != null) { throw new IllegalArgumentException( "DisplayTopology: attempting to add a display that already exists"); } if (mRoot == null) { - mRoot = new TreeNode(displayId, width, height, /* position= */ null, /* offset= */ 0); + mRoot = new TreeNode(displayId, width, height, /* position= */ 0, /* offset= */ 0); mPrimaryDisplayId = displayId; if (shouldLog) { Slog.i(TAG, "First display added: " + mRoot); @@ -241,7 +304,7 @@ class DisplayTopology { * Update the topology to remove any overlaps between displays. */ @VisibleForTesting - void normalize() { + public void normalize() { if (mRoot == null) { return; } @@ -341,6 +404,8 @@ class DisplayTopology { case POSITION_RIGHT -> floatEquals(parentBounds.right, childBounds.left); case POSITION_TOP -> floatEquals(parentBounds.top, childBounds.bottom); case POSITION_BOTTOM -> floatEquals(parentBounds.bottom, childBounds.top); + default -> throw new IllegalStateException( + "Unexpected value: " + targetDisplay.mPosition); }; // Check that the offset is within bounds areTouching &= switch (targetDisplay.mPosition) { @@ -350,6 +415,8 @@ class DisplayTopology { case POSITION_TOP, POSITION_BOTTOM -> childBounds.right + EPSILON >= parentBounds.left && childBounds.left <= parentBounds.right + EPSILON; + default -> throw new IllegalStateException( + "Unexpected value: " + targetDisplay.mPosition); }; if (!areTouching) { @@ -379,36 +446,56 @@ class DisplayTopology { * @param b second float to compare * @return whether the two values are within a small enough tolerance value */ - public static boolean floatEquals(float a, float b) { - return a == b || Float.isNaN(a) && Float.isNaN(b) || Math.abs(a - b) < EPSILON; + private static boolean floatEquals(float a, float b) { + return a == b || (Float.isNaN(a) && Float.isNaN(b)) || Math.abs(a - b) < EPSILON; } - @VisibleForTesting - static class TreeNode { + public static final class TreeNode implements Parcelable { + public static final int POSITION_LEFT = 0; + public static final int POSITION_TOP = 1; + public static final int POSITION_RIGHT = 2; + public static final int POSITION_BOTTOM = 3; + + @IntDef(prefix = { "POSITION_" }, value = { + POSITION_LEFT, POSITION_TOP, POSITION_RIGHT, POSITION_BOTTOM + }) + @Retention(RetentionPolicy.SOURCE) + public @interface Position{} + + @android.annotation.NonNull + public static final Creator CREATOR = + new Creator<>() { + @Override + public TreeNode createFromParcel(Parcel source) { + return new TreeNode(source); + } + + @Override + public TreeNode[] newArray(int size) { + return new TreeNode[size]; + } + }; /** * The logical display ID */ - @VisibleForTesting - final int mDisplayId; + private final int mDisplayId; /** * The width of the display in density-independent pixels (dp). */ - @VisibleForTesting - float mWidth; + private final float mWidth; /** * The height of the display in density-independent pixels (dp). */ - @VisibleForTesting - float mHeight; + private final float mHeight; /** * The position of this display relative to its parent. */ - @VisibleForTesting - Position mPosition; + @Position + private int mPosition; /** * The distance from the top edge of the parent display to the top edge of this display (in @@ -416,13 +503,13 @@ class DisplayTopology { * to the left edge of this display (in case of POSITION_TOP or POSITION_BOTTOM). The unit * used is density-independent pixels (dp). */ - @VisibleForTesting - float mOffset; + private float mOffset; - @VisibleForTesting - final List mChildren = new ArrayList<>(); + private final List mChildren = new ArrayList<>(); - TreeNode(int displayId, float width, float height, Position position, float offset) { + @VisibleForTesting + public TreeNode(int displayId, float width, float height, @Position int position, + float offset) { mDisplayId = displayId; mWidth = width; mHeight = height; @@ -430,11 +517,76 @@ class DisplayTopology { mOffset = offset; } + public TreeNode(Parcel source) { + this(source.readInt(), source.readFloat(), source.readFloat(), source.readInt(), + source.readFloat()); + source.readTypedList(mChildren, CREATOR); + } + + public int getDisplayId() { + return mDisplayId; + } + + public float getWidth() { + return mWidth; + } + + public float getHeight() { + return mHeight; + } + + public int getPosition() { + return mPosition; + } + + public float getOffset() { + return mOffset; + } + + public List getChildren() { + return Collections.unmodifiableList(mChildren); + } + + @Override + public String toString() { + return "Display {id=" + mDisplayId + ", width=" + mWidth + ", height=" + mHeight + + ", position=" + positionToString(mPosition) + ", offset=" + mOffset + "}"; + } + + /** + * @param position The position + * @return The string representation + */ + public static String positionToString(@Position int position) { + return switch (position) { + case POSITION_LEFT -> "left"; + case POSITION_TOP -> "top"; + case POSITION_RIGHT -> "right"; + case POSITION_BOTTOM -> "bottom"; + default -> throw new IllegalStateException("Unexpected value: " + position); + }; + } + + @Override + public int describeContents() { + return 0; + } + + @Override + public void writeToParcel(@NonNull Parcel dest, int flags) { + dest.writeInt(mDisplayId); + dest.writeFloat(mWidth); + dest.writeFloat(mHeight); + dest.writeInt(mPosition); + dest.writeFloat(mOffset); + dest.writeTypedList(mChildren); + } + /** * Print the object's state and debug information into the given stream. * @param ipw The stream to dump information to. */ - void dump(IndentingPrintWriter ipw) { + public void dump(IndentingPrintWriter ipw) { ipw.println(this); ipw.increaseIndent(); for (TreeNode child : mChildren) { @@ -443,15 +595,12 @@ class DisplayTopology { ipw.decreaseIndent(); } - @Override - public String toString() { - return "Display {id=" + mDisplayId + ", width=" + mWidth + ", height=" + mHeight - + ", position=" + mPosition + ", offset=" + mOffset + "}"; - } - + /** + * @param child The child to add + */ @VisibleForTesting - enum Position { - POSITION_LEFT, POSITION_TOP, POSITION_RIGHT, POSITION_BOTTOM + public void addChild(TreeNode child) { + mChildren.add(child); } } } diff --git a/core/java/android/hardware/display/IDisplayManager.aidl b/core/java/android/hardware/display/IDisplayManager.aidl index b612bca5671ee7582a5a9b4d9d54fd89d23d5157..4fbdf7f5afc801d31f9d9eccd4f9ddf5d00e2103 100644 --- a/core/java/android/hardware/display/IDisplayManager.aidl +++ b/core/java/android/hardware/display/IDisplayManager.aidl @@ -23,6 +23,7 @@ import android.hardware.display.BrightnessConfiguration; import android.hardware.display.BrightnessInfo; import android.hardware.display.Curve; import android.hardware.graphics.common.DisplayDecorationSupport; +import android.hardware.display.DisplayTopology; import android.hardware.display.HdrConversionMode; import android.hardware.display.IDisplayManagerCallback; import android.hardware.display.IVirtualDisplayCallback; @@ -254,4 +255,13 @@ interface IDisplayManager { // Get the default doze brightness @EnforcePermission("CONTROL_DISPLAY_BRIGHTNESS") float getDefaultDozeBrightness(int displayId); + + // Get the display topology + @EnforcePermission("MANAGE_DISPLAYS") + @nullable + DisplayTopology getDisplayTopology(); + + // Set the display topology + @EnforcePermission("MANAGE_DISPLAYS") + void setDisplayTopology(in DisplayTopology topology); } diff --git a/core/java/android/hardware/display/IVirtualDisplayCallback.aidl b/core/java/android/hardware/display/IVirtualDisplayCallback.aidl index c3490d177be256d18bfb926ac96bec1a2039636f..9cc0364f27296dbd6bd32695f725304403880a30 100644 --- a/core/java/android/hardware/display/IVirtualDisplayCallback.aidl +++ b/core/java/android/hardware/display/IVirtualDisplayCallback.aidl @@ -38,4 +38,9 @@ oneway interface IVirtualDisplayCallback { * of the application to release() the virtual display. */ void onStopped(); + + /** + * Called when the virtual display's requested brightness has changed. + */ + void onRequestedBrightnessChanged(float brightness); } diff --git a/core/java/android/hardware/display/VirtualDisplay.java b/core/java/android/hardware/display/VirtualDisplay.java index 32b640583734bd0e224ebaa268826fd820307ff4..3b573ea98c279e1b05f583e5c55ca1021d9ab697 100644 --- a/core/java/android/hardware/display/VirtualDisplay.java +++ b/core/java/android/hardware/display/VirtualDisplay.java @@ -16,6 +16,8 @@ package android.hardware.display; import android.annotation.FlaggedApi; +import android.annotation.FloatRange; +import android.annotation.SystemApi; import android.view.Display; import android.view.Surface; @@ -164,5 +166,25 @@ public final class VirtualDisplay { * of the application to release() the virtual display. */ public void onStopped() { } + + /** + * Called when the requested brightness of the display has changed. + * + *

    The system may adjust the display's brightness based on user or app activity. This + * callback will only be invoked if the display has an explicitly specified default + * brightness value.

    + * + *

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

    + * + * @see android.view.View#setKeepScreenOn(boolean) + * @see android.view.WindowManager.LayoutParams#screenBrightness + * @see VirtualDisplayConfig.Builder#setDefaultBrightness(float) + * @hide + */ + @FlaggedApi(android.companion.virtualdevice.flags.Flags.FLAG_DEVICE_AWARE_DISPLAY_POWER) + @SystemApi + public void onRequestedBrightnessChanged( + @FloatRange(from = 0.0f, to = 1.0f) float brightness) {} } } diff --git a/core/java/android/hardware/display/VirtualDisplayConfig.java b/core/java/android/hardware/display/VirtualDisplayConfig.java index 49944c76eb99b96e8407984881bfee79942e797c..57d9d28a9d475024a629c927da844c5e94e9b5fc 100644 --- a/core/java/android/hardware/display/VirtualDisplayConfig.java +++ b/core/java/android/hardware/display/VirtualDisplayConfig.java @@ -29,6 +29,7 @@ import android.media.projection.MediaProjection; import android.os.Handler; import android.os.Parcel; import android.os.Parcelable; +import android.os.PowerManager; import android.util.ArraySet; import android.view.Display; import android.view.DisplayCutout; @@ -61,6 +62,7 @@ public final class VirtualDisplayConfig implements Parcelable { private final boolean mIsHomeSupported; private final DisplayCutout mDisplayCutout; private final boolean mIgnoreActivitySizeRestrictions; + private final float mDefaultBrightness; private VirtualDisplayConfig( @NonNull String name, @@ -76,7 +78,8 @@ public final class VirtualDisplayConfig implements Parcelable { float requestedRefreshRate, boolean isHomeSupported, @Nullable DisplayCutout displayCutout, - boolean ignoreActivitySizeRestrictions) { + boolean ignoreActivitySizeRestrictions, + @FloatRange(from = 0.0f, to = 1.0f) float defaultBrightness) { mName = name; mWidth = width; mHeight = height; @@ -91,6 +94,7 @@ public final class VirtualDisplayConfig implements Parcelable { mIsHomeSupported = isHomeSupported; mDisplayCutout = displayCutout; mIgnoreActivitySizeRestrictions = ignoreActivitySizeRestrictions; + mDefaultBrightness = defaultBrightness; } /** @@ -156,6 +160,22 @@ public final class VirtualDisplayConfig implements Parcelable { return mDisplayCutout; } + /** + * Returns the default brightness of the display. + * + *

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

    + * + * @see Builder#setDefaultBrightness(float) + * @hide + */ + @FlaggedApi(android.companion.virtualdevice.flags.Flags.FLAG_DEVICE_AWARE_DISPLAY_POWER) + @SystemApi + public @FloatRange(from = 0.0f, to = 1.0f) float getDefaultBrightness() { + return mDefaultBrightness; + } + + /** * Returns the unique identifier for the display. Shouldn't be displayed to the user. * @hide @@ -245,6 +265,7 @@ public final class VirtualDisplayConfig implements Parcelable { dest.writeBoolean(mIsHomeSupported); DisplayCutout.ParcelableWrapper.writeCutoutToParcel(mDisplayCutout, dest, flags); dest.writeBoolean(mIgnoreActivitySizeRestrictions); + dest.writeFloat(mDefaultBrightness); } @Override @@ -272,7 +293,8 @@ public final class VirtualDisplayConfig implements Parcelable { && mRequestedRefreshRate == that.mRequestedRefreshRate && mIsHomeSupported == that.mIsHomeSupported && mIgnoreActivitySizeRestrictions == that.mIgnoreActivitySizeRestrictions - && Objects.equals(mDisplayCutout, that.mDisplayCutout); + && Objects.equals(mDisplayCutout, that.mDisplayCutout) + && mDefaultBrightness == that.mDefaultBrightness; } @Override @@ -281,7 +303,7 @@ public final class VirtualDisplayConfig implements Parcelable { mName, mWidth, mHeight, mDensityDpi, mFlags, mSurface, mUniqueId, mDisplayIdToMirror, mWindowManagerMirroringEnabled, mDisplayCategories, mRequestedRefreshRate, mIsHomeSupported, mDisplayCutout, - mIgnoreActivitySizeRestrictions); + mIgnoreActivitySizeRestrictions, mDefaultBrightness); return hashCode; } @@ -303,6 +325,7 @@ public final class VirtualDisplayConfig implements Parcelable { + " mIsHomeSupported=" + mIsHomeSupported + " mDisplayCutout=" + mDisplayCutout + " mIgnoreActivitySizeRestrictions=" + mIgnoreActivitySizeRestrictions + + " mDefaultBrightness=" + mDefaultBrightness + ")"; } @@ -321,6 +344,7 @@ public final class VirtualDisplayConfig implements Parcelable { mIsHomeSupported = in.readBoolean(); mDisplayCutout = DisplayCutout.ParcelableWrapper.readCutoutFromParcel(in); mIgnoreActivitySizeRestrictions = in.readBoolean(); + mDefaultBrightness = in.readFloat(); } @NonNull @@ -355,6 +379,7 @@ public final class VirtualDisplayConfig implements Parcelable { private boolean mIsHomeSupported = false; private DisplayCutout mDisplayCutout = null; private boolean mIgnoreActivitySizeRestrictions = false; + private float mDefaultBrightness = 0.0f; /** * Creates a new Builder. @@ -546,6 +571,35 @@ public final class VirtualDisplayConfig implements Parcelable { return this; } + /** + * Sets the default brightness of the display. + * + *

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

    + * + *

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

    + * + *

    If unset, defaults to {@code 0.0}

    + * + * @see android.view.View#setKeepScreenOn(boolean) + * @see Builder#setDefaultBrightness(float) + * @see VirtualDisplay.Callback#onRequestedBrightnessChanged(float) + * @hide + */ + @FlaggedApi(android.companion.virtualdevice.flags.Flags.FLAG_DEVICE_AWARE_DISPLAY_POWER) + @SystemApi + @NonNull + public Builder setDefaultBrightness(@FloatRange(from = 0.0f, to = 1.0f) float brightness) { + if (brightness < PowerManager.BRIGHTNESS_MIN + || brightness > PowerManager.BRIGHTNESS_MAX) { + throw new IllegalArgumentException( + "Virtual display default brightness must be in range [0.0, 1.0]"); + } + mDefaultBrightness = brightness; + return this; + } + /** * Builds the {@link VirtualDisplayConfig} instance. */ @@ -565,7 +619,8 @@ public final class VirtualDisplayConfig implements Parcelable { mRequestedRefreshRate, mIsHomeSupported, mDisplayCutout, - mIgnoreActivitySizeRestrictions); + mIgnoreActivitySizeRestrictions, + mDefaultBrightness); } } } diff --git a/core/java/android/hardware/input/AidlInputGestureData.aidl b/core/java/android/hardware/input/AidlInputGestureData.aidl index 137f672bf59c5765de3681a4671c7c8c367f1d89..e33ec53dd20850b01c9bbe86156bf3db7d555d42 100644 --- a/core/java/android/hardware/input/AidlInputGestureData.aidl +++ b/core/java/android/hardware/input/AidlInputGestureData.aidl @@ -19,13 +19,26 @@ package android.hardware.input; /** @hide */ @JavaDerive(equals=true) parcelable AidlInputGestureData { - int keycode; - int modifierState; - int gestureType; + Trigger trigger; - // App launch parameters: Only set if gestureType is KEY_GESTURE_TYPE_LAUNCH_APPLICATION + int gestureType; + // App launch parameters (Only set if gestureType is LAUNCH_APPLICATION) String appLaunchCategory; String appLaunchRole; String appLaunchPackageName; String appLaunchClassName; + + parcelable KeyTrigger { + int keycode; + int modifierState; + } + + parcelable TouchpadGestureTrigger { + int gestureType; + } + + union Trigger { + KeyTrigger key; + TouchpadGestureTrigger touchpadGesture; + } } diff --git a/core/java/android/hardware/input/IInputManager.aidl b/core/java/android/hardware/input/IInputManager.aidl index bce95187515acee1bcda3836cd8cd3fb26fc5454..3284761eb27310fe6fb214b04c0b953273e03a9a 100644 --- a/core/java/android/hardware/input/IInputManager.aidl +++ b/core/java/android/hardware/input/IInputManager.aidl @@ -266,17 +266,19 @@ interface IInputManager { @PermissionManuallyEnforced @JavaPassthrough(annotation="@android.annotation.RequiresPermission(value = " + "android.Manifest.permission.MANAGE_KEY_GESTURES)") - int addCustomInputGesture(in AidlInputGestureData data); + int addCustomInputGesture(int userId, in AidlInputGestureData data); @PermissionManuallyEnforced @JavaPassthrough(annotation="@android.annotation.RequiresPermission(value = " + "android.Manifest.permission.MANAGE_KEY_GESTURES)") - int removeCustomInputGesture(in AidlInputGestureData data); + int removeCustomInputGesture(int userId, in AidlInputGestureData data); @PermissionManuallyEnforced @JavaPassthrough(annotation="@android.annotation.RequiresPermission(value = " + "android.Manifest.permission.MANAGE_KEY_GESTURES)") - void removeAllCustomInputGestures(); + void removeAllCustomInputGestures(int userId, int tag); - AidlInputGestureData[] getCustomInputGestures(); + AidlInputGestureData[] getCustomInputGestures(int userId, int tag); + + AidlInputGestureData[] getAppLaunchBookmarks(); } diff --git a/core/java/android/hardware/input/InputGestureData.java b/core/java/android/hardware/input/InputGestureData.java index 5ab73cee96414c8bbc6762f3fb2220b9749827c4..f41550f6061ea9cf9f95ea0594b9294c01f53548 100644 --- a/core/java/android/hardware/input/InputGestureData.java +++ b/core/java/android/hardware/input/InputGestureData.java @@ -35,20 +35,40 @@ import java.util.Objects; */ public final class InputGestureData { + public static final int TOUCHPAD_GESTURE_TYPE_UNKNOWN = 0; + public static final int TOUCHPAD_GESTURE_TYPE_THREE_FINGER_TAP = 1; + @NonNull private final AidlInputGestureData mInputGestureData; - public InputGestureData(AidlInputGestureData inputGestureData) { + public InputGestureData(@NonNull AidlInputGestureData inputGestureData) { this.mInputGestureData = inputGestureData; validate(); } /** Returns the trigger information for this input gesture */ public Trigger getTrigger() { - if (mInputGestureData.keycode != KeyEvent.KEYCODE_UNKNOWN) { - return new KeyTrigger(mInputGestureData.keycode, mInputGestureData.modifierState); + switch (mInputGestureData.trigger.getTag()) { + case AidlInputGestureData.Trigger.Tag.key: { + AidlInputGestureData.KeyTrigger trigger = mInputGestureData.trigger.getKey(); + if (trigger == null) { + throw new RuntimeException("InputGestureData is corrupted, null key trigger!"); + } + return createKeyTrigger(trigger.keycode, trigger.modifierState); + } + case AidlInputGestureData.Trigger.Tag.touchpadGesture: { + AidlInputGestureData.TouchpadGestureTrigger trigger = + mInputGestureData.trigger.getTouchpadGesture(); + if (trigger == null) { + throw new RuntimeException( + "InputGestureData is corrupted, null touchpad trigger!"); + } + return createTouchpadTrigger(trigger.gestureType); + } + default: + throw new RuntimeException("InputGestureData is corrupted, invalid trigger type!"); + } - throw new RuntimeException("InputGestureData is corrupted, invalid trigger type!"); } /** Returns the action to perform for this input gesture */ @@ -127,9 +147,15 @@ public final class InputGestureData { "No app launch data for system action launch application"); } AidlInputGestureData data = new AidlInputGestureData(); + data.trigger = new AidlInputGestureData.Trigger(); if (mTrigger instanceof KeyTrigger keyTrigger) { - data.keycode = keyTrigger.getKeycode(); - data.modifierState = keyTrigger.getModifierState(); + data.trigger.setKey(new AidlInputGestureData.KeyTrigger()); + data.trigger.getKey().keycode = keyTrigger.getKeycode(); + data.trigger.getKey().modifierState = keyTrigger.getModifierState(); + } else if (mTrigger instanceof TouchpadTrigger touchpadTrigger) { + data.trigger.setTouchpadGesture(new AidlInputGestureData.TouchpadGestureTrigger()); + data.trigger.getTouchpadGesture().gestureType = + touchpadTrigger.getTouchpadGestureType(); } else { throw new IllegalArgumentException("Invalid trigger type!"); } @@ -163,30 +189,12 @@ public final class InputGestureData { if (this == o) return true; if (o == null || getClass() != o.getClass()) return false; InputGestureData that = (InputGestureData) o; - return mInputGestureData.keycode == that.mInputGestureData.keycode - && mInputGestureData.modifierState == that.mInputGestureData.modifierState - && mInputGestureData.gestureType == that.mInputGestureData.gestureType - && Objects.equals(mInputGestureData.appLaunchCategory, that.mInputGestureData.appLaunchCategory) - && Objects.equals(mInputGestureData.appLaunchRole, that.mInputGestureData.appLaunchRole) - && Objects.equals(mInputGestureData.appLaunchPackageName, that.mInputGestureData.appLaunchPackageName) - && Objects.equals(mInputGestureData.appLaunchPackageName, that.mInputGestureData.appLaunchPackageName); + return Objects.equals(mInputGestureData, that.mInputGestureData); } @Override public int hashCode() { - int _hash = 1; - _hash = 31 * _hash + mInputGestureData.keycode; - _hash = 31 * _hash + mInputGestureData.modifierState; - _hash = 31 * _hash + mInputGestureData.gestureType; - _hash = 31 * _hash + (mInputGestureData.appLaunchCategory != null - ? mInputGestureData.appLaunchCategory.hashCode() : 0); - _hash = 31 * _hash + (mInputGestureData.appLaunchRole != null - ? mInputGestureData.appLaunchRole.hashCode() : 0); - _hash = 31 * _hash + (mInputGestureData.appLaunchPackageName != null - ? mInputGestureData.appLaunchPackageName.hashCode() : 0); - _hash = 31 * _hash + (mInputGestureData.appLaunchPackageName != null - ? mInputGestureData.appLaunchPackageName.hashCode() : 0); - return _hash; + return mInputGestureData.hashCode(); } public interface Trigger { @@ -197,6 +205,11 @@ public final class InputGestureData { return new KeyTrigger(keycode, modifierState); } + /** Creates a input gesture trigger based on a touchpad gesture */ + public static Trigger createTouchpadTrigger(int touchpadGestureType) { + return new TouchpadTrigger(touchpadGestureType); + } + /** Key based input gesture trigger */ public static class KeyTrigger implements Trigger { private static final int SHORTCUT_META_MASK = @@ -242,8 +255,76 @@ public final class InputGestureData { } } + /** Touchpad based input gesture trigger */ + public static class TouchpadTrigger implements Trigger { + private final int mTouchpadGestureType; + + private TouchpadTrigger(int touchpadGestureType) { + if (touchpadGestureType != TOUCHPAD_GESTURE_TYPE_THREE_FINGER_TAP) { + throw new IllegalArgumentException( + "Invalid touchpadGestureType = " + touchpadGestureType); + } + mTouchpadGestureType = touchpadGestureType; + } + + public int getTouchpadGestureType() { + return mTouchpadGestureType; + } + + @Override + public String toString() { + return "TouchpadTrigger{" + + "mTouchpadGestureType=" + mTouchpadGestureType + + '}'; + } + + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (o == null || getClass() != o.getClass()) return false; + TouchpadTrigger that = (TouchpadTrigger) o; + return mTouchpadGestureType == that.mTouchpadGestureType; + } + + @Override + public int hashCode() { + return Objects.hashCode(mTouchpadGestureType); + } + } + /** Data for action to perform when input gesture is triggered */ public record Action(@KeyGestureEvent.KeyGestureType int keyGestureType, @Nullable AppLaunchData appLaunchData) { } + + /** Filter definition for InputGestureData */ + public enum Filter { + KEY(AidlInputGestureData.Trigger.Tag.key), + TOUCHPAD(AidlInputGestureData.Trigger.Tag.touchpadGesture); + + @AidlInputGestureData.Trigger.Tag + private final int mTag; + + Filter(@AidlInputGestureData.Trigger.Tag int tag) { + mTag = tag; + } + + @Nullable + public static Filter of(@AidlInputGestureData.Trigger.Tag int tag) { + return switch (tag) { + case AidlInputGestureData.Trigger.Tag.key -> KEY; + case AidlInputGestureData.Trigger.Tag.touchpadGesture -> TOUCHPAD; + default -> null; + }; + } + + @AidlInputGestureData.Trigger.Tag + public int getTag() { + return mTag; + } + + public boolean matches(@NonNull InputGestureData inputGestureData) { + return mTag == inputGestureData.mInputGestureData.trigger.getTag(); + } + } } diff --git a/core/java/android/hardware/input/InputManager.java b/core/java/android/hardware/input/InputManager.java index 876ba1021917f66850befc83502505db346f45a8..f8241925dff0483e2c5c50dace114e231cb46b95 100644 --- a/core/java/android/hardware/input/InputManager.java +++ b/core/java/android/hardware/input/InputManager.java @@ -34,6 +34,7 @@ import android.annotation.SdkConstant.SdkConstantType; import android.annotation.SuppressLint; import android.annotation.SystemService; import android.annotation.TestApi; +import android.annotation.UserHandleAware; import android.annotation.UserIdInt; import android.app.ActivityThread; import android.compat.annotation.ChangeId; @@ -1487,16 +1488,16 @@ public final class InputManager { */ @RequiresPermission(Manifest.permission.MANAGE_KEY_GESTURES) @CustomInputGestureResult + @UserHandleAware public int addCustomInputGesture(@NonNull InputGestureData inputGestureData) { if (!enableCustomizableInputGestures()) { return CUSTOM_INPUT_GESTURE_RESULT_ERROR_OTHER; } try { - return mIm.addCustomInputGesture(inputGestureData.getAidlData()); + return mIm.addCustomInputGesture(mContext.getUserId(), inputGestureData.getAidlData()); } catch (RemoteException e) { - e.rethrowFromSystemServer(); + throw e.rethrowFromSystemServer(); } - return CUSTOM_INPUT_GESTURE_RESULT_ERROR_OTHER; } /** Removes an existing custom gesture @@ -1510,53 +1511,84 @@ public final class InputManager { */ @RequiresPermission(Manifest.permission.MANAGE_KEY_GESTURES) @CustomInputGestureResult + @UserHandleAware public int removeCustomInputGesture(@NonNull InputGestureData inputGestureData) { if (!enableCustomizableInputGestures()) { return CUSTOM_INPUT_GESTURE_RESULT_ERROR_OTHER; } try { - return mIm.removeCustomInputGesture(inputGestureData.getAidlData()); + return mIm.removeCustomInputGesture(mContext.getUserId(), + inputGestureData.getAidlData()); } catch (RemoteException e) { - e.rethrowFromSystemServer(); + throw e.rethrowFromSystemServer(); } - return CUSTOM_INPUT_GESTURE_RESULT_ERROR_OTHER; } /** Removes all custom input gestures + * + * @param filter for removing all gestures of a category. If {@code null}, all custom input + * gestures will be removed * * @hide */ @RequiresPermission(Manifest.permission.MANAGE_KEY_GESTURES) - public void removeAllCustomInputGestures() { + @UserHandleAware + public void removeAllCustomInputGestures(@Nullable InputGestureData.Filter filter) { if (!enableCustomizableInputGestures()) { return; } try { - mIm.removeAllCustomInputGestures(); + mIm.removeAllCustomInputGestures(mContext.getUserId(), + filter == null ? -1 : filter.getTag()); } catch (RemoteException e) { - e.rethrowFromSystemServer(); + throw e.rethrowFromSystemServer(); } } /** Get all custom input gestures + * + * @param filter for fetching all gestures of a category. If {@code null}, then will return + * all custom input gestures * * @hide */ - public List getCustomInputGestures() { + @UserHandleAware + public List getCustomInputGestures(@Nullable InputGestureData.Filter filter) { List result = new ArrayList<>(); if (!enableCustomizableInputGestures()) { return result; } try { - for (AidlInputGestureData data : mIm.getCustomInputGestures()) { + for (AidlInputGestureData data : mIm.getCustomInputGestures(mContext.getUserId(), + filter == null ? -1 : filter.getTag())) { result.add(new InputGestureData(data)); } } catch (RemoteException e) { - e.rethrowFromSystemServer(); + throw e.rethrowFromSystemServer(); } return result; } + /** + * Return the set of application launch bookmarks handled by the input framework. + * + * @return list of {@link InputGestureData} containing the application launch shortcuts parsed + * at boot time from {@code bookmarks.xml}. + * + * @hide + */ + public List getAppLaunchBookmarks() { + try { + List result = new ArrayList<>(); + for (AidlInputGestureData data : mIm.getAppLaunchBookmarks()) { + result.add(new InputGestureData(data)); + } + return result; + } 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 4a9efe0a675b9dc9233549be3d3c00c88c488fae..96f6ad117035a3f2b9accd93fde6673ce372923a 100644 --- a/core/java/android/hardware/input/InputSettings.java +++ b/core/java/android/hardware/input/InputSettings.java @@ -20,16 +20,19 @@ import static com.android.hardware.input.Flags.FLAG_KEYBOARD_A11Y_BOUNCE_KEYS_FL import static com.android.hardware.input.Flags.FLAG_KEYBOARD_A11Y_MOUSE_KEYS; import static com.android.hardware.input.Flags.FLAG_KEYBOARD_A11Y_SLOW_KEYS_FLAG; import static com.android.hardware.input.Flags.FLAG_KEYBOARD_A11Y_STICKY_KEYS_FLAG; +import static com.android.hardware.input.Flags.enableCustomizableInputGestures; import static com.android.hardware.input.Flags.keyboardA11yBounceKeysFlag; +import static com.android.hardware.input.Flags.keyboardA11yMouseKeys; import static com.android.hardware.input.Flags.keyboardA11ySlowKeysFlag; import static com.android.hardware.input.Flags.keyboardA11yStickyKeysFlag; -import static com.android.hardware.input.Flags.keyboardA11yMouseKeys; import static com.android.hardware.input.Flags.mouseReverseVerticalScrolling; import static com.android.hardware.input.Flags.mouseSwapPrimaryButton; 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.input.flags.Flags.enableInputFilterRustImpl; +import static com.android.hardware.input.Flags.useKeyGestureEventHandler; 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; import android.Manifest; @@ -378,6 +381,15 @@ public class InputSettings { return touchpadVisualizer(); } + /** + * Returns true if the feature flag for the touchpad three-finger tap shortcut is enabled. + * + * @hide + */ + public static boolean isTouchpadThreeFingerTapShortcutFeatureFlagEnabled() { + return isCustomizableInputGesturesFeatureFlagEnabled() && touchpadThreeFingerTapShortcut(); + } + /** * Returns true if the feature flag for mouse reverse vertical scrolling is enabled. * @hide @@ -497,6 +509,22 @@ public class InputSettings { UserHandle.USER_CURRENT); } + /** + * Returns true if three-finger taps on the touchpad should trigger a customizable shortcut + * rather than a middle click. + * + * The returned value only applies to gesture-compatible touchpads. + * + * @param context The application context. + * @return Whether three-finger taps should trigger the shortcut. + * + * @hide + */ + public static boolean useTouchpadThreeFingerTapShortcut(@NonNull Context context) { + // TODO(b/365063048): determine whether to enable the shortcut based on the settings. + return isTouchpadThreeFingerTapShortcutFeatureFlagEnabled(); + } + /** * Whether a pointer icon will be shown over the location of a stylus pointer. * @@ -1105,4 +1133,18 @@ public class InputSettings { Settings.Secure.KEY_REPEAT_DELAY_MS, delayTimeMillis, UserHandle.USER_CURRENT); } + + /** + * Whether "Customizable key gestures" feature flag is enabled. + * + *

    + * ‘Customizable key gestures’ is a feature which allows users to customize key based + * shortcuts on the physical keyboard. + *

    + * + * @hide + */ + public static boolean isCustomizableInputGesturesFeatureFlagEnabled() { + return enableCustomizableInputGestures() && useKeyGestureEventHandler(); + } } diff --git a/core/java/android/hardware/input/KeyGestureEvent.java b/core/java/android/hardware/input/KeyGestureEvent.java index 9d42b67bf5a8fa4b85b20ca393f76f98e554f81b..24951c4d516e0339f34951445b155a65824818b7 100644 --- a/core/java/android/hardware/input/KeyGestureEvent.java +++ b/core/java/android/hardware/input/KeyGestureEvent.java @@ -117,6 +117,10 @@ public final class KeyGestureEvent { public static final int KEY_GESTURE_TYPE_SNAP_RIGHT_FREEFORM_WINDOW = 69; public static final int KEY_GESTURE_TYPE_MAXIMIZE_FREEFORM_WINDOW = 70; public static final int KEY_GESTURE_TYPE_RESTORE_FREEFORM_WINDOW_SIZE = 71; + public static final int KEY_GESTURE_TYPE_MAGNIFIER_ZOOM_IN = 72; + public static final int KEY_GESTURE_TYPE_MAGNIFIER_ZOOM_OUT = 73; + public static final int KEY_GESTURE_TYPE_TOGGLE_MAGNIFICATION = 74; + public static final int KEY_GESTURE_TYPE_ACTIVATE_SELECT_TO_SPEAK = 75; public static final int FLAG_CANCELLED = 1; @@ -203,6 +207,10 @@ public final class KeyGestureEvent { KEY_GESTURE_TYPE_SNAP_RIGHT_FREEFORM_WINDOW, KEY_GESTURE_TYPE_MAXIMIZE_FREEFORM_WINDOW, KEY_GESTURE_TYPE_RESTORE_FREEFORM_WINDOW_SIZE, + KEY_GESTURE_TYPE_MAGNIFIER_ZOOM_IN, + KEY_GESTURE_TYPE_MAGNIFIER_ZOOM_OUT, + KEY_GESTURE_TYPE_TOGGLE_MAGNIFICATION, + KEY_GESTURE_TYPE_ACTIVATE_SELECT_TO_SPEAK, }) @Retention(RetentionPolicy.SOURCE) public @interface KeyGestureType { @@ -773,6 +781,14 @@ public final class KeyGestureEvent { return "KEY_GESTURE_TYPE_SNAP_RIGHT_FREEFORM_WINDOW"; case KEY_GESTURE_TYPE_RESTORE_FREEFORM_WINDOW_SIZE: return "KEY_GESTURE_TYPE_RESTORE_FREEFORM_WINDOW_SIZE"; + case KEY_GESTURE_TYPE_MAGNIFIER_ZOOM_IN: + return "KEY_GESTURE_TYPE_MAGNIFIER_ZOOM_IN"; + case KEY_GESTURE_TYPE_MAGNIFIER_ZOOM_OUT: + return "KEY_GESTURE_TYPE_MAGNIFIER_ZOOM_OUT"; + case KEY_GESTURE_TYPE_TOGGLE_MAGNIFICATION: + return "KEY_GESTURE_TYPE_TOGGLE_MAGNIFICATION"; + case KEY_GESTURE_TYPE_ACTIVATE_SELECT_TO_SPEAK: + return "KEY_GESTURE_TYPE_ACTIVATE_SELECT_TO_SPEAK"; default: return Integer.toHexString(value); } diff --git a/core/java/android/hardware/input/input_framework.aconfig b/core/java/android/hardware/input/input_framework.aconfig index 71c91e91337690e669657720d45803bf07e0b091..a8eb11d88aa48ec2254fc0edeaf1e596a31e5266 100644 --- a/core/java/android/hardware/input/input_framework.aconfig +++ b/core/java/android/hardware/input/input_framework.aconfig @@ -28,14 +28,6 @@ flag { bug: "294546335" } -flag { - namespace: "input_native" - name: "emoji_and_screenshot_keycodes_available" - is_exported: true - description: "Add new KeyEvent keycodes for opening Emoji Picker and Taking Screenshots" - bug: "315307777" -} - flag { namespace: "input_native" name: "keyboard_a11y_slow_keys_flag" @@ -141,7 +133,7 @@ flag { flag { name: "keyboard_a11y_shortcut_control" namespace: "input" - description: "Adds shortcuts to toggle and control a11y features" + description: "Adds shortcuts to toggle and control a11y keyboard features" bug: "373458181" } @@ -152,9 +144,30 @@ flag { bug: "365064144" } +flag { + name: "enable_new_25q2_keycodes" + namespace: "input" + description: "Enables new 25Q2 keycodes" + bug: "365920375" +} + flag { name: "override_power_key_behavior_in_focused_window" namespace: "input_native" description: "Allows privileged focused windows to capture power key events." bug: "357144512" } + +flag { + name: "touchpad_three_finger_tap_shortcut" + namespace: "input" + description: "Turns three-finger touchpad taps into a customizable shortcut." + bug: "365063048" +} + +flag { + name: "enable_talkback_and_magnifier_key_gestures" + namespace: "input" + description: "Adds key gestures for talkback and magnifier" + bug: "375277034" +} \ No newline at end of file diff --git a/core/java/android/hardware/location/ContextHubInfo.java b/core/java/android/hardware/location/ContextHubInfo.java index 858ec23ebed8b1a49724f09edd905434fc99c799..af715e485b738a04d4ca05418702576009d2bb80 100644 --- a/core/java/android/hardware/location/ContextHubInfo.java +++ b/core/java/android/hardware/location/ContextHubInfo.java @@ -15,7 +15,6 @@ */ package android.hardware.location; -import android.annotation.FlaggedApi; import android.annotation.NonNull; import android.annotation.Nullable; import android.annotation.SystemApi; diff --git a/core/java/android/hardware/location/ContextHubManager.java b/core/java/android/hardware/location/ContextHubManager.java index 6284e7061b8882354ef5016e22e056219bde76b3..494bfc92638426c57d9c2b4f72ece47d1c4d3c25 100644 --- a/core/java/android/hardware/location/ContextHubManager.java +++ b/core/java/android/hardware/location/ContextHubManager.java @@ -18,6 +18,7 @@ package android.hardware.location; import static java.util.Objects.requireNonNull; import android.annotation.CallbackExecutor; +import android.annotation.FlaggedApi; import android.annotation.IntDef; import android.annotation.NonNull; import android.annotation.Nullable; @@ -31,7 +32,6 @@ import android.app.ActivityThread; import android.app.PendingIntent; import android.chre.flags.Flags; import android.content.Context; -import android.content.Intent; import android.content.pm.PackageManager; import android.hardware.contexthub.ErrorCode; import android.os.Handler; @@ -484,15 +484,33 @@ public final class ContextHubManager { } } - /** - * Helper function to generate a stub for a query transaction callback. - * - * @param transaction the transaction to unblock when complete - * - * @return the callback - * - * @hide - */ + /** + * Returns the list of HubInfo objects describing the available hubs (including ContextHub and + * VendorHub). This method is primarily used for debugging purposes as most clients care about + * endpoints and services more than hubs. + * + * @return the list of HubInfo objects + * @see HubInfo + * @hide + */ + @RequiresPermission(android.Manifest.permission.ACCESS_CONTEXT_HUB) + @NonNull + @FlaggedApi(Flags.FLAG_OFFLOAD_API) + public List getHubs() { + try { + return mService.getHubs(); + } catch (RemoteException e) { + throw e.rethrowFromSystemServer(); + } + } + + /** + * Helper function to generate a stub for a query transaction callback. + * + * @param transaction the transaction to unblock when complete + * @return the callback + * @hide + */ private IContextHubTransactionCallback createQueryCallback( ContextHubTransaction> transaction) { return new IContextHubTransactionCallback.Stub() { diff --git a/core/java/android/hardware/location/HubInfo.aidl b/core/java/android/hardware/location/HubInfo.aidl new file mode 100644 index 0000000000000000000000000000000000000000..25b5b0aa1222d1724aa6a094f1cf3c310642adb1 --- /dev/null +++ b/core/java/android/hardware/location/HubInfo.aidl @@ -0,0 +1,20 @@ +/* + * 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.location; + +/** @hide */ +parcelable HubInfo; diff --git a/core/java/android/hardware/location/HubInfo.java b/core/java/android/hardware/location/HubInfo.java new file mode 100644 index 0000000000000000000000000000000000000000..f7de1279672cf9931f84936f59dc1bd138cfce4b --- /dev/null +++ b/core/java/android/hardware/location/HubInfo.java @@ -0,0 +1,153 @@ +/* + * 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.location; + +import android.annotation.FlaggedApi; +import android.annotation.IntDef; +import android.annotation.NonNull; +import android.annotation.Nullable; +import android.chre.flags.Flags; +import android.os.BadParcelableException; +import android.os.Parcel; +import android.os.Parcelable; + +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; + +/** + * Union type for {@link ContextHubInfo} and {@link VendorHubInfo} + * + * @hide + */ +@FlaggedApi(Flags.FLAG_OFFLOAD_API) +public final class HubInfo implements Parcelable { + + @Retention(RetentionPolicy.SOURCE) + @IntDef(value = {TYPE_CONTEXT_HUB, TYPE_VENDOR_HUB}) + private @interface HubType {} + + public static final int TYPE_CONTEXT_HUB = 0; + public static final int TYPE_VENDOR_HUB = 1; + + private final long mId; + @HubType private final int mType; + @Nullable private final ContextHubInfo mContextHubInfo; + @Nullable private final VendorHubInfo mVendorHubInfo; + + /** @hide */ + public HubInfo(long id, @NonNull ContextHubInfo contextHubInfo) { + mId = id; + mType = TYPE_CONTEXT_HUB; + mContextHubInfo = contextHubInfo; + mVendorHubInfo = null; + } + + /** @hide */ + public HubInfo(long id, @NonNull VendorHubInfo vendorHubInfo) { + mId = id; + mType = TYPE_VENDOR_HUB; + mContextHubInfo = null; + mVendorHubInfo = vendorHubInfo; + } + + private HubInfo(Parcel in) { + mId = in.readLong(); + mType = in.readInt(); + + switch (mType) { + case TYPE_CONTEXT_HUB: + mContextHubInfo = ContextHubInfo.CREATOR.createFromParcel(in); + mVendorHubInfo = null; + break; + case TYPE_VENDOR_HUB: + mVendorHubInfo = VendorHubInfo.CREATOR.createFromParcel(in); + mContextHubInfo = null; + break; + default: + throw new BadParcelableException("Parcelable has invalid type"); + } + } + + /** Get the hub unique identifier */ + public long getId() { + return mId; + } + + /** Get the hub type. The type can be {@link TYPE_CONTEXT_HUB} or {@link TYPE_VENDOR_HUB} */ + public int getType() { + return mType; + } + + /** Get the {@link ContextHubInfo} object, null if type is not {@link TYPE_CONTEXT_HUB} */ + @Nullable + public ContextHubInfo getContextHubInfo() { + return mContextHubInfo; + } + + /** Parcel implementation details */ + public int describeContents() { + if (mType == TYPE_CONTEXT_HUB && mContextHubInfo != null) { + return mContextHubInfo.describeContents(); + } + if (mType == TYPE_VENDOR_HUB && mVendorHubInfo != null) { + return mVendorHubInfo.describeContents(); + } + return 0; + } + + /** Parcel implementation details */ + public void writeToParcel(@NonNull Parcel out, int flags) { + out.writeLong(mId); + out.writeInt(mType); + + if (mType == TYPE_CONTEXT_HUB && mContextHubInfo != null) { + mContextHubInfo.writeToParcel(out, flags); + } + + if (mType == TYPE_VENDOR_HUB && mVendorHubInfo != null) { + mVendorHubInfo.writeToParcel(out, flags); + } + } + + @NonNull + @Override + public String toString() { + StringBuilder out = new StringBuilder(); + out.append("HubInfo ID: 0x"); + out.append(Long.toHexString(mId)); + out.append("\n"); + if (mType == TYPE_CONTEXT_HUB && mContextHubInfo != null) { + out.append(" ContextHubDetails: "); + out.append(mContextHubInfo); + } + if (mType == TYPE_VENDOR_HUB && mVendorHubInfo != null) { + out.append(" VendorHubDetails: "); + out.append(mVendorHubInfo); + } + return out.toString(); + } + + public static final @NonNull Creator CREATOR = + new Creator<>() { + public HubInfo createFromParcel(Parcel in) { + return new HubInfo(in); + } + + public HubInfo[] newArray(int size) { + return new HubInfo[size]; + } + }; +} diff --git a/core/java/android/hardware/location/IContextHubService.aidl b/core/java/android/hardware/location/IContextHubService.aidl index 11f3046150d3bfe859e86ca61095dc8072305c9d..b0cc763dc8fd1615a12fb6c88a257e0ee12eaf51 100644 --- a/core/java/android/hardware/location/IContextHubService.aidl +++ b/core/java/android/hardware/location/IContextHubService.aidl @@ -18,6 +18,7 @@ package android.hardware.location; // Declare any non-default types here with import statements import android.app.PendingIntent; +import android.hardware.location.HubInfo; import android.hardware.location.ContextHubInfo; import android.hardware.location.ContextHubMessage; import android.hardware.location.NanoApp; @@ -82,6 +83,10 @@ interface IContextHubService { @EnforcePermission("ACCESS_CONTEXT_HUB") List getContextHubs(); + // Returns a list of HubInfo objects of available hubs (including ContextHub and VendorHub) + @EnforcePermission("ACCESS_CONTEXT_HUB") + List getHubs(); + // Loads a nanoapp at the specified hub (new API) @EnforcePermission("ACCESS_CONTEXT_HUB") void loadNanoAppOnHub( diff --git a/core/java/android/hardware/location/OWNERS b/core/java/android/hardware/location/OWNERS index 747f90947b9c225a6c2ce6ac82513fcf7d58dcf2..340d6f2eb08c884c882007f6e0d43c8b4959ca16 100644 --- a/core/java/android/hardware/location/OWNERS +++ b/core/java/android/hardware/location/OWNERS @@ -9,4 +9,4 @@ wyattriley@google.com yuhany@google.com # ContextHub team -per-file *ContextHub*,*NanoApp* = file:platform/system/chre:/OWNERS +per-file Android.bp,*Hub*,*NanoApp* = file:platform/system/chre:/OWNERS diff --git a/core/java/android/hardware/location/VendorHubInfo.aidl b/core/java/android/hardware/location/VendorHubInfo.aidl new file mode 100644 index 0000000000000000000000000000000000000000..a7936acbb654b555a1ab15ad5ade915eb4e6a92f --- /dev/null +++ b/core/java/android/hardware/location/VendorHubInfo.aidl @@ -0,0 +1,20 @@ +/* + * 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.location; + +/** @hide */ +parcelable VendorHubInfo; \ No newline at end of file diff --git a/core/java/android/hardware/location/VendorHubInfo.java b/core/java/android/hardware/location/VendorHubInfo.java new file mode 100644 index 0000000000000000000000000000000000000000..26772b18176f884d973a8fb7a9400d0b8bdf0847 --- /dev/null +++ b/core/java/android/hardware/location/VendorHubInfo.java @@ -0,0 +1,95 @@ +/* + * 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.location; + +import android.annotation.FlaggedApi; +import android.annotation.NonNull; +import android.chre.flags.Flags; +import android.os.Parcel; +import android.os.Parcelable; +import android.os.ParcelableHolder; + +/** + * Information about a VendorHub. VendorHub is similar to ContextHub, but it does not run the + * Context Hub Runtime Environment (or nano apps). It provides a unified endpoint messaging API + * through the ContextHub V4 HAL. + * + * @hide + */ +@FlaggedApi(Flags.FLAG_OFFLOAD_API) +public final class VendorHubInfo implements Parcelable { + private final String mName; + private final int mVersion; + private final ParcelableHolder mExtendedInfo; + + /** @hide */ + public VendorHubInfo(android.hardware.contexthub.VendorHubInfo halHubInfo) { + mName = halHubInfo.name; + mVersion = halHubInfo.version; + mExtendedInfo = halHubInfo.extendedInfo; + } + + private VendorHubInfo(Parcel in) { + mName = in.readString(); + mVersion = in.readInt(); + mExtendedInfo = ParcelableHolder.CREATOR.createFromParcel(in); + } + + /** Get the hub name */ + @NonNull + public String getName() { + return mName; + } + + /** Get the hub version */ + public int getVersion() { + return mVersion; + } + + /** Parcel implementation details */ + public int describeContents() { + return mExtendedInfo.describeContents(); + } + + /** Parcel implementation details */ + public void writeToParcel(@NonNull Parcel out, int flags) { + out.writeString(mName); + out.writeInt(mVersion); + mExtendedInfo.writeToParcel(out, flags); + } + + @NonNull + @Override + public String toString() { + StringBuilder out = new StringBuilder(); + out.append("VendorHub Name : "); + out.append(mName); + out.append(", Version : "); + out.append(mVersion); + return out.toString(); + } + + public static final @NonNull Creator CREATOR = + new Creator<>() { + public VendorHubInfo createFromParcel(Parcel in) { + return new VendorHubInfo(in); + } + + public VendorHubInfo[] newArray(int size) { + return new VendorHubInfo[size]; + } + }; +} diff --git a/core/java/android/hardware/soundtrigger/SoundTrigger.java b/core/java/android/hardware/soundtrigger/SoundTrigger.java index c6fd0ee3c80df2752e8b240816154f44465e6396..7745b036bcbe3371476ba280a8217b0448cb1550 100644 --- a/core/java/android/hardware/soundtrigger/SoundTrigger.java +++ b/core/java/android/hardware/soundtrigger/SoundTrigger.java @@ -1521,8 +1521,7 @@ public class SoundTrigger { private final boolean mAllowMultipleTriggers; private final KeyphraseRecognitionExtra mKeyphrases[]; private final byte[] mData; - @ModuleProperties.AudioCapabilities - private final int mAudioCapabilities; + private final @ModuleProperties.AudioCapabilities int mAudioCapabilities; /** * Constructor for {@link RecognitionConfig} with {@code audioCapabilities} describes a @@ -1535,11 +1534,12 @@ public class SoundTrigger { * @param keyphrases List of keyphrases in the sound model. * @param data Opaque data for use by system applications who know about voice engine * internals, typically during enrollment. - * @param audioCapabilities Bit field encoding of the AudioCapabilities. + * @param audioCapabilities Bit field encoding of the AudioCapabilities. See + * {@link ModuleProperties.AudioCapabilities} for details. */ private RecognitionConfig(boolean captureRequested, boolean allowMultipleTriggers, @Nullable KeyphraseRecognitionExtra[] keyphrases, @Nullable byte[] data, - int audioCapabilities) { + @ModuleProperties.AudioCapabilities int audioCapabilities) { this.mCaptureRequested = captureRequested; this.mAllowMultipleTriggers = allowMultipleTriggers; this.mKeyphrases = keyphrases != null ? keyphrases : new KeyphraseRecognitionExtra[0]; @@ -1617,8 +1617,11 @@ public class SoundTrigger { return mData; } - /** Bit field encoding of the AudioCapabilities supported by the firmware. */ - public int getAudioCapabilities() { + /** + * Bit field encoding of the AudioCapabilities supported by the firmware. See + * {@link ModuleProperties.AudioCapabilities} for details. + */ + public @ModuleProperties.AudioCapabilities int getAudioCapabilities() { return mAudioCapabilities; } @@ -1702,7 +1705,7 @@ public class SoundTrigger { private boolean mAllowMultipleTriggers; @Nullable private KeyphraseRecognitionExtra[] mKeyphrases; @Nullable private byte[] mData; - private int mAudioCapabilities; + private @ModuleProperties.AudioCapabilities int mAudioCapabilities; /** * Constructs a new Builder with the default values. @@ -1750,18 +1753,20 @@ public class SoundTrigger { * internals, typically during enrollment. * @return the same Builder instance. */ - public @NonNull Builder setData(@Nullable byte[] data) { - mData = data; + public @NonNull Builder setData(@NonNull byte[] data) { + mData = requireNonNull(data, "Data must not be null"); return this; } /** * Sets the audio capabilities field. * @param audioCapabilities The bit field encoding of the audio capabilities associated - * with this recognition session. + * with this recognition session. See + * {@link ModuleProperties.AudioCapabilities} for details. * @return the same Builder instance. */ - public @NonNull Builder setAudioCapabilities(int audioCapabilities) { + public @NonNull Builder setAudioCapabilities( + @ModuleProperties.AudioCapabilities int audioCapabilities) { mAudioCapabilities = audioCapabilities; return this; } diff --git a/core/java/android/hardware/usb/OWNERS b/core/java/android/hardware/usb/OWNERS index a753f9634d0d588f43475bae8c1985feaff3f966..37604bc2eb652c3f32da23b941f4fe59a5ee36b2 100644 --- a/core/java/android/hardware/usb/OWNERS +++ b/core/java/android/hardware/usb/OWNERS @@ -1,7 +1,7 @@ # Bug component: 175220 -aprasath@google.com -kumarashishg@google.com -sarup@google.com anothermark@google.com +febinthattil@google.com +aprasath@google.com badhri@google.com +kumarashishg@google.com \ No newline at end of file diff --git a/core/java/android/net/vcn/flags.aconfig b/core/java/android/net/vcn/flags.aconfig index 1adefe5a0b86f28724443d9b311a51cef2730f34..1b2c575917b263379d64a55e8bbe8b102f0cc3c8 100644 --- a/core/java/android/net/vcn/flags.aconfig +++ b/core/java/android/net/vcn/flags.aconfig @@ -17,13 +17,6 @@ flag { bug: "376339506" } -flag { - name: "safe_mode_timeout_config" - namespace: "vcn" - description: "Feature flag for adjustable safe mode timeout" - bug: "317406085" -} - flag { name: "fix_config_garbage_collection" namespace: "vcn" diff --git a/core/java/android/os/AggregateBatteryConsumer.java b/core/java/android/os/AggregateBatteryConsumer.java index c7f8878f104efcf9008914aa4e8f0e4fe1bfc1ba..f0e12ca644dd6ccd16d2489342d3d0d6d7c63c99 100644 --- a/core/java/android/os/AggregateBatteryConsumer.java +++ b/core/java/android/os/AggregateBatteryConsumer.java @@ -85,7 +85,7 @@ public final class AggregateBatteryConsumer extends BatteryConsumer { throw new XmlPullParserException("Invalid XML parser state"); } - consumerBuilder.setConsumedPower( + consumerBuilder.addConsumedPower( parser.getAttributeDouble(null, BatteryUsageStats.XML_ATTR_POWER)); while (!(eventType == XmlPullParser.END_TAG && parser.getName().equals( @@ -131,12 +131,20 @@ public final class AggregateBatteryConsumer extends BatteryConsumer { return this; } + /** + * Adds the total power included in this aggregate. + */ + public Builder addConsumedPower(double consumedPowerMah) { + mData.putDouble(COLUMN_INDEX_CONSUMED_POWER, + mData.getDouble(COLUMN_INDEX_CONSUMED_POWER) + consumedPowerMah); + return this; + } + /** * Adds power and usage duration from the supplied AggregateBatteryConsumer. */ public void add(AggregateBatteryConsumer aggregateBatteryConsumer) { - setConsumedPower(mData.getDouble(COLUMN_INDEX_CONSUMED_POWER) - + aggregateBatteryConsumer.getConsumedPower()); + addConsumedPower(aggregateBatteryConsumer.getConsumedPower()); mPowerComponentsBuilder.addPowerAndDuration(aggregateBatteryConsumer.mPowerComponents); } diff --git a/core/java/android/os/BatteryConsumer.java b/core/java/android/os/BatteryConsumer.java index b0ecca790b801f307766cc8f3e1b7f276f1f09d2..14b67f64b6da85549171baa48a64817ef360e7e9 100644 --- a/core/java/android/os/BatteryConsumer.java +++ b/core/java/android/os/BatteryConsumer.java @@ -1064,7 +1064,9 @@ public abstract class BatteryConsumer { * @param componentId The ID of the power component, e.g. * {@link BatteryConsumer#POWER_COMPONENT_CPU}. * @param componentPower Amount of consumed power in mAh. + * @deprecated use {@link #addConsumedPower} */ + @Deprecated @NonNull public T setConsumedPower(@PowerComponentId int componentId, double componentPower) { return setConsumedPower(componentId, componentPower, POWER_MODEL_POWER_PROFILE); @@ -1076,7 +1078,9 @@ public abstract class BatteryConsumer { * @param componentId The ID of the power component, e.g. * {@link BatteryConsumer#POWER_COMPONENT_CPU}. * @param componentPower Amount of consumed power in mAh. + * @deprecated use {@link #addConsumedPower} */ + @Deprecated @SuppressWarnings("unchecked") @NonNull public T setConsumedPower(@PowerComponentId int componentId, double componentPower, @@ -1102,6 +1106,21 @@ public abstract class BatteryConsumer { return (T) this; } + @SuppressWarnings("unchecked") + @NonNull + public T addConsumedPower(@PowerComponentId int componentId, double componentPower) { + mPowerComponentsBuilder.addConsumedPower(getKey(componentId, PROCESS_STATE_UNSPECIFIED), + componentPower, POWER_MODEL_UNDEFINED); + 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) { @@ -1115,7 +1134,9 @@ public abstract class BatteryConsumer { * @param componentId The ID of the power component, e.g. * {@link UidBatteryConsumer#POWER_COMPONENT_CPU}. * @param componentUsageTimeMillis Amount of time in microseconds. + * @deprecated use {@link #addUsageDurationMillis} */ + @Deprecated @SuppressWarnings("unchecked") @NonNull public T setUsageDurationMillis(@PowerComponentId int componentId, @@ -1126,6 +1147,7 @@ public abstract class BatteryConsumer { return (T) this; } + @Deprecated @SuppressWarnings("unchecked") @NonNull public T setUsageDurationMillis(Key key, long componentUsageTimeMillis) { @@ -1133,6 +1155,14 @@ public abstract class BatteryConsumer { return (T) this; } + @NonNull + public T addUsageDurationMillis(@PowerComponentId int componentId, + long componentUsageTimeMillis) { + mPowerComponentsBuilder.addUsageDurationMillis( + getKey(componentId, PROCESS_STATE_UNSPECIFIED), componentUsageTimeMillis); + return (T) this; + } + @SuppressWarnings("unchecked") @NonNull public T addUsageDurationMillis(Key key, long componentUsageTimeMillis) { diff --git a/core/java/android/os/BatteryUsageStats.java b/core/java/android/os/BatteryUsageStats.java index 6c3c2852c7e71c8f606f91e0ca1ed8e99cc715ac..72e4cef2f6ebbd3bf642f724ebf795eabfe61eea 100644 --- a/core/java/android/os/BatteryUsageStats.java +++ b/core/java/android/os/BatteryUsageStats.java @@ -209,7 +209,7 @@ public final class BatteryUsageStats implements Parcelable, Closeable { } builder.getAggregateBatteryConsumerBuilder(AGGREGATE_BATTERY_CONSUMER_SCOPE_ALL_APPS) - .setConsumedPower(totalPowerMah); + .addConsumedPower(totalPowerMah); mAggregateBatteryConsumers = new AggregateBatteryConsumer[AGGREGATE_BATTERY_CONSUMER_SCOPE_COUNT]; @@ -1315,7 +1315,7 @@ public final class BatteryUsageStats implements Parcelable, Closeable { } synchronized (BatteryUsageStats.class) { - if (!sInstances.isEmpty()) { + if (sInstances != null && !sInstances.isEmpty()) { Exception callSite = sInstances.entrySet().iterator().next().getValue(); int count = sInstances.size(); sInstances.clear(); diff --git a/core/java/android/os/Build.java b/core/java/android/os/Build.java index 13d7e3c2fbfd13e3d37ed54f76a99e13d5a01fec..102bdd0b625c9d81ae0cd94d0be695f081905d16 100644 --- a/core/java/android/os/Build.java +++ b/core/java/android/os/Build.java @@ -40,8 +40,6 @@ import android.util.ArraySet; import android.util.Slog; import android.view.View; -import com.android.internal.ravenwood.RavenwoodEnvironment; - import dalvik.system.VMRuntime; import java.lang.annotation.Retention; @@ -57,10 +55,6 @@ import java.util.stream.Collectors; */ @RavenwoodKeepWholeClass public class Build { - static { - // Set up the default system properties. - RavenwoodEnvironment.ensureRavenwoodInitialized(); - } private static final String TAG = "Build"; /** Value used for when a build property is unknown. */ @@ -1571,6 +1565,61 @@ public class Build { /** A string that uniquely identifies this build. Do not attempt to parse this value. */ public static final String FINGERPRINT = deriveFingerprint(); + /** The status of the known issue on this device is not known. */ + @FlaggedApi(android.os.Flags.FLAG_API_FOR_BACKPORTED_FIXES) + public static final int BACKPORTED_FIX_STATUS_UNKNOWN = 0; + /** The known issue is fixed on this device. */ + @FlaggedApi(android.os.Flags.FLAG_API_FOR_BACKPORTED_FIXES) + public static final int BACKPORTED_FIX_STATUS_FIXED = 1; + /** + * The known issue is not applicable to this device. + * + *

    For example if the issue only affects a specific brand, devices + * from other brands would report not applicable. + */ + @FlaggedApi(android.os.Flags.FLAG_API_FOR_BACKPORTED_FIXES) + public static final int BACKPORTED_FIX_STATUS_NOT_APPLICABLE = 2; + /** The known issue is not fixed on this device. */ + @FlaggedApi(android.os.Flags.FLAG_API_FOR_BACKPORTED_FIXES) + public static final int BACKPORTED_FIX_STATUS_NOT_FIXED = 3; + + /** + * The status of the backported fix for a known issue on this device. + * + * @hide + */ + @IntDef( + prefix = {"BACKPORTED_FIX_STATUS_"}, + value = { + BACKPORTED_FIX_STATUS_UNKNOWN, + BACKPORTED_FIX_STATUS_FIXED, + BACKPORTED_FIX_STATUS_NOT_APPLICABLE, + BACKPORTED_FIX_STATUS_NOT_FIXED, + }) + @Retention(RetentionPolicy.SOURCE) + public @interface BackportedFixStatus { + } + + /** + * The status of the backported fix for a known issue on this device. + * + * @param id The id of the known issue to check. + * @return {@link #BACKPORTED_FIX_STATUS_FIXED} if the known issue is + * fixed on this device, + * {@link #BACKPORTED_FIX_STATUS_NOT_FIXED} if the known issue is not + * fixed on this device, + * {@link #BACKPORTED_FIX_STATUS_NOT_APPLICABLE} if the known issue is + * is not applicable on this device, + * otherwise {@link #BACKPORTED_FIX_STATUS_UNKNOWN}. + */ + + @FlaggedApi(android.os.Flags.FLAG_API_FOR_BACKPORTED_FIXES) + public static @BackportedFixStatus int getBackportedFixStatus(long id) { + // TODO: b/308461809 - query aliases from system prop + // TODO: b/372518979 - use backported fix datastore. + return BACKPORTED_FIX_STATUS_UNKNOWN; + } + /** * Some devices split the fingerprint components between multiple * partitions, so we might derive the fingerprint at runtime. diff --git a/core/java/android/os/CombinedMessageQueue/MessageQueue.java b/core/java/android/os/CombinedMessageQueue/MessageQueue.java index 66f4198ad31c38b0a4b505fa8620b3e1634b5177..69bd6685bcac24bd770e917ecb793be8aed2f829 100644 --- a/core/java/android/os/CombinedMessageQueue/MessageQueue.java +++ b/core/java/android/os/CombinedMessageQueue/MessageQueue.java @@ -55,7 +55,7 @@ import java.util.concurrent.locks.ReentrantLock; * {@link Looper#myQueue() Looper.myQueue()}. */ @RavenwoodKeepWholeClass -@RavenwoodRedirectionClass("MessageQueue_host") +@RavenwoodRedirectionClass("MessageQueue_ravenwood") public final class MessageQueue { private static final String TAG_L = "LegacyMessageQueue"; private static final String TAG_C = "ConcurrentMessageQueue"; @@ -93,9 +93,7 @@ public final class MessageQueue { * system processes and provides a higher level of concurrency and higher enqueue throughput * than the legacy implementation. */ - private static boolean sUseConcurrent; - - private static boolean sUseConcurrentInitialized = false; + private boolean mUseConcurrent; @RavenwoodRedirect private native static long nativeInit(); @@ -112,10 +110,7 @@ public final class MessageQueue { private native static void nativeSetFileDescriptorEvents(long ptr, int fd, int events); MessageQueue(boolean quitAllowed) { - if (!sUseConcurrentInitialized) { - sUseConcurrent = UserHandle.isCore(Process.myUid()); - sUseConcurrentInitialized = true; - } + mUseConcurrent = UserHandle.isCore(Process.myUid()); mQuitAllowed = quitAllowed; mPtr = nativeInit(); } @@ -158,7 +153,7 @@ public final class MessageQueue { * @return True if the looper is idle. */ public boolean isIdle() { - if (sUseConcurrent) { + if (mUseConcurrent) { final long now = SystemClock.uptimeMillis(); if (stackHasMessages(null, 0, null, null, now, mMatchDeliverableMessages, false)) { @@ -208,7 +203,7 @@ public final class MessageQueue { if (handler == null) { throw new NullPointerException("Can't add a null IdleHandler"); } - if (sUseConcurrent) { + if (mUseConcurrent) { synchronized (mIdleHandlersLock) { mIdleHandlers.add(handler); } @@ -229,7 +224,7 @@ public final class MessageQueue { * @param handler The IdleHandler to be removed. */ public void removeIdleHandler(@NonNull IdleHandler handler) { - if (sUseConcurrent) { + if (mUseConcurrent) { synchronized (mIdleHandlersLock) { mIdleHandlers.remove(handler); } @@ -252,7 +247,7 @@ public final class MessageQueue { * @hide */ public boolean isPolling() { - if (sUseConcurrent) { + if (mUseConcurrent) { // If the loop is quitting then it must not be idling. // We can assume mPtr != 0 when sQuitting is false. return !((boolean) sQuitting.getVolatile(this)) && nativeIsPolling(mPtr); @@ -303,7 +298,7 @@ public final class MessageQueue { throw new IllegalArgumentException("listener must not be null"); } - if (sUseConcurrent) { + if (mUseConcurrent) { synchronized (mFileDescriptorRecordsLock) { updateOnFileDescriptorEventListenerLocked(fd, events, listener); } @@ -331,7 +326,7 @@ public final class MessageQueue { if (fd == null) { throw new IllegalArgumentException("fd must not be null"); } - if (sUseConcurrent) { + if (mUseConcurrent) { synchronized (mFileDescriptorRecordsLock) { updateOnFileDescriptorEventListenerLocked(fd, 0, null); } @@ -388,7 +383,7 @@ public final class MessageQueue { final int oldWatchedEvents; final OnFileDescriptorEventListener listener; final int seq; - if (sUseConcurrent) { + if (mUseConcurrent) { synchronized (mFileDescriptorRecordsLock) { record = mFileDescriptorRecords.get(fd); if (record == null) { @@ -431,13 +426,26 @@ public final class MessageQueue { // Update the file descriptor record if the listener changed the set of // events to watch and the listener itself hasn't been updated since. if (newWatchedEvents != oldWatchedEvents) { - synchronized (this) { - int index = mFileDescriptorRecords.indexOfKey(fd); - if (index >= 0 && mFileDescriptorRecords.valueAt(index) == record - && record.mSeq == seq) { - record.mEvents = newWatchedEvents; - if (newWatchedEvents == 0) { - mFileDescriptorRecords.removeAt(index); + if (mUseConcurrent) { + synchronized (mFileDescriptorRecordsLock) { + int index = mFileDescriptorRecords.indexOfKey(fd); + if (index >= 0 && mFileDescriptorRecords.valueAt(index) == record + && record.mSeq == seq) { + record.mEvents = newWatchedEvents; + if (newWatchedEvents == 0) { + mFileDescriptorRecords.removeAt(index); + } + } + } + } else { + synchronized (this) { + int index = mFileDescriptorRecords.indexOfKey(fd); + if (index >= 0 && mFileDescriptorRecords.valueAt(index) == record + && record.mSeq == seq) { + record.mEvents = newWatchedEvents; + if (newWatchedEvents == 0) { + mFileDescriptorRecords.removeAt(index); + } } } } @@ -708,7 +716,7 @@ public final class MessageQueue { @UnsupportedAppUsage Message next() { - if (sUseConcurrent) { + if (mUseConcurrent) { return nextConcurrent(); } @@ -834,7 +842,7 @@ public final class MessageQueue { throw new IllegalStateException("Main thread not allowed to quit."); } - if (sUseConcurrent) { + if (mUseConcurrent) { synchronized (mIdleHandlersLock) { if (sQuitting.compareAndSet(this, false, true)) { if (safe) { @@ -898,7 +906,7 @@ public final class MessageQueue { private int postSyncBarrier(long when) { // Enqueue a new sync barrier token. // We don't need to wake the queue because the purpose of a barrier is to stall it. - if (sUseConcurrent) { + if (mUseConcurrent) { final int token = mNextBarrierTokenAtomic.getAndIncrement(); // b/376573804: apps and tests may expect to be able to use reflection @@ -991,7 +999,7 @@ public final class MessageQueue { public void removeSyncBarrier(int token) { // Remove a sync barrier token from the queue. // If the queue is no longer stalled by a barrier then wake it. - if (sUseConcurrent) { + if (mUseConcurrent) { boolean removed; MessageNode first; final MatchBarrierToken matchBarrierToken = new MatchBarrierToken(token); @@ -1058,7 +1066,7 @@ public final class MessageQueue { throw new IllegalArgumentException("Message must have a target."); } - if (sUseConcurrent) { + if (mUseConcurrent) { if (msg.isInUse()) { throw new IllegalStateException(msg + " This message is already in use."); } @@ -1187,7 +1195,7 @@ public final class MessageQueue { if (h == null) { return false; } - if (sUseConcurrent) { + if (mUseConcurrent) { return findOrRemoveMessages(h, what, object, null, 0, mMatchHandlerWhatAndObject, false); } @@ -1219,7 +1227,7 @@ public final class MessageQueue { if (h == null) { return false; } - if (sUseConcurrent) { + if (mUseConcurrent) { return findOrRemoveMessages(h, what, object, null, 0, mMatchHandlerWhatAndObjectEquals, false); @@ -1253,7 +1261,7 @@ public final class MessageQueue { if (h == null) { return false; } - if (sUseConcurrent) { + if (mUseConcurrent) { return findOrRemoveMessages(h, -1, object, r, 0, mMatchHandlerRunnableAndObject, false); } @@ -1285,7 +1293,7 @@ public final class MessageQueue { if (h == null) { return false; } - if (sUseConcurrent) { + if (mUseConcurrent) { return findOrRemoveMessages(h, -1, null, null, 0, mMatchHandler, false); } synchronized (this) { @@ -1304,7 +1312,7 @@ public final class MessageQueue { if (h == null) { return; } - if (sUseConcurrent) { + if (mUseConcurrent) { findOrRemoveMessages(h, what, object, null, 0, mMatchHandlerWhatAndObject, true); return; } @@ -1355,7 +1363,7 @@ public final class MessageQueue { return; } - if (sUseConcurrent) { + if (mUseConcurrent) { findOrRemoveMessages(h, what, object, null, 0, mMatchHandlerWhatAndObjectEquals, true); return; } @@ -1407,7 +1415,7 @@ public final class MessageQueue { return; } - if (sUseConcurrent) { + if (mUseConcurrent) { findOrRemoveMessages(h, -1, object, r, 0, mMatchHandlerRunnableAndObject, true); return; } @@ -1470,7 +1478,7 @@ public final class MessageQueue { return; } - if (sUseConcurrent) { + if (mUseConcurrent) { findOrRemoveMessages(h, -1, object, r, 0, mMatchHandlerRunnableAndObjectEquals, true); return; } @@ -1532,7 +1540,7 @@ public final class MessageQueue { return; } - if (sUseConcurrent) { + if (mUseConcurrent) { findOrRemoveMessages(h, -1, object, null, 0, mMatchHandlerAndObject, true); return; } @@ -1594,7 +1602,7 @@ public final class MessageQueue { return; } - if (sUseConcurrent) { + if (mUseConcurrent) { findOrRemoveMessages(h, -1, object, null, 0, mMatchHandlerAndObjectEquals, true); return; } @@ -1742,7 +1750,7 @@ public final class MessageQueue { @NeverCompile void dump(Printer pw, String prefix, Handler h) { - if (sUseConcurrent) { + if (mUseConcurrent) { long now = SystemClock.uptimeMillis(); int n = 0; @@ -1803,7 +1811,7 @@ public final class MessageQueue { @NeverCompile void dumpDebug(ProtoOutputStream proto, long fieldId) { - if (sUseConcurrent) { + if (mUseConcurrent) { final long messageQueueToken = proto.start(fieldId); StackNode node = (StackNode) sState.getVolatile(this); diff --git a/core/java/android/os/ConcurrentMessageQueue/MessageQueue.java b/core/java/android/os/ConcurrentMessageQueue/MessageQueue.java index 9db88d17614b3a727579cb84c5bce5a30087af81..c2a47d7678014c4246cec15409f08d6a04a51f17 100644 --- a/core/java/android/os/ConcurrentMessageQueue/MessageQueue.java +++ b/core/java/android/os/ConcurrentMessageQueue/MessageQueue.java @@ -54,7 +54,7 @@ import java.util.concurrent.locks.ReentrantLock; * {@link Looper#myQueue() Looper.myQueue()}. */ @RavenwoodKeepWholeClass -@RavenwoodRedirectionClass("MessageQueue_host") +@RavenwoodRedirectionClass("MessageQueue_ravenwood") public final class MessageQueue { private static final String TAG = "ConcurrentMessageQueue"; private static final boolean DEBUG = false; diff --git a/core/java/android/os/IThermalHeadroomListener.aidl b/core/java/android/os/IThermalHeadroomListener.aidl new file mode 100644 index 0000000000000000000000000000000000000000..b2797d8805fadf2df46f40927d200ead4437bb74 --- /dev/null +++ b/core/java/android/os/IThermalHeadroomListener.aidl @@ -0,0 +1,31 @@ +/* +** 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; + +/** + * Listener for thermal headroom and threshold changes. + * This is mainly used by {@link android.os.PowerManager} to serve public thermal headoom related + * APIs. + * {@hide} + */ +oneway interface IThermalHeadroomListener { + /** + * Called when thermal headroom or thresholds changed. + */ + void onHeadroomChange(in float headroom, in float forecastHeadroom, + in int forecastSeconds, in float[] thresholds); +} diff --git a/core/java/android/os/IThermalService.aidl b/core/java/android/os/IThermalService.aidl index bcffa45fbbd286af12b08dcfeb49c3ba554d466c..aa3bcfab6b6605c8571597758b49bd93a0f72046 100644 --- a/core/java/android/os/IThermalService.aidl +++ b/core/java/android/os/IThermalService.aidl @@ -18,6 +18,7 @@ package android.os; import android.os.CoolingDevice; import android.os.IThermalEventListener; +import android.os.IThermalHeadroomListener; import android.os.IThermalStatusListener; import android.os.Temperature; @@ -116,4 +117,20 @@ interface IThermalService { * @return thermal headroom for each thermal status */ float[] getThermalHeadroomThresholds(); + + /** + * Register a listener for thermal headroom change. + * @param listener the {@link android.os.IThermalHeadroomListener} to be notified. + * @return true if registered successfully. + * {@hide} + */ + boolean registerThermalHeadroomListener(in IThermalHeadroomListener listener); + + /** + * Unregister a previously-registered listener for thermal headroom. + * @param listener the {@link android.os.IThermalHeadroomListener} to no longer be notified. + * @return true if unregistered successfully. + * {@hide} + */ + boolean unregisterThermalHeadroomListener(in IThermalHeadroomListener listener); } diff --git a/core/java/android/os/IVibratorManagerService.aidl b/core/java/android/os/IVibratorManagerService.aidl index 6aa9852314dfa81711502a2d0761844d4951e0c6..ecb5e6f1b29a29e5c203e918e5f6554737965950 100644 --- a/core/java/android/os/IVibratorManagerService.aidl +++ b/core/java/android/os/IVibratorManagerService.aidl @@ -17,13 +17,17 @@ package android.os; import android.os.CombinedVibration; +import android.os.ICancellationSignal; import android.os.IVibratorStateListener; import android.os.VibrationAttributes; import android.os.VibratorInfo; +import android.os.vibrator.IVibrationSession; +import android.os.vibrator.IVibrationSessionCallback; /** {@hide} */ interface IVibratorManagerService { int[] getVibratorIds(); + int getCapabilities(); VibratorInfo getVibratorInfo(int vibratorId); @EnforcePermission("ACCESS_VIBRATOR_STATE") boolean isVibrating(int vibratorId); @@ -50,4 +54,9 @@ interface IVibratorManagerService { oneway void performHapticFeedbackForInputDevice(int uid, int deviceId, String opPkg, int constant, int inputDeviceId, int inputSource, String reason, int flags, int privFlags); + + @EnforcePermission(allOf={"VIBRATE", "VIBRATE_VENDOR_EFFECTS", "START_VIBRATION_SESSIONS"}) + ICancellationSignal startVendorVibrationSession(int uid, int deviceId, String opPkg, + in int[] vibratorIds, in VibrationAttributes attributes, String reason, + in IVibrationSessionCallback callback); } diff --git a/core/java/android/os/IpcDataCache.java b/core/java/android/os/IpcDataCache.java index 7875c23be038aa1ec7105a66115762aa0097d1d6..8db1567336d3ddb9f4154a92b0499fb16cb5b384 100644 --- a/core/java/android/os/IpcDataCache.java +++ b/core/java/android/os/IpcDataCache.java @@ -23,6 +23,7 @@ import android.annotation.StringDef; import android.annotation.SystemApi; import android.annotation.TestApi; import android.app.PropertyInvalidatedCache; +import android.app.PropertyInvalidatedCache.Args; import android.text.TextUtils; import android.util.ArraySet; @@ -341,7 +342,7 @@ public class IpcDataCache extends PropertyInvalidatedCache computer) { - super(maxEntries, module, api, cacheName, computer); + super(new Args(module).maxEntries(maxEntries).api(api), cacheName, computer); } /** @@ -563,7 +564,8 @@ public class IpcDataCache extends PropertyInvalidatedCache computer) { - super(config.maxEntries(), config.module(), config.api(), config.name(), computer); + super(new Args(config.module()).maxEntries(config.maxEntries()).api(config.api()), + config.name(), computer); } /** diff --git a/core/java/android/os/LegacyMessageQueue/MessageQueue.java b/core/java/android/os/LegacyMessageQueue/MessageQueue.java index 9f7b0b71ae95facea43f9fab19810e8d869eebcf..cae82d010132f646e999256edc5c28ecb39fbddb 100644 --- a/core/java/android/os/LegacyMessageQueue/MessageQueue.java +++ b/core/java/android/os/LegacyMessageQueue/MessageQueue.java @@ -45,7 +45,7 @@ import java.util.concurrent.atomic.AtomicLong; * {@link Looper#myQueue() Looper.myQueue()}. */ @RavenwoodKeepWholeClass -@RavenwoodRedirectionClass("MessageQueue_host") +@RavenwoodRedirectionClass("MessageQueue_ravenwood") public final class MessageQueue { private static final String TAG = "MessageQueue"; private static final boolean DEBUG = false; diff --git a/core/java/android/os/LockedMessageQueue/MessageQueue.java b/core/java/android/os/LockedMessageQueue/MessageQueue.java index f3eec13cb20f09face3ef4008976359a97e85db7..2401f3d11bcf8abc202299c7cccc520a4aff4823 100644 --- a/core/java/android/os/LockedMessageQueue/MessageQueue.java +++ b/core/java/android/os/LockedMessageQueue/MessageQueue.java @@ -48,7 +48,7 @@ import java.util.concurrent.atomic.AtomicLong; * {@link Looper#myQueue() Looper.myQueue()}. */ @RavenwoodKeepWholeClass -@RavenwoodRedirectionClass("MessageQueue_host") +@RavenwoodRedirectionClass("MessageQueue_ravenwood") public final class MessageQueue { private static final String TAG = "LockedMessageQueue"; private static final boolean DEBUG = false; diff --git a/ravenwood/runtime-helper-src/framework/android/os/MessageQueue_host.java b/core/java/android/os/MessageQueue_ravenwood.java similarity index 87% rename from ravenwood/runtime-helper-src/framework/android/os/MessageQueue_host.java rename to core/java/android/os/MessageQueue_ravenwood.java index 1b63adc4319f9c90326397fa34c2f68505d29ead..4033707c3253a57435ddc30471c8721ef649ebb1 100644 --- a/ravenwood/runtime-helper-src/framework/android/os/MessageQueue_host.java +++ b/core/java/android/os/MessageQueue_ravenwood.java @@ -16,13 +16,16 @@ package android.os; +import android.ravenwood.annotation.RavenwoodKeepWholeClass; + import java.util.Map; import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.atomic.AtomicLong; -public class MessageQueue_host { +@RavenwoodKeepWholeClass +class MessageQueue_ravenwood { private static final AtomicLong sNextId = new AtomicLong(1); - private static final Map sInstances = new ConcurrentHashMap<>(); + private static final Map sInstances = new ConcurrentHashMap<>(); private boolean mDeleted = false; @@ -37,8 +40,8 @@ public class MessageQueue_host { } } - private static MessageQueue_host getInstance(long id) { - MessageQueue_host q = sInstances.get(id); + private static MessageQueue_ravenwood getInstance(long id) { + MessageQueue_ravenwood q = sInstances.get(id); if (q == null) { throw new RuntimeException("MessageQueue doesn't exist with id=" + id); } @@ -48,7 +51,7 @@ public class MessageQueue_host { public static long nativeInit() { final long id = sNextId.getAndIncrement(); - final MessageQueue_host q = new MessageQueue_host(); + final MessageQueue_ravenwood q = new MessageQueue_ravenwood(); sInstances.put(id, q); return id; } diff --git a/core/java/android/os/ParcelFileDescriptor.java b/core/java/android/os/ParcelFileDescriptor.java index e80efd2a9380c2a9633fd9fd20474ebf60c6bd65..60eeb2b8b0d5787cd397bd4162e3da70488ddd5b 100644 --- a/core/java/android/os/ParcelFileDescriptor.java +++ b/core/java/android/os/ParcelFileDescriptor.java @@ -41,7 +41,6 @@ import android.content.ContentResolver; import android.net.Uri; import android.os.MessageQueue.OnFileDescriptorEventListener; import android.ravenwood.annotation.RavenwoodKeepWholeClass; -import android.ravenwood.annotation.RavenwoodReplace; import android.ravenwood.annotation.RavenwoodThrow; import android.system.ErrnoException; import android.system.Os; @@ -51,8 +50,6 @@ import android.util.CloseGuard; import android.util.Log; import android.util.Slog; -import com.android.internal.ravenwood.RavenwoodEnvironment; - import dalvik.system.VMRuntime; import libcore.io.IoUtils; @@ -1254,15 +1251,10 @@ public class ParcelFileDescriptor implements Parcelable, Closeable { } } - @RavenwoodReplace private static boolean isAtLeastQ() { return (VMRuntime.getRuntime().getTargetSdkVersion() >= Build.VERSION_CODES.Q); } - private static boolean isAtLeastQ$ravenwood() { - return RavenwoodEnvironment.workaround().isTargetSdkAtLeastQ(); - } - private static int ifAtLeastQ(int value) { return isAtLeastQ() ? value : 0; } diff --git a/core/java/android/os/PowerComponents.java b/core/java/android/os/PowerComponents.java index f4e3f3b6e430fb119680d75dd1c6e3e25dfbffe0..d116e0737c460685f69a408296cf962bd99457d4 100644 --- a/core/java/android/os/PowerComponents.java +++ b/core/java/android/os/PowerComponents.java @@ -439,8 +439,8 @@ class PowerComponents { } final BatteryConsumer.Key key = builder.mData.layout.getKey(componentId, processState, screenState, powerState); - builder.setConsumedPower(key, powerMah, model); - builder.setUsageDurationMillis(key, durationMs); + builder.addConsumedPower(key, powerMah, model); + builder.addUsageDurationMillis(key, durationMs); break; } } @@ -468,6 +468,10 @@ class PowerComponents { } } + /** + * @deprecated use {@link #addConsumedPower(BatteryConsumer.Key, double, int)} + */ + @Deprecated @NonNull public Builder setConsumedPower(BatteryConsumer.Key key, double componentPower, int powerModel) { @@ -489,6 +493,10 @@ class PowerComponents { return this; } + /** + * @deprecated use {@link #addUsageDurationMillis(BatteryConsumer.Key, long)} + */ + @Deprecated @NonNull public Builder setUsageDurationMillis(BatteryConsumer.Key key, long componentUsageDurationMillis) { diff --git a/core/java/android/os/PowerManager.java b/core/java/android/os/PowerManager.java index 9d4ac2963b2d185c26a2a052f0f3c06e66d76b96..07fded19c79943f8e9e2d706916002b5583cd399 100644 --- a/core/java/android/os/PowerManager.java +++ b/core/java/android/os/PowerManager.java @@ -20,6 +20,7 @@ import android.Manifest.permission; import android.annotation.CallbackExecutor; import android.annotation.CurrentTimeMillisLong; import android.annotation.FlaggedApi; +import android.annotation.FloatRange; import android.annotation.IntDef; import android.annotation.IntRange; import android.annotation.NonNull; @@ -40,6 +41,7 @@ import android.util.Log; import android.util.proto.ProtoOutputStream; import android.view.Display; +import com.android.internal.annotations.GuardedBy; import com.android.internal.util.Preconditions; import java.lang.annotation.ElementType; @@ -1199,10 +1201,12 @@ public final class PowerManager { /** We lazily initialize it.*/ private PowerExemptionManager mPowerExemptionManager; + @GuardedBy("mThermalStatusListenerMap") private final ArrayMap - mListenerMap = new ArrayMap<>(); - private final Object mThermalHeadroomThresholdsLock = new Object(); - private float[] mThermalHeadroomThresholds = null; + mThermalStatusListenerMap = new ArrayMap<>(); + @GuardedBy("mThermalHeadroomListenerMap") + private final ArrayMap + mThermalHeadroomListenerMap = new ArrayMap<>(); /** * {@hide} @@ -2689,15 +2693,59 @@ public final class PowerManager { void onThermalStatusChanged(@ThermalStatus int status); } + /** + * Listener passed to + * {@link PowerManager#addThermalHeadroomListener} and + * {@link PowerManager#removeThermalHeadroomListener} + * to notify caller of Thermal headroom or thresholds changes. + */ + @FlaggedApi(Flags.FLAG_ALLOW_THERMAL_THRESHOLDS_CALLBACK) + public interface OnThermalHeadroomChangedListener { + + /** + * Called when overall thermal headroom or headroom thresholds have significantly + * changed that requires action. + *

    + * This may not be used to fully replace the {@link #getThermalHeadroom(int)} API as it will + * only notify on one of the conditions below that will significantly change one or both + * values of current headroom and headroom thresholds since previous callback: + * 1. thermal throttling events: when the skin temperature has cross any of the thresholds + * and there isn't a previous callback in a short time ago with similar values. + * 2. skin temperature threshold change events: note that if the absolute °C threshold + * values change in a way that does not significantly change the current headroom nor + * headroom thresholds, it will not trigger any callback. The client should not + * need to take action in such case since the difference from temperature vs threshold + * hasn't changed. + *

    + * By API version 36, it provides a forecast in the same call for developer's convenience + * based on a {@code forecastSeconds} defined by the device, which can be static or dynamic + * varied by OEM. Be aware that it will not notify on forecast temperature change but the + * events mentioned above. So periodically polling against {@link #getThermalHeadroom(int)} + * API should still be used to actively monitor temperature forecast in advance. + *

    + * This serves as a more advanced option compared to thermal status listener, where the + * latter will only notify on thermal throttling events with status update. + * + * @param headroom current headroom + * @param forecastHeadroom forecasted headroom in future + * @param forecastSeconds how many seconds in the future used in forecast + * @param thresholds new headroom thresholds, see {@link #getThermalHeadroomThresholds()} + */ + void onThermalHeadroomChanged( + @FloatRange(from = 0f) float headroom, + @FloatRange(from = 0f) float forecastHeadroom, + @IntRange(from = 0) int forecastSeconds, + @NonNull Map<@ThermalStatus Integer, Float> thresholds); + } /** - * This function adds a listener for thermal status change, listen call back will be + * This function adds a listener for thermal status change, listener callback will be * enqueued tasks on the main thread * * @param listener listener to be added, */ public void addThermalStatusListener(@NonNull OnThermalStatusChangedListener listener) { - Objects.requireNonNull(listener, "listener cannot be null"); + Objects.requireNonNull(listener, "Thermal status listener cannot be null"); addThermalStatusListener(mContext.getMainExecutor(), listener); } @@ -2709,29 +2757,31 @@ public final class PowerManager { */ public void addThermalStatusListener(@NonNull @CallbackExecutor Executor executor, @NonNull OnThermalStatusChangedListener listener) { - Objects.requireNonNull(listener, "listener cannot be null"); - Objects.requireNonNull(executor, "executor cannot be null"); - Preconditions.checkArgument(!mListenerMap.containsKey(listener), - "Listener already registered: %s", listener); - IThermalStatusListener internalListener = new IThermalStatusListener.Stub() { - @Override - public void onStatusChange(int status) { - final long token = Binder.clearCallingIdentity(); - try { - executor.execute(() -> listener.onThermalStatusChanged(status)); - } finally { - Binder.restoreCallingIdentity(token); + Objects.requireNonNull(listener, "Thermal status listener cannot be null"); + Objects.requireNonNull(executor, "Executor cannot be null"); + synchronized (mThermalStatusListenerMap) { + Preconditions.checkArgument(!mThermalStatusListenerMap.containsKey(listener), + "Thermal status listener already registered: %s", listener); + IThermalStatusListener internalListener = new IThermalStatusListener.Stub() { + @Override + public void onStatusChange(int status) { + final long token = Binder.clearCallingIdentity(); + try { + executor.execute(() -> listener.onThermalStatusChanged(status)); + } finally { + Binder.restoreCallingIdentity(token); + } } + }; + try { + if (mThermalService.registerThermalStatusListener(internalListener)) { + mThermalStatusListenerMap.put(listener, internalListener); + } else { + throw new RuntimeException("Thermal status listener failed to set"); + } + } catch (RemoteException e) { + throw e.rethrowFromSystemServer(); } - }; - try { - if (mThermalService.registerThermalStatusListener(internalListener)) { - mListenerMap.put(listener, internalListener); - } else { - throw new RuntimeException("Listener failed to set"); - } - } catch (RemoteException e) { - throw e.rethrowFromSystemServer(); } } @@ -2741,20 +2791,101 @@ public final class PowerManager { * @param listener listener to be removed */ public void removeThermalStatusListener(@NonNull OnThermalStatusChangedListener listener) { - Objects.requireNonNull(listener, "listener cannot be null"); - IThermalStatusListener internalListener = mListenerMap.get(listener); - Preconditions.checkArgument(internalListener != null, "Listener was not added"); - try { - if (mThermalService.unregisterThermalStatusListener(internalListener)) { - mListenerMap.remove(listener); - } else { - throw new RuntimeException("Listener failed to remove"); + Objects.requireNonNull(listener, "Thermal status listener cannot be null"); + synchronized (mThermalStatusListenerMap) { + IThermalStatusListener internalListener = mThermalStatusListenerMap.get(listener); + Preconditions.checkArgument(internalListener != null, + "Thermal status listener was not added"); + try { + if (mThermalService.unregisterThermalStatusListener(internalListener)) { + mThermalStatusListenerMap.remove(listener); + } else { + throw new RuntimeException("Failed to unregister thermal status listener"); + } + } catch (RemoteException e) { + throw e.rethrowFromSystemServer(); } - } catch (RemoteException e) { - throw e.rethrowFromSystemServer(); } } + /** + * This function adds a listener for thermal headroom change, listener callback will be + * enqueued tasks on the main thread + * + * @param listener listener to be added, + */ + @FlaggedApi(Flags.FLAG_ALLOW_THERMAL_THRESHOLDS_CALLBACK) + public void addThermalHeadroomListener(@NonNull OnThermalHeadroomChangedListener listener) { + Objects.requireNonNull(listener, "Thermal headroom listener cannot be null"); + addThermalHeadroomListener(mContext.getMainExecutor(), listener); + } + + /** + * This function adds a listener for thermal headroom change. + * + * @param executor {@link Executor} to handle listener callback. + * @param listener listener to be added. + */ + @FlaggedApi(Flags.FLAG_ALLOW_THERMAL_THRESHOLDS_CALLBACK) + public void addThermalHeadroomListener(@NonNull @CallbackExecutor Executor executor, + @NonNull OnThermalHeadroomChangedListener listener) { + Objects.requireNonNull(listener, "Thermal headroom listener cannot be null"); + Objects.requireNonNull(executor, "Executor cannot be null"); + synchronized (mThermalHeadroomListenerMap) { + Preconditions.checkArgument(!mThermalHeadroomListenerMap.containsKey(listener), + "Thermal headroom listener already registered: %s", listener); + IThermalHeadroomListener internalListener = new IThermalHeadroomListener.Stub() { + @Override + public void onHeadroomChange(float headroom, float forecastHeadroom, + int forecastSeconds, float[] thresholds) + throws RemoteException { + final Map map = convertThresholdsToMap(thresholds); + final long token = Binder.clearCallingIdentity(); + try { + executor.execute(() -> listener.onThermalHeadroomChanged(headroom, + forecastHeadroom, forecastSeconds, map)); + } finally { + Binder.restoreCallingIdentity(token); + } + } + }; + try { + if (mThermalService.registerThermalHeadroomListener(internalListener)) { + mThermalHeadroomListenerMap.put(listener, internalListener); + } else { + throw new RuntimeException("Thermal headroom listener failed to set"); + } + } catch (RemoteException e) { + throw e.rethrowFromSystemServer(); + } + } + } + + /** + * This function removes a listener for Thermal headroom change + * + * @param listener listener to be removed + */ + @FlaggedApi(Flags.FLAG_ALLOW_THERMAL_THRESHOLDS_CALLBACK) + public void removeThermalHeadroomListener(@NonNull OnThermalHeadroomChangedListener listener) { + Objects.requireNonNull(listener, "Thermal headroom listener cannot be null"); + synchronized (mThermalHeadroomListenerMap) { + IThermalHeadroomListener internalListener = mThermalHeadroomListenerMap.get(listener); + Preconditions.checkArgument(internalListener != null, + "Thermal headroom listener was not added"); + try { + if (mThermalService.unregisterThermalHeadroomListener(internalListener)) { + mThermalHeadroomListenerMap.remove(listener); + } else { + throw new RuntimeException("Failed to unregister thermal status listener"); + } + } catch (RemoteException e) { + throw e.rethrowFromSystemServer(); + } + } + } + + @CurrentTimeMillisLong private final AtomicLong mLastHeadroomUpdate = new AtomicLong(0L); private static final int MINIMUM_HEADROOM_TIME_MILLIS = 500; @@ -2794,7 +2925,8 @@ public final class PowerManager { * functionality or if this function is called significantly faster than once per * second. */ - public float getThermalHeadroom(@IntRange(from = 0, to = 60) int forecastSeconds) { + public @FloatRange(from = 0f) float getThermalHeadroom( + @IntRange(from = 0, to = 60) int forecastSeconds) { // Rate-limit calls into the thermal service long now = SystemClock.elapsedRealtime(); long timeSinceLastUpdate = now - mLastHeadroomUpdate.get(); @@ -2839,9 +2971,11 @@ public final class PowerManager { * headroom of 0.75 will never come with {@link #THERMAL_STATUS_MODERATE} but lower, and 0.65 * will never come with {@link #THERMAL_STATUS_LIGHT} but {@link #THERMAL_STATUS_NONE}. *

    - * The returned map of thresholds will not change between calls to this function, so it's - * best to call this once on initialization. Modifying the result will not change the thresholds - * cached by the system, and a new call to the API will get a new copy. + * Starting at {@link android.os.Build.VERSION_CODES#BAKLAVA} the returned map of thresholds can + * change between calls to this function, one could use the new + * {@link #addThermalHeadroomListener(Executor, OnThermalHeadroomChangedListener)} API to + * register a listener and get callback for changes to thresholds. + *

    * * @return map from each thermal status to its thermal headroom * @throws IllegalStateException if the thermal service is not ready @@ -2850,24 +2984,22 @@ public final class PowerManager { @FlaggedApi(Flags.FLAG_ALLOW_THERMAL_HEADROOM_THRESHOLDS) public @NonNull Map<@ThermalStatus Integer, Float> getThermalHeadroomThresholds() { try { - synchronized (mThermalHeadroomThresholdsLock) { - if (mThermalHeadroomThresholds == null) { - mThermalHeadroomThresholds = mThermalService.getThermalHeadroomThresholds(); - } - final ArrayMap ret = new ArrayMap<>(THERMAL_STATUS_SHUTDOWN); - for (int status = THERMAL_STATUS_LIGHT; status <= THERMAL_STATUS_SHUTDOWN; - status++) { - if (!Float.isNaN(mThermalHeadroomThresholds[status])) { - ret.put(status, mThermalHeadroomThresholds[status]); - } - } - return ret; - } + return convertThresholdsToMap(mThermalService.getThermalHeadroomThresholds()); } catch (RemoteException e) { throw e.rethrowFromSystemServer(); } } + private Map<@ThermalStatus Integer, Float> convertThresholdsToMap(final float[] thresholds) { + final ArrayMap ret = new ArrayMap<>(THERMAL_STATUS_SHUTDOWN); + for (int status = THERMAL_STATUS_LIGHT; status <= THERMAL_STATUS_SHUTDOWN; status++) { + if (!Float.isNaN(thresholds[status])) { + ret.put(status, thresholds[status]); + } + } + return ret; + } + /** * If true, the doze component is not started until after the screen has been * turned off and the screen off animation has been performed. diff --git a/core/java/android/os/Process.java b/core/java/android/os/Process.java index 71d29af6cf0251f714ecd43e8747f751a77c45b5..e7282435ad46bfc775cc7fc57d3de9f4d94f4257 100644 --- a/core/java/android/os/Process.java +++ b/core/java/android/os/Process.java @@ -29,6 +29,11 @@ import android.annotation.TestApi; import android.annotation.UptimeMillisLong; import android.compat.annotation.UnsupportedAppUsage; import android.os.Build.VERSION_CODES; +import android.ravenwood.annotation.RavenwoodKeep; +import android.ravenwood.annotation.RavenwoodKeepPartialClass; +import android.ravenwood.annotation.RavenwoodRedirect; +import android.ravenwood.annotation.RavenwoodRedirectionClass; +import android.ravenwood.annotation.RavenwoodReplace; import android.sysprop.MemoryProperties; import android.system.ErrnoException; import android.system.Os; @@ -37,8 +42,6 @@ import android.system.StructPollfd; import android.util.Pair; import android.webkit.WebViewZygote; -import com.android.internal.os.SomeArgs; -import com.android.internal.util.Preconditions; import com.android.sdksandbox.flags.Flags; import dalvik.system.VMDebug; @@ -55,6 +58,8 @@ import java.util.concurrent.TimeoutException; /** * Tools for managing OS processes. */ +@RavenwoodKeepPartialClass +@RavenwoodRedirectionClass("Process_ravenwood") public class Process { private static final String LOG_TAG = "Process"; @@ -671,7 +676,6 @@ public class Process { */ public static final ZygoteProcess ZYGOTE_PROCESS = new ZygoteProcess(); - /** * The process name set via {@link #setArgV0(String)}. */ @@ -845,47 +849,20 @@ public class Process { /** * Returns true if the current process is a 64-bit runtime. */ - @android.ravenwood.annotation.RavenwoodKeep + @RavenwoodKeep public static final boolean is64Bit() { return VMRuntime.getRuntime().is64Bit(); } - private static volatile ThreadLocal sIdentity$ravenwood; - - /** @hide */ - @android.ravenwood.annotation.RavenwoodKeep - public static void init$ravenwood(final int uid, final int pid) { - sIdentity$ravenwood = ThreadLocal.withInitial(() -> { - final SomeArgs args = SomeArgs.obtain(); - args.argi1 = uid; - args.argi2 = pid; - args.argi3 = Long.hashCode(Thread.currentThread().getId()); - args.argi4 = THREAD_PRIORITY_DEFAULT; - args.arg1 = Boolean.TRUE; // backgroundOk - return args; - }); - } - - /** @hide */ - @android.ravenwood.annotation.RavenwoodKeep - public static void reset$ravenwood() { - sIdentity$ravenwood = null; - } - /** * Returns the identifier of this process, which can be used with * {@link #killProcess} and {@link #sendSignal}. */ - @android.ravenwood.annotation.RavenwoodReplace + @RavenwoodKeep public static final int myPid() { return Os.getpid(); } - /** @hide */ - public static final int myPid$ravenwood() { - return Preconditions.requireNonNullViaRavenwoodRule(sIdentity$ravenwood).get().argi2; - } - /** * Returns the identifier of this process' parent. * @hide @@ -899,39 +876,29 @@ public class Process { * Returns the identifier of the calling thread, which be used with * {@link #setThreadPriority(int, int)}. */ - @android.ravenwood.annotation.RavenwoodReplace + @RavenwoodKeep public static final int myTid() { return Os.gettid(); } - /** @hide */ - public static final int myTid$ravenwood() { - return Preconditions.requireNonNullViaRavenwoodRule(sIdentity$ravenwood).get().argi3; - } - /** * Returns the identifier of this process's uid. This is the kernel uid * that the process is running under, which is the identity of its * app-specific sandbox. It is different from {@link #myUserHandle} in that * a uid identifies a specific app sandbox in a specific user. */ - @android.ravenwood.annotation.RavenwoodReplace + @RavenwoodKeep public static final int myUid() { return Os.getuid(); } - /** @hide */ - public static final int myUid$ravenwood() { - return Preconditions.requireNonNullViaRavenwoodRule(sIdentity$ravenwood).get().argi1; - } - /** * Returns this process's user handle. This is the * user the process is running under. It is distinct from * {@link #myUid()} in that a particular user will have multiple * distinct apps running under it each with their own uid. */ - @android.ravenwood.annotation.RavenwoodKeep + @RavenwoodKeep public static UserHandle myUserHandle() { return UserHandle.of(UserHandle.getUserId(myUid())); } @@ -940,7 +907,7 @@ public class Process { * Returns whether the given uid belongs to a system core component or not. * @hide */ - @android.ravenwood.annotation.RavenwoodKeep + @RavenwoodKeep public static boolean isCoreUid(int uid) { return UserHandle.isCore(uid); } @@ -951,7 +918,7 @@ public class Process { * @return Whether the uid corresponds to an application sandbox running in * a specific user. */ - @android.ravenwood.annotation.RavenwoodKeep + @RavenwoodKeep public static boolean isApplicationUid(int uid) { return UserHandle.isApp(uid); } @@ -959,7 +926,7 @@ public class Process { /** * Returns whether the current process is in an isolated sandbox. */ - @android.ravenwood.annotation.RavenwoodKeep + @RavenwoodKeep public static final boolean isIsolated() { return isIsolated(myUid()); } @@ -971,7 +938,7 @@ public class Process { @Deprecated @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.TIRAMISU, publicAlternatives = "Use {@link #isIsolatedUid(int)} instead.") - @android.ravenwood.annotation.RavenwoodKeep + @RavenwoodKeep public static final boolean isIsolated(int uid) { return isIsolatedUid(uid); } @@ -979,7 +946,7 @@ public class Process { /** * Returns whether the process with the given {@code uid} is an isolated sandbox. */ - @android.ravenwood.annotation.RavenwoodKeep + @RavenwoodKeep public static final boolean isIsolatedUid(int uid) { uid = UserHandle.getAppId(uid); return (uid >= FIRST_ISOLATED_UID && uid <= LAST_ISOLATED_UID) @@ -991,7 +958,7 @@ public class Process { * @see android.app.sdksandbox.SdkSandboxManager */ @SuppressLint("UnflaggedApi") // promoting from @SystemApi. - @android.ravenwood.annotation.RavenwoodKeep + @RavenwoodKeep public static final boolean isSdkSandboxUid(int uid) { uid = UserHandle.getAppId(uid); return (uid >= FIRST_SDK_SANDBOX_UID && uid <= LAST_SDK_SANDBOX_UID); @@ -1007,7 +974,7 @@ public class Process { * @throws IllegalArgumentException if input is not an sdk sandbox uid */ @SuppressLint("UnflaggedApi") // promoting from @SystemApi. - @android.ravenwood.annotation.RavenwoodKeep + @RavenwoodKeep public static final int getAppUidForSdkSandboxUid(int uid) { if (!isSdkSandboxUid(uid)) { throw new IllegalArgumentException("Input UID is not an SDK sandbox UID"); @@ -1023,7 +990,7 @@ public class Process { */ @SystemApi(client = MODULE_LIBRARIES) @TestApi - @android.ravenwood.annotation.RavenwoodKeep + @RavenwoodKeep // TODO(b/318651609): Deprecate once Process#getSdkSandboxUidForAppUid is rolled out to 100% public static final int toSdkSandboxUid(int uid) { return uid + (FIRST_SDK_SANDBOX_UID - FIRST_APPLICATION_UID); @@ -1039,7 +1006,7 @@ public class Process { * @throws IllegalArgumentException if input is not an app uid */ @FlaggedApi(Flags.FLAG_SDK_SANDBOX_UID_TO_APP_UID_API) - @android.ravenwood.annotation.RavenwoodKeep + @RavenwoodKeep public static final int getSdkSandboxUidForAppUid(int uid) { if (!isApplicationUid(uid)) { throw new IllegalArgumentException("Input UID is not an app UID"); @@ -1050,7 +1017,7 @@ public class Process { /** * Returns whether the current process is a sdk sandbox process. */ - @android.ravenwood.annotation.RavenwoodKeep + @RavenwoodKeep public static final boolean isSdkSandbox() { return isSdkSandboxUid(myUid()); } @@ -1127,28 +1094,11 @@ public class Process { * not have permission to modify the given thread, or to use the given * priority. */ - @android.ravenwood.annotation.RavenwoodReplace + @RavenwoodRedirect public static final native void setThreadPriority(int tid, @IntRange(from = -20, to = THREAD_PRIORITY_LOWEST) int priority) throws IllegalArgumentException, SecurityException; - /** @hide */ - public static final void setThreadPriority$ravenwood(int tid, int priority) { - final SomeArgs args = - Preconditions.requireNonNullViaRavenwoodRule(sIdentity$ravenwood).get(); - if (args.argi3 == tid) { - boolean backgroundOk = (args.arg1 == Boolean.TRUE); - if (priority >= THREAD_PRIORITY_BACKGROUND && !backgroundOk) { - throw new IllegalArgumentException( - "Priority " + priority + " blocked by setCanSelfBackground()"); - } - args.argi4 = priority; - } else { - throw new UnsupportedOperationException( - "Cross-thread priority management not yet available in Ravenwood"); - } - } - /** * Call with 'false' to cause future calls to {@link #setThreadPriority(int)} to * throw an exception if passed a background-level thread priority. This is only @@ -1156,16 +1106,9 @@ public class Process { * * @hide */ - @android.ravenwood.annotation.RavenwoodReplace + @RavenwoodRedirect public static final native void setCanSelfBackground(boolean backgroundOk); - /** @hide */ - public static final void setCanSelfBackground$ravenwood(boolean backgroundOk) { - final SomeArgs args = - Preconditions.requireNonNullViaRavenwoodRule(sIdentity$ravenwood).get(); - args.arg1 = Boolean.valueOf(backgroundOk); - } - /** * Sets the scheduling group for a thread. * @hide @@ -1294,13 +1237,12 @@ public class Process { * * @see #setThreadPriority(int, int) */ - @android.ravenwood.annotation.RavenwoodReplace + @RavenwoodReplace public static final native void setThreadPriority( @IntRange(from = -20, to = THREAD_PRIORITY_LOWEST) int priority) throws IllegalArgumentException, SecurityException; - /** @hide */ - public static final void setThreadPriority$ravenwood(int priority) { + private static void setThreadPriority$ravenwood(int priority) { setThreadPriority(myTid(), priority); } @@ -1317,23 +1259,11 @@ public class Process { * @throws IllegalArgumentException Throws IllegalArgumentException if * tid does not exist. */ - @android.ravenwood.annotation.RavenwoodReplace + @RavenwoodRedirect @IntRange(from = -20, to = THREAD_PRIORITY_LOWEST) public static final native int getThreadPriority(int tid) throws IllegalArgumentException; - /** @hide */ - public static final int getThreadPriority$ravenwood(int tid) { - final SomeArgs args = - Preconditions.requireNonNullViaRavenwoodRule(sIdentity$ravenwood).get(); - if (args.argi3 == tid) { - return args.argi4; - } else { - throw new UnsupportedOperationException( - "Cross-thread priority management not yet available in Ravenwood"); - } - } - /** * Return the current scheduling policy of a thread, based on Linux. * diff --git a/core/java/android/os/SemiConcurrentMessageQueue/MessageQueue.java b/core/java/android/os/SemiConcurrentMessageQueue/MessageQueue.java index db323dcf90090b8f6478020c31b512e6e0508ad0..435c34f832c6d4fde13bde263847f2000e542258 100644 --- a/core/java/android/os/SemiConcurrentMessageQueue/MessageQueue.java +++ b/core/java/android/os/SemiConcurrentMessageQueue/MessageQueue.java @@ -52,7 +52,7 @@ import java.util.concurrent.atomic.AtomicLong; * {@link Looper#myQueue() Looper.myQueue()}. */ @RavenwoodKeepWholeClass -@RavenwoodRedirectionClass("MessageQueue_host") +@RavenwoodRedirectionClass("MessageQueue_ravenwood") public final class MessageQueue { private static final String TAG = "SemiConcurrentMessageQueue"; private static final boolean DEBUG = false; diff --git a/core/java/android/os/StrictMode.java b/core/java/android/os/StrictMode.java index 90993e1850d463aed204e1bcfdbd478ed17142e4..edeb75b6193d43f78cf2762bff7ff9251c8fd06c 100644 --- a/core/java/android/os/StrictMode.java +++ b/core/java/android/os/StrictMode.java @@ -365,7 +365,7 @@ public final class StrictMode { public static final int NETWORK_POLICY_REJECT = 2; /** - * Detect explicit calls to {@link Runtime#gc()}. + * Detects explicit calls to {@link Runtime#gc()}. */ @ChangeId @EnabledSince(targetSdkVersion = Build.VERSION_CODES.UPSIDE_DOWN_CAKE) @@ -501,7 +501,7 @@ public final class StrictMode { private Executor mExecutor; /** - * Create a Builder that detects nothing and has no violations. (but note that {@link + * Creates a Builder that detects nothing and has no violations. (but note that {@link * #build} will default to enabling {@link #penaltyLog} if no other penalties are * specified) */ @@ -509,7 +509,7 @@ public final class StrictMode { mMask = 0; } - /** Initialize a Builder from an existing ThreadPolicy. */ + /** Initializes a Builder from an existing ThreadPolicy. */ public Builder(ThreadPolicy policy) { mMask = policy.mask; mListener = policy.mListener; @@ -517,7 +517,7 @@ public final class StrictMode { } /** - * Detect everything that's potentially suspect. + * Detects everything that's potentially suspect. * *

    As of the Gingerbread release this includes network and disk operations but will * likely expand in future releases. @@ -544,52 +544,52 @@ public final class StrictMode { return this; } - /** Disable the detection of everything. */ + /** Disables the detection of everything. */ public @NonNull Builder permitAll() { return disable(DETECT_THREAD_ALL); } - /** Enable detection of network operations. */ + /** Enables detection of network operations. */ public @NonNull Builder detectNetwork() { return enable(DETECT_THREAD_NETWORK); } - /** Disable detection of network operations. */ + /** Disables detection of network operations. */ public @NonNull Builder permitNetwork() { return disable(DETECT_THREAD_NETWORK); } - /** Enable detection of disk reads. */ + /** Enables detection of disk reads. */ public @NonNull Builder detectDiskReads() { return enable(DETECT_THREAD_DISK_READ); } - /** Disable detection of disk reads. */ + /** Disables detection of disk reads. */ public @NonNull Builder permitDiskReads() { return disable(DETECT_THREAD_DISK_READ); } - /** Enable detection of slow calls. */ + /** Enables detection of slow calls. */ public @NonNull Builder detectCustomSlowCalls() { return enable(DETECT_THREAD_CUSTOM); } - /** Disable detection of slow calls. */ + /** Disables detection of slow calls. */ public @NonNull Builder permitCustomSlowCalls() { return disable(DETECT_THREAD_CUSTOM); } - /** Disable detection of mismatches between defined resource types and getter calls. */ + /** Disables detection of mismatches between defined resource types and getter calls. */ public @NonNull Builder permitResourceMismatches() { return disable(DETECT_THREAD_RESOURCE_MISMATCH); } - /** Detect unbuffered input/output operations. */ + /** Detects unbuffered input/output operations. */ public @NonNull Builder detectUnbufferedIo() { return enable(DETECT_THREAD_UNBUFFERED_IO); } - /** Disable detection of unbuffered input/output operations. */ + /** Disables detection of unbuffered input/output operations. */ public @NonNull Builder permitUnbufferedIo() { return disable(DETECT_THREAD_UNBUFFERED_IO); } @@ -610,32 +610,32 @@ public final class StrictMode { return enable(DETECT_THREAD_RESOURCE_MISMATCH); } - /** Enable detection of disk writes. */ + /** Enables detection of disk writes. */ public @NonNull Builder detectDiskWrites() { return enable(DETECT_THREAD_DISK_WRITE); } - /** Disable detection of disk writes. */ + /** Disables detection of disk writes. */ public @NonNull Builder permitDiskWrites() { return disable(DETECT_THREAD_DISK_WRITE); } /** - * Detect calls to {@link Runtime#gc()}. + * Detects calls to {@link Runtime#gc()}. */ public @NonNull Builder detectExplicitGc() { return enable(DETECT_THREAD_EXPLICIT_GC); } /** - * Disable detection of calls to {@link Runtime#gc()}. + * Disables detection of calls to {@link Runtime#gc()}. */ public @NonNull Builder permitExplicitGc() { return disable(DETECT_THREAD_EXPLICIT_GC); } /** - * Show an annoying dialog to the developer on detected violations, rate-limited to be + * Shows an annoying dialog to the developer on detected violations, rate-limited to be * only a little annoying. */ public @NonNull Builder penaltyDialog() { @@ -643,7 +643,7 @@ public final class StrictMode { } /** - * Crash the whole process on violation. This penalty runs at the end of all enabled + * Crashes the whole process on violation. This penalty runs at the end of all enabled * penalties so you'll still get see logging or other violations before the process * dies. * @@ -655,7 +655,7 @@ public final class StrictMode { } /** - * Crash the whole process on any network usage. Unlike {@link #penaltyDeath}, this + * Crashes the whole process on any network usage. Unlike {@link #penaltyDeath}, this * penalty runs before anything else. You must still have called {@link * #detectNetwork} to enable this. * @@ -665,18 +665,18 @@ public final class StrictMode { return enable(PENALTY_DEATH_ON_NETWORK); } - /** Flash the screen during a violation. */ + /** Flashes the screen during a violation. */ public @NonNull Builder penaltyFlashScreen() { return enable(PENALTY_FLASH); } - /** Log detected violations to the system log. */ + /** Logs detected violations to the system log. */ public @NonNull Builder penaltyLog() { return enable(PENALTY_LOG); } /** - * Enable detected violations log a stacktrace and timing data to the {@link + * Enables detected violations log a stacktrace and timing data to the {@link * android.os.DropBoxManager DropBox} on policy violation. Intended mostly for platform * integrators doing beta user field data collection. */ @@ -685,7 +685,7 @@ public final class StrictMode { } /** - * Call #{@link OnThreadViolationListener#onThreadViolation(Violation)} on specified + * Calls #{@link OnThreadViolationListener#onThreadViolation(Violation)} on specified * executor every violation. */ public @NonNull Builder penaltyListener( @@ -715,7 +715,7 @@ public final class StrictMode { } /** - * Construct the ThreadPolicy instance. + * Constructs the ThreadPolicy instance. * *

    Note: if no penalties are enabled before calling build, {@link * #penaltyLog} is implicitly set. @@ -805,7 +805,7 @@ public final class StrictMode { mMask = 0; } - /** Build upon an existing VmPolicy. */ + /** Builds upon an existing VmPolicy. */ public Builder(VmPolicy base) { mMask = base.mask; mClassInstanceLimitNeedCow = true; @@ -815,7 +815,7 @@ public final class StrictMode { } /** - * Set an upper bound on how many instances of a class can be in memory at once. Helps + * Sets an upper bound on how many instances of a class can be in memory at once. Helps * to prevent object leaks. */ public @NonNull Builder setClassInstanceLimit(Class klass, int instanceLimit) { @@ -838,7 +838,7 @@ public final class StrictMode { return this; } - /** Detect leaks of {@link android.app.Activity} subclasses. */ + /** Detects leaks of {@link android.app.Activity} subclasses. */ public @NonNull Builder detectActivityLeaks() { return enable(DETECT_VM_ACTIVITY_LEAKS); } @@ -852,7 +852,7 @@ public final class StrictMode { } /** - * Detect reflective usage of APIs that are not part of the public Android SDK. + * Detects reflective usage of APIs that are not part of the public Android SDK. * *

    Note that any non-SDK APIs that this processes accesses before this detection is * enabled may not be detected. To ensure that all such API accesses are detected, @@ -863,7 +863,7 @@ public final class StrictMode { } /** - * Permit reflective usage of APIs that are not part of the public Android SDK. Note + * Permits reflective usage of APIs that are not part of the public Android SDK. Note * that this only affects {@code StrictMode}, the underlying runtime may * continue to restrict or warn on access to methods that are not part of the * public SDK. @@ -873,7 +873,7 @@ public final class StrictMode { } /** - * Detect everything that's potentially suspect. + * Detects everything that's potentially suspect. * *

    In the Honeycomb release this includes leaks of SQLite cursors, Activities, and * other closable objects but will likely expand in future releases. @@ -924,8 +924,8 @@ public final class StrictMode { } /** - * Detect when an {@link android.database.sqlite.SQLiteCursor} or other SQLite object is - * finalized without having been closed. + * Detects when an {@link android.database.sqlite.SQLiteCursor} or other SQLite + * object is finalized without having been closed. * *

    You always want to explicitly close your SQLite cursors to avoid unnecessary * database contention and temporary memory leaks. @@ -935,8 +935,8 @@ public final class StrictMode { } /** - * Detect when an {@link java.io.Closeable} or other object with an explicit termination - * method is finalized without having been closed. + * Detects when an {@link java.io.Closeable} or other object with an explicit + * termination method is finalized without having been closed. * *

    You always want to explicitly close such objects to avoid unnecessary resources * leaks. @@ -946,16 +946,16 @@ public final class StrictMode { } /** - * Detect when a {@link BroadcastReceiver} or {@link ServiceConnection} is leaked during - * {@link Context} teardown. + * Detects when a {@link BroadcastReceiver} or {@link ServiceConnection} is leaked + * during {@link Context} teardown. */ public @NonNull Builder detectLeakedRegistrationObjects() { return enable(DETECT_VM_REGISTRATION_LEAKS); } /** - * Detect when the calling application exposes a {@code file://} {@link android.net.Uri} - * to another app. + * Detects when the calling application exposes a {@code file://} + * {@link android.net.Uri} to another app. * *

    This exposure is discouraged since the receiving app may not have access to the * shared path. For example, the receiving app may not have requested the {@link @@ -973,9 +973,9 @@ public final class StrictMode { } /** - * Detect any network traffic from the calling app which is not wrapped in SSL/TLS. This - * can help you detect places that your app is inadvertently sending cleartext data - * across the network. + * Detects any network traffic from the calling app which is not wrapped in SSL/TLS. + * This can help you detect places that your app is inadvertently sending cleartext + * data across the network. * *

    Using {@link #penaltyDeath()} or {@link #penaltyDeathOnCleartextNetwork()} will * block further traffic on that socket to prevent accidental data leakage, in addition @@ -992,7 +992,7 @@ public final class StrictMode { } /** - * Detect when the calling application sends a {@code content://} {@link + * Detects when the calling application sends a {@code content://} {@link * android.net.Uri} to another app without setting {@link * Intent#FLAG_GRANT_READ_URI_PERMISSION} or {@link * Intent#FLAG_GRANT_WRITE_URI_PERMISSION}. @@ -1008,7 +1008,7 @@ public final class StrictMode { } /** - * Detect any sockets in the calling app which have not been tagged using {@link + * Detects any sockets in the calling app which have not been tagged using {@link * TrafficStats}. Tagging sockets can help you investigate network usage inside your * app, such as a narrowing down heavy usage to a specific library or component. * @@ -1028,7 +1028,7 @@ public final class StrictMode { } /** - * Detect any implicit reliance on Direct Boot automatic filtering + * Detects any implicit reliance on Direct Boot automatic filtering * of {@link PackageManager} values. Violations are only triggered * when implicit calls are made while the user is locked. *

    @@ -1051,7 +1051,7 @@ public final class StrictMode { } /** - * Detect access to filesystem paths stored in credential protected + * Detects access to filesystem paths stored in credential protected * storage areas while the user is locked. *

    * When a user is locked, credential protected storage is @@ -1072,7 +1072,7 @@ public final class StrictMode { } /** - * Detect attempts to invoke a method on a {@link Context} that is not suited for such + * Detects attempts to invoke a method on a {@link Context} that is not suited for such * operation. *

    An example of this is trying to obtain an instance of UI service (e.g. * {@link android.view.WindowManager}) from a non-visual {@link Context}. This is not @@ -1086,7 +1086,7 @@ public final class StrictMode { } /** - * Disable detection of incorrect context use. + * Disables detection of incorrect context use. * * @see #detectIncorrectContextUse() * @@ -1098,7 +1098,7 @@ public final class StrictMode { } /** - * Detect when your app sends an unsafe {@link Intent}. + * Detects when your app sends an unsafe {@link Intent}. *

    * Violations may indicate security vulnerabilities in the design of * your app, where a malicious app could trick you into granting @@ -1139,7 +1139,7 @@ public final class StrictMode { } /** - * Permit your app to launch any {@link Intent} which originated + * Permits your app to launch any {@link Intent} which originated * from outside your app. *

    * Disabling this check is strongly discouraged, as @@ -1214,13 +1214,13 @@ public final class StrictMode { return enable(PENALTY_DEATH_ON_FILE_URI_EXPOSURE); } - /** Log detected violations to the system log. */ + /** Logs detected violations to the system log. */ public @NonNull Builder penaltyLog() { return enable(PENALTY_LOG); } /** - * Enable detected violations log a stacktrace and timing data to the {@link + * Enables detected violations log a stacktrace and timing data to the {@link * android.os.DropBoxManager DropBox} on policy violation. Intended mostly for platform * integrators doing beta user field data collection. */ @@ -1229,7 +1229,7 @@ public final class StrictMode { } /** - * Call #{@link OnVmViolationListener#onVmViolation(Violation)} on every violation. + * Calls #{@link OnVmViolationListener#onVmViolation(Violation)} on every violation. */ public @NonNull Builder penaltyListener( @NonNull Executor executor, @NonNull OnVmViolationListener listener) { @@ -1258,7 +1258,7 @@ public final class StrictMode { } /** - * Construct the VmPolicy instance. + * Constructs the VmPolicy instance. * *

    Note: if no penalties are enabled before calling build, {@link * #penaltyLog} is implicitly set. @@ -1474,7 +1474,7 @@ public final class StrictMode { } /** - * Determine if the given app is "bundled" as part of the system image. These bundled apps are + * Determines if the given app is "bundled" as part of the system image. These bundled apps are * developed in lock-step with the OS, and they aren't updated outside of an OTA, so we want to * chase any {@link StrictMode} regressions by enabling detection when running on {@link * Build#IS_USERDEBUG} or {@link Build#IS_ENG} builds. @@ -1512,7 +1512,7 @@ public final class StrictMode { } /** - * Initialize default {@link ThreadPolicy} for the current thread. + * Initializes default {@link ThreadPolicy} for the current thread. * * @hide */ @@ -1547,7 +1547,7 @@ public final class StrictMode { } /** - * Initialize default {@link VmPolicy} for the current VM. + * Initializes default {@link VmPolicy} for the current VM. * * @hide */ @@ -2244,7 +2244,7 @@ public final class StrictMode { } /** - * Enable the recommended StrictMode defaults, with violations just being logged. + * Enables the recommended StrictMode defaults, with violations just being logged. * *

    This catches disk and network access on the main thread, as well as leaked SQLite cursors * and unclosed resources. This is simply a wrapper around {@link #setVmPolicy} and {@link @@ -2545,7 +2545,7 @@ public final class StrictMode { private static final SparseLongArray sRealLastVmViolationTime = new SparseLongArray(); /** - * Clamp the given map by removing elements with timestamp older than the given retainSince. + * Clamps the given map by removing elements with timestamp older than the given retainSince. */ private static void clampViolationTimeMap(final @NonNull SparseLongArray violationTime, final long retainSince) { @@ -2812,7 +2812,7 @@ public final class StrictMode { }; /** - * Enter a named critical span (e.g. an animation) + * Enters a named critical span (e.g. an animation) * *

    The name is an arbitary label (or tag) that will be applied to any strictmode violation * that happens while this span is active. You must call finish() on the span when done. @@ -3056,7 +3056,7 @@ public final class StrictMode { /** If this is a instance count violation, the number of instances in memory, else -1. */ public long numInstances = -1; - /** Create an instance of ViolationInfo initialized from an exception. */ + /** Creates an instance of ViolationInfo initialized from an exception. */ ViolationInfo(Violation tr, int penaltyMask) { this.mViolation = tr; this.mPenaltyMask = penaltyMask; @@ -3131,8 +3131,8 @@ public final class StrictMode { } /** - * Add a {@link Throwable} from the current process that caused the underlying violation. We - * only preserve the stack trace elements. + * Adds a {@link Throwable} from the current process that caused the underlying violation. + * We only preserve the stack trace elements. * * @hide */ @@ -3160,14 +3160,14 @@ public final class StrictMode { return result; } - /** Create an instance of ViolationInfo initialized from a Parcel. */ + /** Creates an instance of ViolationInfo initialized from a Parcel. */ @UnsupportedAppUsage public ViolationInfo(Parcel in) { this(in, false); } /** - * Create an instance of ViolationInfo initialized from a Parcel. + * Creates an instance of ViolationInfo initialized from a Parcel. * * @param unsetGatheringBit if true, the caller is the root caller and the gathering penalty * should be removed. @@ -3203,7 +3203,7 @@ public final class StrictMode { tags = in.readStringArray(); } - /** Save a ViolationInfo instance to a parcel. */ + /** Saves a ViolationInfo instance to a parcel. */ @Override public void writeToParcel(Parcel dest, int flags) { dest.writeSerializable(mViolation); @@ -3248,7 +3248,7 @@ public final class StrictMode { } } - /** Dump a ViolationInfo instance to a Printer. */ + /** Dumps a ViolationInfo instance to a Printer. */ public void dump(Printer pw, String prefix) { pw.println(prefix + "stackTrace: " + getStackTrace()); pw.println(prefix + "penalty: " + mPenaltyMask); diff --git a/core/java/android/os/SystemVibrator.java b/core/java/android/os/SystemVibrator.java index 011a3ee91adafdbb829c3b9c4d3c66fa7ed5b7ac..c3cddf32f063dbba64c35d25ef0726b50637696a 100644 --- a/core/java/android/os/SystemVibrator.java +++ b/core/java/android/os/SystemVibrator.java @@ -18,8 +18,11 @@ package android.os; import android.annotation.CallbackExecutor; import android.annotation.NonNull; +import android.annotation.Nullable; import android.compat.annotation.UnsupportedAppUsage; import android.content.Context; +import android.hardware.vibrator.IVibratorManager; +import android.os.vibrator.VendorVibrationSession; import android.os.vibrator.VibratorInfoFactory; import android.util.ArrayMap; import android.util.Log; @@ -53,6 +56,7 @@ public class SystemVibrator extends Vibrator { private final Object mLock = new Object(); @GuardedBy("mLock") private VibratorInfo mVibratorInfo; + private int[] mVibratorIds; @UnsupportedAppUsage public SystemVibrator(Context context) { @@ -71,7 +75,11 @@ public class SystemVibrator extends Vibrator { Log.w(TAG, "Failed to retrieve vibrator info; no vibrator manager."); return VibratorInfo.EMPTY_VIBRATOR_INFO; } - int[] vibratorIds = mVibratorManager.getVibratorIds(); + int[] vibratorIds = getVibratorIds(); + if (vibratorIds == null) { + Log.w(TAG, "Failed to retrieve vibrator info; error retrieving vibrator ids."); + return VibratorInfo.EMPTY_VIBRATOR_INFO; + } if (vibratorIds.length == 0) { // It is known that the device has no vibrator, so cache and return info that // reflects the lack of support for effects/primitives. @@ -95,20 +103,22 @@ public class SystemVibrator extends Vibrator { @Override public boolean hasVibrator() { - if (mVibratorManager == null) { + int[] vibratorIds = getVibratorIds(); + if (vibratorIds == null) { Log.w(TAG, "Failed to check if vibrator exists; no vibrator manager."); return false; } - return mVibratorManager.getVibratorIds().length > 0; + return vibratorIds.length > 0; } @Override public boolean isVibrating() { - if (mVibratorManager == null) { + int[] vibratorIds = getVibratorIds(); + if (vibratorIds == null) { Log.w(TAG, "Failed to vibrate; no vibrator manager."); return false; } - for (int vibratorId : mVibratorManager.getVibratorIds()) { + for (int vibratorId : vibratorIds) { if (mVibratorManager.getVibrator(vibratorId).isVibrating()) { return true; } @@ -136,6 +146,11 @@ public class SystemVibrator extends Vibrator { Log.w(TAG, "Failed to add vibrate state listener; no vibrator manager."); return; } + int[] vibratorIds = getVibratorIds(); + if (vibratorIds == null) { + Log.w(TAG, "Failed to add vibrate state listener; error retrieving vibrator ids."); + return; + } MultiVibratorStateListener delegate = null; try { synchronized (mRegisteredListeners) { @@ -145,7 +160,7 @@ public class SystemVibrator extends Vibrator { return; } delegate = new MultiVibratorStateListener(executor, listener); - delegate.register(mVibratorManager); + delegate.register(mVibratorManager, vibratorIds); mRegisteredListeners.put(listener, delegate); delegate = null; } @@ -183,6 +198,11 @@ public class SystemVibrator extends Vibrator { return getInfo().hasAmplitudeControl(); } + @Override + public boolean areVendorSessionsSupported() { + return mVibratorManager.hasCapabilities(IVibratorManager.CAP_START_SESSIONS); + } + @Override public boolean setAlwaysOnEffect(int uid, String opPkg, int alwaysOnId, VibrationEffect effect, VibrationAttributes attrs) { @@ -243,6 +263,41 @@ public class SystemVibrator extends Vibrator { mVibratorManager.cancel(usageFilter); } + @Override + public void startVendorSession(@NonNull VibrationAttributes attrs, @Nullable String reason, + @Nullable CancellationSignal cancellationSignal, @NonNull Executor executor, + @NonNull VendorVibrationSession.Callback callback) { + if (mVibratorManager == null) { + Log.w(TAG, "Failed to start vibration session; no vibrator manager."); + executor.execute( + () -> callback.onFinished(VendorVibrationSession.STATUS_UNKNOWN_ERROR)); + return; + } + int[] vibratorIds = getVibratorIds(); + if (vibratorIds == null) { + Log.w(TAG, "Failed to start vibration session; error retrieving vibrator ids."); + executor.execute( + () -> callback.onFinished(VendorVibrationSession.STATUS_UNKNOWN_ERROR)); + return; + } + mVibratorManager.startVendorSession(vibratorIds, attrs, reason, cancellationSignal, + executor, callback); + } + + @Nullable + private int[] getVibratorIds() { + synchronized (mLock) { + if (mVibratorIds != null) { + return mVibratorIds; + } + if (mVibratorManager == null) { + Log.w(TAG, "Failed to retrieve vibrator ids; no vibrator manager."); + return null; + } + return mVibratorIds = mVibratorManager.getVibratorIds(); + } + } + /** * Tries to unregister individual {@link android.os.Vibrator.OnVibratorStateChangedListener} * that were left registered to vibrators after failures to register them to all vibrators. @@ -319,8 +374,7 @@ public class SystemVibrator extends Vibrator { } /** Registers a listener to all individual vibrators in {@link VibratorManager}. */ - public void register(VibratorManager vibratorManager) { - int[] vibratorIds = vibratorManager.getVibratorIds(); + public void register(VibratorManager vibratorManager, @NonNull int[] vibratorIds) { synchronized (mLock) { for (int i = 0; i < vibratorIds.length; i++) { int vibratorId = vibratorIds[i]; diff --git a/core/java/android/os/SystemVibratorManager.java b/core/java/android/os/SystemVibratorManager.java index a5697fb0e8a8d6d4cedcf596639a2664702f6967..f9935d2870b04f2d58a41a12a33141df160d722e 100644 --- a/core/java/android/os/SystemVibratorManager.java +++ b/core/java/android/os/SystemVibratorManager.java @@ -22,6 +22,10 @@ import android.annotation.CallbackExecutor; import android.annotation.NonNull; import android.annotation.Nullable; import android.content.Context; +import android.hardware.vibrator.IVibratorManager; +import android.os.vibrator.IVibrationSession; +import android.os.vibrator.IVibrationSessionCallback; +import android.os.vibrator.VendorVibrationSession; import android.util.ArrayMap; import android.util.Log; import android.util.SparseArray; @@ -47,6 +51,8 @@ public class SystemVibratorManager extends VibratorManager { @GuardedBy("mLock") private int[] mVibratorIds; @GuardedBy("mLock") + private int mCapabilities; + @GuardedBy("mLock") private final SparseArray mVibrators = new SparseArray<>(); @GuardedBy("mLock") @@ -84,6 +90,11 @@ public class SystemVibratorManager extends VibratorManager { } } + @Override + public boolean hasCapabilities(int capabilities) { + return (getCapabilities() & capabilities) == capabilities; + } + @NonNull @Override public Vibrator getVibrator(int vibratorId) { @@ -173,7 +184,7 @@ public class SystemVibratorManager extends VibratorManager { int inputSource, String reason, int flags, int privFlags) { if (mService == null) { Log.w(TAG, "Failed to perform haptic feedback for input device;" - + " no vibrator manager service."); + + " no vibrator manager service."); return; } Trace.traceBegin(TRACE_TAG_VIBRATOR, "performHapticFeedbackForInputDevice"); @@ -197,6 +208,50 @@ public class SystemVibratorManager extends VibratorManager { cancelVibration(usageFilter); } + @Override + public void startVendorSession(@NonNull int[] vibratorIds, @NonNull VibrationAttributes attrs, + @Nullable String reason, @Nullable CancellationSignal cancellationSignal, + @NonNull Executor executor, @NonNull VendorVibrationSession.Callback callback) { + Objects.requireNonNull(vibratorIds); + VendorVibrationSessionCallbackDelegate callbackDelegate = + new VendorVibrationSessionCallbackDelegate(executor, callback); + if (mService == null) { + Log.w(TAG, "Failed to start vibration session; no vibrator manager service."); + callbackDelegate.onFinished(VendorVibrationSession.STATUS_UNKNOWN_ERROR); + return; + } + try { + ICancellationSignal remoteCancellationSignal = mService.startVendorVibrationSession( + mUid, mContext.getDeviceId(), mPackageName, vibratorIds, attrs, reason, + callbackDelegate); + if (cancellationSignal != null) { + cancellationSignal.setRemote(remoteCancellationSignal); + } + } catch (RemoteException e) { + Log.w(TAG, "Failed to start vibration session.", e); + callbackDelegate.onFinished(VendorVibrationSession.STATUS_UNKNOWN_ERROR); + } + } + + private int getCapabilities() { + synchronized (mLock) { + if (mCapabilities != 0) { + return mCapabilities; + } + try { + if (mService == null) { + Log.w(TAG, "Failed to retrieve vibrator manager capabilities;" + + " no vibrator manager service."); + } else { + return mCapabilities = mService.getCapabilities(); + } + } catch (RemoteException e) { + e.rethrowFromSystemServer(); + } + return 0; + } + } + private void cancelVibration(int usageFilter) { if (mService == null) { Log.w(TAG, "Failed to cancel vibration; no vibrator manager service."); @@ -228,12 +283,45 @@ public class SystemVibratorManager extends VibratorManager { } } + /** Callback for vendor vibration sessions. */ + private static class VendorVibrationSessionCallbackDelegate extends + IVibrationSessionCallback.Stub { + private final Executor mExecutor; + private final VendorVibrationSession.Callback mCallback; + + VendorVibrationSessionCallbackDelegate( + @NonNull Executor executor, + @NonNull VendorVibrationSession.Callback callback) { + Objects.requireNonNull(executor); + Objects.requireNonNull(callback); + mExecutor = executor; + mCallback = callback; + } + + @Override + public void onStarted(IVibrationSession session) { + mExecutor.execute(() -> mCallback.onStarted(new VendorVibrationSession(session))); + } + + @Override + public void onFinishing() { + mExecutor.execute(() -> mCallback.onFinishing()); + } + + @Override + public void onFinished(int status) { + mExecutor.execute(() -> mCallback.onFinished(status)); + } + } + /** Controls vibrations on a single vibrator. */ private final class SingleVibrator extends Vibrator { private final VibratorInfo mVibratorInfo; + private final int[] mVibratorId; SingleVibrator(@NonNull VibratorInfo vibratorInfo) { mVibratorInfo = vibratorInfo; + mVibratorId = new int[]{mVibratorInfo.getId()}; } @Override @@ -251,6 +339,11 @@ public class SystemVibratorManager extends VibratorManager { return mVibratorInfo.hasAmplitudeControl(); } + @Override + public boolean areVendorSessionsSupported() { + return SystemVibratorManager.this.hasCapabilities(IVibratorManager.CAP_START_SESSIONS); + } + @Override public boolean setAlwaysOnEffect(int uid, String opPkg, int alwaysOnId, @Nullable VibrationEffect effect, @Nullable VibrationAttributes attrs) { @@ -369,5 +462,13 @@ public class SystemVibratorManager extends VibratorManager { } } } + + @Override + public void startVendorSession(@NonNull VibrationAttributes attrs, String reason, + @Nullable CancellationSignal cancellationSignal, @NonNull Executor executor, + @NonNull VendorVibrationSession.Callback callback) { + SystemVibratorManager.this.startVendorSession(mVibratorId, attrs, reason, + cancellationSignal, executor, callback); + } } } diff --git a/core/java/android/os/UidBatteryConsumer.java b/core/java/android/os/UidBatteryConsumer.java index f893739fcf28bc0bc2eea27831da6c06afd6532c..976bfe41ba454fd08fcb3ac1931895ff45709d0e 100644 --- a/core/java/android/os/UidBatteryConsumer.java +++ b/core/java/android/os/UidBatteryConsumer.java @@ -210,12 +210,6 @@ public final class UidBatteryConsumer extends BatteryConsumer { serializer.attribute(null, BatteryUsageStats.XML_ATTR_HIGHEST_DRAIN_PACKAGE, packageWithHighestDrain); } - serializer.attributeLong(null, BatteryUsageStats.XML_ATTR_TIME_IN_FOREGROUND, - getTimeInProcessStateMs(PROCESS_STATE_FOREGROUND)); - serializer.attributeLong(null, BatteryUsageStats.XML_ATTR_TIME_IN_BACKGROUND, - getTimeInProcessStateMs(PROCESS_STATE_BACKGROUND)); - serializer.attributeLong(null, BatteryUsageStats.XML_ATTR_TIME_IN_FOREGROUND_SERVICE, - getTimeInProcessStateMs(PROCESS_STATE_FOREGROUND_SERVICE)); mPowerComponents.writeToXml(serializer); serializer.endTag(null, BatteryUsageStats.XML_TAG_UID); } @@ -235,13 +229,6 @@ public final class UidBatteryConsumer extends BatteryConsumer { consumerBuilder.setPackageWithHighestDrain( parser.getAttributeValue(null, BatteryUsageStats.XML_ATTR_HIGHEST_DRAIN_PACKAGE)); - consumerBuilder.setTimeInProcessStateMs(PROCESS_STATE_FOREGROUND, - parser.getAttributeLong(null, BatteryUsageStats.XML_ATTR_TIME_IN_FOREGROUND)); - consumerBuilder.setTimeInProcessStateMs(PROCESS_STATE_BACKGROUND, - parser.getAttributeLong(null, BatteryUsageStats.XML_ATTR_TIME_IN_BACKGROUND)); - consumerBuilder.setTimeInProcessStateMs(PROCESS_STATE_FOREGROUND_SERVICE, - parser.getAttributeLong(null, - BatteryUsageStats.XML_ATTR_TIME_IN_FOREGROUND_SERVICE)); while (!(eventType == XmlPullParser.END_TAG && parser.getName().equals(BatteryUsageStats.XML_TAG_UID)) && eventType != XmlPullParser.END_DOCUMENT) { @@ -335,7 +322,11 @@ public final class UidBatteryConsumer extends BatteryConsumer { /** * Sets the duration, in milliseconds, that this UID was active in a particular process * state, such as foreground service. + * + * @deprecated time in process is now derived from the + * {@link BatteryConsumer#POWER_COMPONENT_BASE} duration */ + @Deprecated @NonNull public Builder setTimeInProcessStateMs(@ProcessState int state, long timeInProcessStateMs) { Key key = getKey(POWER_COMPONENT_BASE, state); diff --git a/core/java/android/os/Vibrator.java b/core/java/android/os/Vibrator.java index c4c4580bf0a829da289cfee322c90ca0680b94de..53f8a9267499340ac7ee551bbac438fcd02c362c 100644 --- a/core/java/android/os/Vibrator.java +++ b/core/java/android/os/Vibrator.java @@ -33,6 +33,7 @@ import android.content.res.Resources; import android.hardware.vibrator.IVibrator; import android.media.AudioAttributes; import android.os.vibrator.Flags; +import android.os.vibrator.VendorVibrationSession; import android.os.vibrator.VibrationConfig; import android.os.vibrator.VibratorFrequencyProfile; import android.os.vibrator.VibratorFrequencyProfileLegacy; @@ -246,6 +247,34 @@ public abstract class Vibrator { return getInfo().areVibrationFeaturesSupported(effect); } + /** + * Check whether the vibrator has support for vendor-specific effects. + * + *

    Vendor vibration effects can be created via {@link VibrationEffect#createVendorEffect}. + * + * @return True if the hardware can play vendor-specific vibration effects, false otherwise. + * @hide + */ + @SystemApi + @FlaggedApi(Flags.FLAG_VENDOR_VIBRATION_EFFECTS) + public boolean areVendorEffectsSupported() { + return getInfo().hasCapability(IVibrator.CAP_PERFORM_VENDOR_EFFECTS); + } + + /** + * Check whether the vibrator has support for vendor-specific vibration sessions. + * + *

    Vendor vibration sessions can be started via {@link #startVendorSession}. + * + * @return True if the hardware can play vendor-specific vibration sessions, false otherwise. + * @hide + */ + @SystemApi + @FlaggedApi(Flags.FLAG_VENDOR_VIBRATION_EFFECTS) + public boolean areVendorSessionsSupported() { + return false; + } + /** * Check whether the vibrator can be controlled by an external service with the * {@link IExternalVibratorService}. @@ -922,4 +951,44 @@ public abstract class Vibrator { @RequiresPermission(android.Manifest.permission.ACCESS_VIBRATOR_STATE) public void removeVibratorStateListener(@NonNull OnVibratorStateChangedListener listener) { } + + /** + * Starts a vibration session in this vibrator. + * + *

    The session will start asynchronously once the vibrator control can be acquired. Once it's + * started the {@link VendorVibrationSession} will be provided to the callback. This session + * should be used to play vibrations until the session is ended or canceled. + * + *

    The vendor app will have exclusive control over the vibrator during this session. This + * control can be revoked by the vibrator service, which will be notified to the same session + * callback with the {@link VendorVibrationSession#STATUS_CANCELED}. + * + *

    The {@link VibrationAttributes} will be used to decide the priority of the vendor + * vibrations that will be performed in this session. All vibrations within this session will + * apply the same attributes. + * + * @param attrs The {@link VibrationAttributes} corresponding to the vibrations that will be + * performed in the session. This will be used to decide the priority of this + * session against other system vibrations. + * @param reason The description for this session, used for debugging purposes. + * @param cancellationSignal A signal to cancel the session before it starts. + * @param executor The executor for the session callbacks. + * @param callback The {@link VendorVibrationSession.Callback} for the started session. + * + * @see VendorVibrationSession + * @hide + */ + @SystemApi + @FlaggedApi(Flags.FLAG_VENDOR_VIBRATION_EFFECTS) + @RequiresPermission(allOf = { + android.Manifest.permission.VIBRATE, + android.Manifest.permission.VIBRATE_VENDOR_EFFECTS, + android.Manifest.permission.START_VIBRATION_SESSIONS, + }) + public void startVendorSession(@NonNull VibrationAttributes attrs, @Nullable String reason, + @Nullable CancellationSignal cancellationSignal, @NonNull Executor executor, + @NonNull VendorVibrationSession.Callback callback) { + Log.w(TAG, "startVendorSession is not supported"); + executor.execute(() -> callback.onFinished(VendorVibrationSession.STATUS_UNSUPPORTED)); + } } diff --git a/core/java/android/os/VibratorManager.java b/core/java/android/os/VibratorManager.java index 0428876891f9a45b084893bfe973f36af2887511..0072bc22ad8f9df1e39de7485ffa4da8890f439d 100644 --- a/core/java/android/os/VibratorManager.java +++ b/core/java/android/os/VibratorManager.java @@ -22,9 +22,12 @@ import android.annotation.RequiresPermission; import android.annotation.SystemService; import android.app.ActivityThread; import android.content.Context; +import android.os.vibrator.VendorVibrationSession; import android.util.Log; import android.view.HapticFeedbackConstants; +import java.util.concurrent.Executor; + /** * Provides access to all vibrators from the device, as well as the ability to run them * in a synchronized fashion. @@ -61,6 +64,14 @@ public abstract class VibratorManager { @NonNull public abstract int[] getVibratorIds(); + /** + * Return true if the vibrator manager has all capabilities, false otherwise. + * @hide + */ + public boolean hasCapabilities(int capabilities) { + return false; + } + /** * Retrieve a single vibrator by id. * @@ -190,4 +201,30 @@ public abstract class VibratorManager { */ @RequiresPermission(android.Manifest.permission.VIBRATE) public abstract void cancel(int usageFilter); + + + /** + * Starts a vibration session on given vibrators. + * + * @param vibratorIds The vibrators that will be controlled by this session. + * @param attrs The {@link VibrationAttributes} corresponding to the vibrations that will + * be performed in the session. This will be used to decide the priority of + * this session against other system vibrations. + * @param reason The description for this session, used for debugging purposes. + * @param cancellationSignal A signal to cancel the session before it starts. + * @param executor The executor for the session callbacks. + * @param callback The {@link VendorVibrationSession.Callback} for the started session. + * @see Vibrator#startVendorSession + * @hide + */ + @RequiresPermission(allOf = { + android.Manifest.permission.VIBRATE, + android.Manifest.permission.VIBRATE_VENDOR_EFFECTS, + android.Manifest.permission.START_VIBRATION_SESSIONS, + }) + public void startVendorSession(@NonNull int[] vibratorIds, @NonNull VibrationAttributes attrs, + @Nullable String reason, @Nullable CancellationSignal cancellationSignal, + @NonNull Executor executor, @NonNull VendorVibrationSession.Callback callback) { + Log.w(TAG, "startVendorSession is not supported"); + } } diff --git a/core/java/android/os/flags.aconfig b/core/java/android/os/flags.aconfig index 9c83bc2c88ec36a3747b43c45e4e3bdd5451cc67..d9db28e0b3c3885fb96263125f3e9449f54298e3 100644 --- a/core/java/android/os/flags.aconfig +++ b/core/java/android/os/flags.aconfig @@ -242,6 +242,15 @@ flag { bug: "317250784" } +flag { + name: "update_engine_api" + namespace: "art_mainline" + description: "Update Engine APIs for ART" + is_exported: true + is_fixed_read_only: true + bug: "377557749" +} + flag { namespace: "system_performance" name: "perfetto_sdk_tracing" diff --git a/core/java/android/os/instrumentation/ExecutableMethodFileOffsets.aidl b/core/java/android/os/instrumentation/ExecutableMethodFileOffsets.aidl new file mode 100644 index 0000000000000000000000000000000000000000..dbe54891b0f2e4f2ce2e0985e8d78a15b61c98f6 --- /dev/null +++ b/core/java/android/os/instrumentation/ExecutableMethodFileOffsets.aidl @@ -0,0 +1,37 @@ +/* + * Copyright (C) 2024 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package android.os.instrumentation; + +/** + * Represents the location of the code for a compiled method within a process' + * memory. + * {@hide} + */ +@JavaDerive(toString=true) +parcelable ExecutableMethodFileOffsets { + /** + * The OS path of the containing file (could be virtual). + */ + @utf8InCpp String containerPath; + /** + * The offset of the containing file within the process' memory. + */ + long containerOffset; + /** + * The offset of the method within the containing file. + */ + long methodOffset; +} diff --git a/core/java/android/os/instrumentation/IDynamicInstrumentationManager.aidl b/core/java/android/os/instrumentation/IDynamicInstrumentationManager.aidl new file mode 100644 index 0000000000000000000000000000000000000000..c45c51d15cc96a61483c5e68ebbc73d12a166809 --- /dev/null +++ b/core/java/android/os/instrumentation/IDynamicInstrumentationManager.aidl @@ -0,0 +1,33 @@ +/* + * Copyright (C) 2024 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package android.os.instrumentation; + +import android.os.instrumentation.ExecutableMethodFileOffsets; +import android.os.instrumentation.MethodDescriptor; +import android.os.instrumentation.TargetProcess; + +/** + * System private API for managing the dynamic attachment of instrumentation. + * + * {@hide} + */ +interface IDynamicInstrumentationManager { + /** Provides ART metadata about the described compiled method within the target process */ + @PermissionManuallyEnforced + @nullable ExecutableMethodFileOffsets getExecutableMethodFileOffsets( + in TargetProcess targetProcess, in MethodDescriptor methodDescriptor); +} diff --git a/core/java/android/os/instrumentation/MethodDescriptor.aidl b/core/java/android/os/instrumentation/MethodDescriptor.aidl new file mode 100644 index 0000000000000000000000000000000000000000..055d0ecb66e4f625dfdb62efed46577627e7f09a --- /dev/null +++ b/core/java/android/os/instrumentation/MethodDescriptor.aidl @@ -0,0 +1,37 @@ +/* + * Copyright (C) 2024 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package android.os.instrumentation; + +/** + * Represents a JVM method, where class fields that make up its signature. + * {@hide} + */ +@JavaDerive(toString=true) +parcelable MethodDescriptor { + /** + * Fully qualified class in reverse.domain.Naming + */ + @utf8InCpp String fullyQualifiedClassName; + /** + * Name of the method. + */ + @utf8InCpp String methodName; + /** + * Fully qualified types of method parameters, or string representations if primitive e.g. "int". + */ + @utf8InCpp String[] fullyQualifiedParameters; +} diff --git a/core/java/android/os/instrumentation/TargetProcess.aidl b/core/java/android/os/instrumentation/TargetProcess.aidl new file mode 100644 index 0000000000000000000000000000000000000000..e90780d07ef21b21eef7dd7497f56cb4d239be4c --- /dev/null +++ b/core/java/android/os/instrumentation/TargetProcess.aidl @@ -0,0 +1,29 @@ +/* + * Copyright (C) 2024 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package android.os.instrumentation; + +/** + * Addresses a process that would run on the device. + * Helps disambiguate targeted processes in cases of pid re-use. + * {@hide} + */ +@JavaDerive(toString=true) +parcelable TargetProcess { + int uid; + int pid; + @utf8InCpp String processName; +} diff --git a/core/java/android/os/storage/IStorageManager.aidl b/core/java/android/os/storage/IStorageManager.aidl index 1ab48a22cbbd8161e417acec6e833e1ef688ed76..09b96da39a84201d616afcf3b3bf47741ffc3f45 100644 --- a/core/java/android/os/storage/IStorageManager.aidl +++ b/core/java/android/os/storage/IStorageManager.aidl @@ -181,6 +181,5 @@ interface IStorageManager { * device's useful lifetime remains. If no information is available, -1 * is returned. */ - @EnforcePermission("READ_PRIVILEGED_PHONE_STATE") int getInternalStorageRemainingLifetime() = 99; } diff --git a/core/java/android/os/vibrator/IVibrationSession.aidl b/core/java/android/os/vibrator/IVibrationSession.aidl new file mode 100644 index 0000000000000000000000000000000000000000..e8295492665d13696a9216e51218e8a8593e9165 --- /dev/null +++ b/core/java/android/os/vibrator/IVibrationSession.aidl @@ -0,0 +1,55 @@ +/** + * 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.os.CombinedVibration; + +/** + * The communication channel by which an app control the system vibrators. + * + * In order to synchronize the places where vibrations might be controlled we provide this interface + * so the vibrator subsystem has a chance to: + * + * 1) Decide whether the current session should have the vibrator control. + * 2) Stop any on-going session for a new session/vibration, based on current system policy. + * {@hide} + */ +interface IVibrationSession { + const int STATUS_UNKNOWN = 0; + const int STATUS_SUCCESS = 1; + const int STATUS_IGNORED = 2; + const int STATUS_UNSUPPORTED = 3; + const int STATUS_CANCELED = 4; + const int STATUS_UNKNOWN_ERROR = 5; + + /** + * A method called to start a vibration within this session. This will fail if the session + * is finishing or was canceled. + */ + void vibrate(in CombinedVibration vibration, String reason); + + /** + * A method called by the app to stop this session gracefully. The vibrator will complete any + * ongoing vibration before the session is ended. + */ + void finishSession(); + + /** + * A method called by the app to stop this session immediatelly by interrupting any ongoing + * vibration. + */ + void cancelSession(); +} diff --git a/core/java/android/os/vibrator/IVibrationSessionCallback.aidl b/core/java/android/os/vibrator/IVibrationSessionCallback.aidl new file mode 100644 index 0000000000000000000000000000000000000000..36c3695a1bfe96be7819241ba4f5a4ede7d830aa --- /dev/null +++ b/core/java/android/os/vibrator/IVibrationSessionCallback.aidl @@ -0,0 +1,43 @@ +/** + * 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.os.vibrator.IVibrationSession; + +/** + * Callback for vibration session state. + * {@hide} + */ +oneway interface IVibrationSessionCallback { + + /** + * A method called by the service after a vibration session has successfully started. After this + * is called the app has control over the vibrator through this given session. + */ + void onStarted(in IVibrationSession session); + + /** + * A method called by the service to indicate the session is ending and should no longer receive + * vibration requests. + */ + void onFinishing(); + + /** + * A method called by the service after the session has ended. This might be triggered by the + * app or the service. The status code indicates the end reason. + */ + void onFinished(int status); +} diff --git a/core/java/android/os/vibrator/VendorVibrationSession.java b/core/java/android/os/vibrator/VendorVibrationSession.java new file mode 100644 index 0000000000000000000000000000000000000000..c23f2ed1a303846f7168bce08ae0d0cef218542b --- /dev/null +++ b/core/java/android/os/vibrator/VendorVibrationSession.java @@ -0,0 +1,236 @@ +/* + * 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 static android.os.vibrator.Flags.FLAG_VENDOR_VIBRATION_EFFECTS; + +import android.annotation.FlaggedApi; +import android.annotation.IntDef; +import android.annotation.NonNull; +import android.annotation.Nullable; +import android.annotation.RequiresPermission; +import android.annotation.SystemApi; +import android.os.CombinedVibration; +import android.os.RemoteException; +import android.os.VibrationEffect; +import android.os.Vibrator; +import android.util.Log; + +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.util.Objects; + +/** + * A vendor session that temporarily gains control over the system vibrators. + * + *

    Vibration effects can be played by the vibrator in a vendor session via {@link #vibrate}. The + * effects will be forwarded to the vibrator hardware immediately. Any concurrency support is + * defined and controlled by the vibrator hardware implementation. + * + *

    The session should be ended by {@link #close()}, which will wait until the last vibration ends + * and the vibrator is released. The end of the session will be notified to the {@link Callback} + * provided when the session was created. + * + *

    Any ongoing session can be immediately interrupted by the vendor app via {@link #cancel()}, + * including after {@link #close()} was called and the session is tearing down. A session can also + * be canceled by the vibrator service when it needs to regain control of the system vibrators. + * + * @see Vibrator#startVendorSession + * @hide + */ +@FlaggedApi(FLAG_VENDOR_VIBRATION_EFFECTS) +@SystemApi +public final class VendorVibrationSession implements AutoCloseable { + private static final String TAG = "VendorVibrationSession"; + + /** + * The session ended successfully. + */ + public static final int STATUS_SUCCESS = IVibrationSession.STATUS_SUCCESS; + + /** + * The session was ignored. + * + *

    This might be caused by user settings, vibration policies or the device state that + * prevents the app from performing vibrations for the requested + * {@link android.os.VibrationAttributes}. + */ + public static final int STATUS_IGNORED = IVibrationSession.STATUS_IGNORED; + + /** + * The session is not supported. + * + *

    The support for vendor vibration sessions can be checked via + * {@link Vibrator#areVendorSessionsSupported()}. + */ + public static final int STATUS_UNSUPPORTED = IVibrationSession.STATUS_UNSUPPORTED; + + /** + * The session was canceled. + * + *

    This might be triggered by the app after a session starts via {@link #cancel()}, or it + * can be triggered by the platform before or after the session has started. + */ + public static final int STATUS_CANCELED = IVibrationSession.STATUS_CANCELED; + + /** + * The session status is unknown. + */ + public static final int STATUS_UNKNOWN = IVibrationSession.STATUS_UNKNOWN; + + /** + * The session failed with unknown error. + * + *

    This can be caused by a failure to start a vibration session or after it has started, to + * indicate it has ended unexpectedly because of a system failure. + */ + public static final int STATUS_UNKNOWN_ERROR = IVibrationSession.STATUS_UNKNOWN_ERROR; + + /** @hide */ + @IntDef(prefix = { "STATUS_" }, value = { + STATUS_SUCCESS, + STATUS_IGNORED, + STATUS_UNSUPPORTED, + STATUS_CANCELED, + STATUS_UNKNOWN, + STATUS_UNKNOWN_ERROR, + }) + @Retention(RetentionPolicy.SOURCE) + public @interface Status{} + + private final IVibrationSession mSession; + + /** @hide */ + public VendorVibrationSession(@NonNull IVibrationSession session) { + Objects.requireNonNull(session); + mSession = session; + } + + /** + * Vibrate with a given effect. + * + *

    The vibration will be sent to the vibrator hardware immediately, without waiting for any + * previous vibration completion. The vendor should control the concurrency behavior at the + * hardware level (e.g. queueing, mixing, interrupting). + * + *

    If the provided effect is played by the vibrator service with controlled timings (e.g. + * effects created via {@link VibrationEffect#createWaveform}), then triggering a new vibration + * will cause the ongoing playback to be interrupted in favor of the new vibration. If the + * effect is broken down into multiple consecutive commands (e.g. large primitive compositions) + * then the hardware commands will be triggered in succession without waiting for the completion + * callback. + * + *

    The vendor app is responsible for timing the session requests and the vibrator hardware + * implementation is free to handle concurrency with different policies. + * + * @param effect The {@link VibrationEffect} describing the vibration to be performed. + * @param reason The description for the vibration reason, for debugging purposes. + */ + @RequiresPermission(android.Manifest.permission.VIBRATE) + public void vibrate(@NonNull VibrationEffect effect, @Nullable String reason) { + try { + mSession.vibrate(CombinedVibration.createParallel(effect), reason); + } catch (RemoteException e) { + Log.w(TAG, "Failed to vibrate in a vendor vibration session.", e); + e.rethrowFromSystemServer(); + } + } + + /** + * Cancel ongoing session. + * + *

    This will stop the vibration immediately and return the vibrator control to the + * platform. This can also be triggered after {@link #close()} to immediately release the + * vibrator. + * + *

    This will trigger {@link VendorVibrationSession.Callback#onFinished} directly with + * {@link #STATUS_CANCELED}. + */ + public void cancel() { + try { + mSession.cancelSession(); + } catch (RemoteException e) { + Log.w(TAG, "Failed to cancel vendor vibration session.", e); + e.rethrowFromSystemServer(); + } + } + + /** + * End ongoing session gracefully. + * + *

    This might continue the vibration while it's ramping down and wrapping up the session + * in the vibrator hardware. No more vibration commands can be sent through this session + * after this method is called. + * + *

    This will trigger {@link VendorVibrationSession.Callback#onFinishing()}. + */ + @Override + public void close() { + try { + mSession.finishSession(); + } catch (RemoteException e) { + Log.w(TAG, "Failed to finish vendor vibration session.", e); + e.rethrowFromSystemServer(); + } + } + + /** + * Callbacks for {@link VendorVibrationSession} events. + * + * @see Vibrator#startVendorSession + * @see VendorVibrationSession + */ + public interface Callback { + + /** + * New session was successfully started. + * + *

    The vendor app can interact with the vibrator using the + * {@link VendorVibrationSession} provided. + */ + void onStarted(@NonNull VendorVibrationSession session); + + /** + * The session is ending and finishing any pending vibrations. + * + *

    This is only invoked after {@link #onStarted(VendorVibrationSession)}. It will be + * triggered by both {@link VendorVibrationSession#cancel()} and + * {@link VendorVibrationSession#close()}. This might also be triggered if the platform + * cancels the ongoing session. + * + *

    Session vibrations might be still ongoing in the vibrator hardware but the app can + * no longer send commands through the session. A finishing session can still be immediately + * stopped via calls to {@link VendorVibrationSession.Callback#cancel()}. + */ + void onFinishing(); + + /** + * The session is finished. + * + *

    The vibrator has finished any vibration and returned to the platform's control. This + * might be triggered by the vendor app or by the vibrator service. + * + *

    If this is triggered before {@link #onStarted} then the session was finished before + * starting, either because it was cancelled or failed to start. If the session has already + * started then this will be triggered after {@link #onFinishing()} to indicate all session + * vibrations are complete and the vibrator is no longer under the session's control. + * + * @param status The session status. + */ + void onFinished(@VendorVibrationSession.Status int status); + } +} diff --git a/core/java/android/permission/flags.aconfig b/core/java/android/permission/flags.aconfig index 6a4932211f272687bf5bea168a7670f0a01cf0e7..60a0ae3f107dc044529c594bf9ac5f0a4dba5a2f 100644 --- a/core/java/android/permission/flags.aconfig +++ b/core/java/android/permission/flags.aconfig @@ -52,6 +52,24 @@ flag { bug: "310220212" } +flag { + name: "enhanced_confirmation_in_call_apis_enabled" + is_exported: true + is_fixed_read_only: true + namespace: "permissions" + description: "enable enhanced confirmation incall apis" + bug: "310220212" +} + +flag { + name: "unknown_call_package_install_blocking_enabled" + is_exported: true + is_fixed_read_only: true + namespace: "permissions" + description: "enable the blocking of certain app installs during an unknown call" + bug: "310220212" +} + flag { name: "op_enable_mobile_data_by_user" is_exported: true @@ -332,3 +350,39 @@ flag { description: "Enables ExtServices to leverage TextClassifier for OTP detection" bug: "351976749" } + +flag { + name: "health_connect_backup_restore_permission_enabled" + is_fixed_read_only: true + namespace: "health_fitness_aconfig" + description: "This flag protects the permission that is required to call Health Connect backup and restore apis" + bug: "376014879" # android_fr bug + is_exported: true +} + +flag { + name: "enable_aiai_proxied_text_classifiers" + is_fixed_read_only: true + is_exported: true + namespace: "permissions" + description: "Enables the AiAi to utilize the default OTP text classifier that is also used by ExtServices" + bug: "377229653" +} + +flag { + name: "enable_sqlite_appops_accesses" + is_fixed_read_only: true + is_exported: true + namespace: "permissions" + description: "Enables SQlite for recording discrete and historical AppOp accesses" + bug: "377584611" +} + +flag { + name: "ranging_permission_enabled" + is_fixed_read_only: true + is_exported: true + namespace: "uwb" + description: "This fixed read-only flag is used to enable new ranging permission for all ranging use cases." + bug: "370977414" +} diff --git a/core/java/android/print/OWNERS b/core/java/android/print/OWNERS index 0809de25b45c17f618c693ed54202246cc00d7e3..ce79f5d0c669cbdf09a20c687c0abe404c34c579 100644 --- a/core/java/android/print/OWNERS +++ b/core/java/android/print/OWNERS @@ -2,3 +2,4 @@ anothermark@google.com kumarashishg@google.com +bmgordon@google.com diff --git a/core/java/android/printservice/OWNERS b/core/java/android/printservice/OWNERS index 0809de25b45c17f618c693ed54202246cc00d7e3..ce79f5d0c669cbdf09a20c687c0abe404c34c579 100644 --- a/core/java/android/printservice/OWNERS +++ b/core/java/android/printservice/OWNERS @@ -2,3 +2,4 @@ anothermark@google.com kumarashishg@google.com +bmgordon@google.com diff --git a/core/java/android/provider/Settings.java b/core/java/android/provider/Settings.java index d19681c863201ad503aa851417bf362e295d5dff..ef351719ea70b5d290651fb9f594b27077c662aa 100644 --- a/core/java/android/provider/Settings.java +++ b/core/java/android/provider/Settings.java @@ -8686,6 +8686,19 @@ public final class Settings { */ public static final String ACCESSIBILITY_QS_TARGETS = "accessibility_qs_targets"; + /** + * Setting specifying the accessibility services, accessibility shortcut targets, + * or features to be toggled via a keyboard shortcut gesture. + * + *

    This is a colon-separated string list which contains the flattened + * {@link ComponentName} and the class name of a system class implementing a supported + * accessibility feature. + * + * @hide + */ + public static final String ACCESSIBILITY_KEY_GESTURE_TARGETS = + "accessibility_key_gesture_targets"; + /** * The system class name of magnification controller which is a target to be toggled via * accessibility shortcut or accessibility button. diff --git a/core/java/android/security/flags.aconfig b/core/java/android/security/flags.aconfig index 1d35344e5218e505068cdf051d98660cf9c960c3..7cb0ffcfcc721f89885ab7b16739f60b264730f0 100644 --- a/core/java/android/security/flags.aconfig +++ b/core/java/android/security/flags.aconfig @@ -120,3 +120,10 @@ flag { description: "Feature flag for exposing KeyStore grant APIs" bug: "351158708" } + +flag { + name: "secure_lockdown" + namespace: "biometrics" + description: "Feature flag for Secure Lockdown feature" + bug: "373422357" +} \ No newline at end of file diff --git a/core/java/android/security/responsible_apis_flags.aconfig b/core/java/android/security/responsible_apis_flags.aconfig index 5995760a41ec44ece5c405e7e02b50e19ea77090..66e1f38621ae737eb658f3e0da69b24a6565199c 100644 --- a/core/java/android/security/responsible_apis_flags.aconfig +++ b/core/java/android/security/responsible_apis_flags.aconfig @@ -67,6 +67,7 @@ flag { name: "aapm_api" namespace: "responsible_apis" description: "Android Advanced Protection Mode Service and Manager" + is_exported: true bug: "352420507" is_fixed_read_only: true } diff --git a/core/java/android/service/dreams/flags.aconfig b/core/java/android/service/dreams/flags.aconfig index 72f2de805474adb2da0892e29913bed681b59419..dfc11dcb5427e6e24b9917549620331efe6f5b18 100644 --- a/core/java/android/service/dreams/flags.aconfig +++ b/core/java/android/service/dreams/flags.aconfig @@ -67,3 +67,13 @@ flag { purpose: PURPOSE_BUGFIX } } + +flag { + name: "cleanup_dream_settings_on_uninstall" + namespace: "systemui" + description: "Cleans up dream settings if dream package is uninstalled." + bug: "338210427" + metadata { + purpose: PURPOSE_BUGFIX + } +} diff --git a/core/java/android/service/games/GameSession.java b/core/java/android/service/games/GameSession.java index e8d53d3517951b645b64c733f467de76db40fe93..531e0b11996ac05e9a6b2fd60fb664febe234d70 100644 --- a/core/java/android/service/games/GameSession.java +++ b/core/java/android/service/games/GameSession.java @@ -516,6 +516,8 @@ public abstract class GameSession { options, future); + trampolineIntent.collectExtraIntentKeys(); + try { int result = ActivityTaskManager.getService().startActivityFromGameSession( mContext.getIApplicationThread(), mContext.getPackageName(), "GameSession", diff --git a/core/java/android/service/notification/flags.aconfig b/core/java/android/service/notification/flags.aconfig index 34e311f8c932349709ba45b6e129e9cfc5ba46f1..d065939bc19ddb342729159535901ebf880b398b 100644 --- a/core/java/android/service/notification/flags.aconfig +++ b/core/java/android/service/notification/flags.aconfig @@ -65,4 +65,11 @@ flag { namespace: "systemui" description: "Allows the NAS to create and modify conversation notifications" bug: "373599715" -} \ No newline at end of file +} + +flag { + name: "notification_regroup_on_classification" + namespace: "systemui" + description: "This flag controls regrouping after notification classification" + bug: "372775153" +} diff --git a/core/java/android/service/settings/preferences/GetValueRequest.aidl b/core/java/android/service/settings/preferences/GetValueRequest.aidl new file mode 100644 index 0000000000000000000000000000000000000000..2a0eb09aa2a4cb8dfd4cc23fe21a9b1aba7a054d --- /dev/null +++ b/core/java/android/service/settings/preferences/GetValueRequest.aidl @@ -0,0 +1,4 @@ +package android.service.settings.preferences; + +/** @hide */ +parcelable GetValueRequest; \ No newline at end of file diff --git a/core/java/android/service/settings/preferences/GetValueRequest.java b/core/java/android/service/settings/preferences/GetValueRequest.java new file mode 100644 index 0000000000000000000000000000000000000000..4f82800d1855c0d6a278a57fb03b630e253cd01f --- /dev/null +++ b/core/java/android/service/settings/preferences/GetValueRequest.java @@ -0,0 +1,139 @@ +/* + * 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.service.settings.preferences; + +import android.annotation.FlaggedApi; +import android.os.Parcel; +import android.os.Parcelable; +import android.text.TextUtils; + +import androidx.annotation.NonNull; + +import com.android.settingslib.flags.Flags; + +import java.util.Objects; + +/** + * Request parameters to retrieve the current value of a Settings Preference. + * + *

    This object passed to {@link SettingsPreferenceService#onGetPreferenceValue} will result + * in a {@link GetValueResult}. + * + *

      + *
    • {@link #getScreenKey} is a parameter to distinguish the container screen + * of a preference as a preference key may not be unique within its application. + *
    • {@link #getPreferenceKey} is a parameter to identify the preference for which the value is + * being requested. These keys will be unique with their Preference Screen, but may not be unique + * within their application, so it is required to pair this with {@link #getScreenKey} to + * ensure this request matches the intended target. + *
    + */ +@FlaggedApi(Flags.FLAG_SETTINGS_CATALYST) +public final class GetValueRequest implements Parcelable { + + @NonNull + private final String mScreenKey; + @NonNull + private final String mPreferenceKey; + + /** + * Returns the screen key of requested Preference. + */ + @NonNull + public String getScreenKey() { + return mScreenKey; + } + + /** + * Returns the key of requested Preference. + */ + @NonNull + public String getPreferenceKey() { + return mPreferenceKey; + } + + private GetValueRequest(@NonNull Builder builder) { + mScreenKey = builder.mScreenKey; + mPreferenceKey = builder.mPreferenceKey; + } + + private GetValueRequest(@NonNull Parcel in) { + mScreenKey = Objects.requireNonNull(in.readString8()); + mPreferenceKey = Objects.requireNonNull(in.readString8()); + } + + /** @hide */ + @Override + public void writeToParcel(@NonNull Parcel dest, int flags) { + dest.writeString8(mScreenKey); + dest.writeString8(mPreferenceKey); + } + + /** @hide */ + @Override + public int describeContents() { + return 0; + } + + /** + * Parcelable Creator for {@link GetValueRequest}. + */ + @NonNull + public static final Creator CREATOR = new Creator() { + @Override + public GetValueRequest createFromParcel(@NonNull Parcel in) { + return new GetValueRequest(in); + } + + @Override + public GetValueRequest[] newArray(int size) { + return new GetValueRequest[size]; + } + }; + + /** + * Builder to construct {@link GetValueRequest}. + */ + public static final class Builder { + private final String mScreenKey; + private final String mPreferenceKey; + + /** + * Create Builder instance. + * @param screenKey required to be not empty + * @param preferenceKey required to be not empty + */ + public Builder(@NonNull String screenKey, @NonNull String preferenceKey) { + if (TextUtils.isEmpty(screenKey)) { + throw new IllegalArgumentException("screenKey cannot be empty"); + } + if (TextUtils.isEmpty(preferenceKey)) { + throw new IllegalArgumentException("preferenceKey cannot be empty"); + } + mScreenKey = screenKey; + mPreferenceKey = preferenceKey; + } + + /** + * Constructs an immutable {@link GetValueRequest} object. + */ + @NonNull + public GetValueRequest build() { + return new GetValueRequest(this); + } + } +} diff --git a/core/java/android/service/settings/preferences/GetValueResult.aidl b/core/java/android/service/settings/preferences/GetValueResult.aidl new file mode 100644 index 0000000000000000000000000000000000000000..b5ebd35a3a373139e65e2201bb9d3ed3709d863b --- /dev/null +++ b/core/java/android/service/settings/preferences/GetValueResult.aidl @@ -0,0 +1,4 @@ +package android.service.settings.preferences; + +/** @hide */ +parcelable GetValueResult; \ No newline at end of file diff --git a/core/java/android/service/settings/preferences/GetValueResult.java b/core/java/android/service/settings/preferences/GetValueResult.java new file mode 100644 index 0000000000000000000000000000000000000000..369dea77cc859535ecf98e3bfdd86b3c0295ce68 --- /dev/null +++ b/core/java/android/service/settings/preferences/GetValueResult.java @@ -0,0 +1,213 @@ +/* + * 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.service.settings.preferences; + +import android.annotation.FlaggedApi; +import android.annotation.IntDef; +import android.os.Parcel; +import android.os.Parcelable; + +import androidx.annotation.NonNull; +import androidx.annotation.Nullable; + +import com.android.settingslib.flags.Flags; + +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; + +/** + * Result object given a corresponding {@link GetValueRequest}. + *
      + *
    • If the request was successful, {@link #getResultCode} will be {@link #RESULT_OK}, + * {@link #getValue} will be populated with the settings preference value and + * {@link #getMetadata} will be populated with its metadata. + *
    • If the request is unsuccessful, {@link #getResultCode} be a value other than + * {@link #RESULT_OK} - see documentation for those possibilities to understand the cause + * of the failure. + *
    + */ +@FlaggedApi(Flags.FLAG_SETTINGS_CATALYST) +public final class GetValueResult implements Parcelable { + + @ResultCode + private final int mResultCode; + @Nullable + private final SettingsPreferenceValue mValue; + @Nullable + private final SettingsPreferenceMetadata mMetadata; + + /** + * Returns the result code indicating status of the request. + */ + @ResultCode + public int getResultCode() { + return mResultCode; + } + + /** + * Returns the value of requested Preference if request successful. + */ + @Nullable + public SettingsPreferenceValue getValue() { + return mValue; + } + + /** + * Returns the metadata of requested Preference if request successful. + */ + @Nullable + public SettingsPreferenceMetadata getMetadata() { + return mMetadata; + } + + /** @hide */ + @IntDef(prefix = { "RESULT_" }, value = { + RESULT_OK, + RESULT_UNSUPPORTED, + RESULT_UNAVAILABLE, + RESULT_REQUIRE_APP_PERMISSION, + RESULT_DISALLOW, + RESULT_INVALID_REQUEST, + RESULT_INTERNAL_ERROR, + }) + @Retention(RetentionPolicy.SOURCE) + public @interface ResultCode { + } + + /** Request is successful. */ + public static final int RESULT_OK = 0; + /** + * Requested preference is not supported by this API. + *

    Retry not advised. + */ + public static final int RESULT_UNSUPPORTED = 1; + /** + * Preference is currently not available, likely due to device state or the state of + * a dependency. + *

    Retry may succeed if underlying conditions change. + */ + public static final int RESULT_UNAVAILABLE = 2; + /** + * Requested preference requires permissions not held by the calling application. + *

    Retry may succeed if necessary permissions are obtained. + */ + public static final int RESULT_REQUIRE_APP_PERMISSION = 3; + /** + * Requested preference is not allowed for access in this API under the current device policy. + *

    Retry may succeed if underlying conditions change. + */ + public static final int RESULT_DISALLOW = 4; + /** + * Request object is not valid. + *

    Retry not advised with current parameters. + */ + public static final int RESULT_INVALID_REQUEST = 5; + /** + * API call failed due to an issue with the service binding. + *

    Retry may succeed. + */ + public static final int RESULT_INTERNAL_ERROR = 6; + + + private GetValueResult(@NonNull Builder builder) { + mResultCode = builder.mResultCode; + mValue = builder.mValue; + mMetadata = builder.mMetadata; + } + + private GetValueResult(@NonNull Parcel in) { + mResultCode = in.readInt(); + mValue = in.readParcelable(SettingsPreferenceValue.class.getClassLoader(), + SettingsPreferenceValue.class); + mMetadata = in.readParcelable(SettingsPreferenceMetadata.class.getClassLoader(), + SettingsPreferenceMetadata.class); + } + + /** @hide */ + @Override + public void writeToParcel(@NonNull Parcel dest, int flags) { + dest.writeInt(mResultCode); + dest.writeParcelable(mValue, flags); + dest.writeParcelable(mMetadata, flags); + } + + /** @hide */ + @Override + public int describeContents() { + return 0; + } + + /** + * Parcelable Creator for {@link GetValueResult}. + */ + @NonNull + public static final Creator CREATOR = new Creator<>() { + @Override + public GetValueResult createFromParcel(@NonNull Parcel in) { + return new GetValueResult(in); + } + + @Override + public GetValueResult[] newArray(int size) { + return new GetValueResult[size]; + } + }; + + /** + * Builder to construct {@link GetValueResult}. + */ + public static final class Builder { + @ResultCode + private final int mResultCode; + private SettingsPreferenceValue mValue; + private SettingsPreferenceMetadata mMetadata; + + /** + * Create Builder instance. + * @param resultCode indicates status of the request + */ + public Builder(@ResultCode int resultCode) { + mResultCode = resultCode; + } + + /** + * Sets the preference value on the result. + */ + @NonNull + public Builder setValue(@Nullable SettingsPreferenceValue value) { + mValue = value; + return this; + } + + /** + * Sets the metadata on the result. + */ + @NonNull + public Builder setMetadata(@Nullable SettingsPreferenceMetadata metadata) { + mMetadata = metadata; + return this; + } + + /** + * Constructs an immutable {@link GetValueResult} object. + */ + @NonNull + public GetValueResult build() { + return new GetValueResult(this); + } + } +} diff --git a/core/java/android/service/settings/preferences/IGetValueCallback.aidl b/core/java/android/service/settings/preferences/IGetValueCallback.aidl new file mode 100644 index 0000000000000000000000000000000000000000..bbc7423f453e4831cfb661004fdf40c6f9637fb8 --- /dev/null +++ b/core/java/android/service/settings/preferences/IGetValueCallback.aidl @@ -0,0 +1,9 @@ +package android.service.settings.preferences; + +import android.service.settings.preferences.GetValueResult; + +/** @hide */ +oneway interface IGetValueCallback { + void onSuccess(in GetValueResult result) = 1; + void onFailure() = 2; +} diff --git a/core/java/android/service/settings/preferences/IMetadataCallback.aidl b/core/java/android/service/settings/preferences/IMetadataCallback.aidl new file mode 100644 index 0000000000000000000000000000000000000000..3bd5ebe9366003aa722b1f6feba13e904bf0f210 --- /dev/null +++ b/core/java/android/service/settings/preferences/IMetadataCallback.aidl @@ -0,0 +1,9 @@ +package android.service.settings.preferences; + +import android.service.settings.preferences.MetadataResult; + +/** @hide */ +oneway interface IMetadataCallback { + void onSuccess(in MetadataResult result); + void onFailure(); +} diff --git a/core/java/android/service/settings/preferences/ISetValueCallback.aidl b/core/java/android/service/settings/preferences/ISetValueCallback.aidl new file mode 100644 index 0000000000000000000000000000000000000000..0765660c83c369061419cab6848b7558cd14aa27 --- /dev/null +++ b/core/java/android/service/settings/preferences/ISetValueCallback.aidl @@ -0,0 +1,9 @@ +package android.service.settings.preferences; + +import android.service.settings.preferences.SetValueResult; + +/** @hide */ +oneway interface ISetValueCallback { + void onSuccess(in SetValueResult result); + void onFailure(); +} diff --git a/core/java/android/service/settings/preferences/ISettingsPreferenceService.aidl b/core/java/android/service/settings/preferences/ISettingsPreferenceService.aidl new file mode 100644 index 0000000000000000000000000000000000000000..64a8b90fe581e984124e70bfa3e9f45a8806828b --- /dev/null +++ b/core/java/android/service/settings/preferences/ISettingsPreferenceService.aidl @@ -0,0 +1,18 @@ +package android.service.settings.preferences; + +import android.service.settings.preferences.GetValueRequest; +import android.service.settings.preferences.IGetValueCallback; +import android.service.settings.preferences.IMetadataCallback; +import android.service.settings.preferences.ISetValueCallback; +import android.service.settings.preferences.MetadataRequest; +import android.service.settings.preferences.SetValueRequest; + +/** @hide */ +oneway interface ISettingsPreferenceService { + @EnforcePermission("READ_SYSTEM_PREFERENCES") + void getAllPreferenceMetadata(in MetadataRequest request, IMetadataCallback callback) = 1; + @EnforcePermission("READ_SYSTEM_PREFERENCES") + void getPreferenceValue(in GetValueRequest request, IGetValueCallback callback) = 2; + @EnforcePermission(allOf = {"READ_SYSTEM_PREFERENCES", "WRITE_SYSTEM_PREFERENCES"}) + void setPreferenceValue(in SetValueRequest request, ISetValueCallback callback) = 3; +} diff --git a/core/java/android/service/settings/preferences/MetadataRequest.aidl b/core/java/android/service/settings/preferences/MetadataRequest.aidl new file mode 100644 index 0000000000000000000000000000000000000000..dc3cbc42661e62faa8f15077b2e10b6443cd26fc --- /dev/null +++ b/core/java/android/service/settings/preferences/MetadataRequest.aidl @@ -0,0 +1,4 @@ +package android.service.settings.preferences; + +/** @hide */ +parcelable MetadataRequest; \ No newline at end of file diff --git a/core/java/android/service/settings/preferences/MetadataRequest.java b/core/java/android/service/settings/preferences/MetadataRequest.java new file mode 100644 index 0000000000000000000000000000000000000000..ffecc6bec5b293dcde2753f06bbafeda10112b0b --- /dev/null +++ b/core/java/android/service/settings/preferences/MetadataRequest.java @@ -0,0 +1,75 @@ +/* + * 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.service.settings.preferences; + +import android.annotation.FlaggedApi; +import android.os.Parcel; +import android.os.Parcelable; + +import androidx.annotation.NonNull; + +import com.android.settingslib.flags.Flags; + +/** + * Request parameters to retrieve all metadata for all available settings preferences within this + * application. + * + *

    This object passed to {@link SettingsPreferenceService#onGetAllPreferenceMetadata} will result + * in a {@link MetadataResult}. + */ +@FlaggedApi(Flags.FLAG_SETTINGS_CATALYST) +public final class MetadataRequest implements Parcelable { + private MetadataRequest() {} + + /** @hide */ + @Override + public void writeToParcel(@NonNull Parcel dest, int flags) { + } + + /** @hide */ + @Override + public int describeContents() { + return 0; + } + + /** + * Parcelable Creator for {@link MetadataRequest}. + */ + @NonNull + public static final Creator CREATOR = new Creator<>() { + @Override + public MetadataRequest createFromParcel(@NonNull Parcel in) { + return new MetadataRequest(); + } + + @Override + public MetadataRequest[] newArray(int size) { + return new MetadataRequest[size]; + } + }; + + /** + * Builder to construct {@link MetadataRequest}. + */ + public static final class Builder { + /** Constructs an immutable {@link MetadataRequest} object. */ + @NonNull + public MetadataRequest build() { + return new MetadataRequest(); + } + } +} diff --git a/core/java/android/service/settings/preferences/MetadataResult.aidl b/core/java/android/service/settings/preferences/MetadataResult.aidl new file mode 100644 index 0000000000000000000000000000000000000000..af9e8a86e3abfc84e63907e8d7f9cf3b7ef13c85 --- /dev/null +++ b/core/java/android/service/settings/preferences/MetadataResult.aidl @@ -0,0 +1,4 @@ +package android.service.settings.preferences; + +/** @hide */ +parcelable MetadataResult; \ No newline at end of file diff --git a/core/java/android/service/settings/preferences/MetadataResult.java b/core/java/android/service/settings/preferences/MetadataResult.java new file mode 100644 index 0000000000000000000000000000000000000000..6a65dcc9c757a4309844a9b229d24b1667ab7a51 --- /dev/null +++ b/core/java/android/service/settings/preferences/MetadataResult.java @@ -0,0 +1,164 @@ +/* + * 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.service.settings.preferences; + +import android.annotation.FlaggedApi; +import android.annotation.IntDef; +import android.os.Parcel; +import android.os.Parcelable; + +import androidx.annotation.NonNull; + +import com.android.settingslib.flags.Flags; + +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; + +/** + * Result object given a corresponding {@link MetadataRequest}. + *

      + *
    • If the request was successful, {@link #getResultCode} will be {@link #RESULT_OK} and + * {@link #getMetadataList} will be populated with metadata for all available preferences within + * this application. + *
    • If the request is unsuccessful, {@link #getResultCode} be a value other than + * {@link #RESULT_OK} - see documentation for those possibilities to understand the cause + * of the failure. + *
    + */ +@FlaggedApi(Flags.FLAG_SETTINGS_CATALYST) +public final class MetadataResult implements Parcelable { + + @ResultCode + private final int mResultCode; + @NonNull + private final List mMetadataList; + + /** + * Returns the result code indicating status of the request. + */ + @ResultCode + public int getResultCode() { + return mResultCode; + } + + /** + * Returns the list of available Preference Metadata. + *

    This instance is shared so this list should not be modified. + */ + @NonNull + public List getMetadataList() { + return mMetadataList; + } + + /** @hide */ + @IntDef(prefix = { "RESULT_" }, value = { + RESULT_OK, + RESULT_UNSUPPORTED, + RESULT_INTERNAL_ERROR + }) + @Retention(RetentionPolicy.SOURCE) + public @interface ResultCode { + } + + /** Request is successful. */ + public static final int RESULT_OK = 0; + /** + * No preferences in this application support this API. + *

    Retry not advised. + */ + public static final int RESULT_UNSUPPORTED = 1; + /** + * API call failed due to an issue with the service binding. + *

    Retry may succeed. + */ + public static final int RESULT_INTERNAL_ERROR = 2; + + private MetadataResult(@NonNull Builder builder) { + mResultCode = builder.mResultCode; + mMetadataList = builder.mMetadataList; + } + private MetadataResult(@NonNull Parcel in) { + mResultCode = in.readInt(); + mMetadataList = new ArrayList<>(); + in.readTypedList(mMetadataList, SettingsPreferenceMetadata.CREATOR); + } + + /** @hide */ + @Override + public void writeToParcel(@NonNull Parcel dest, int flags) { + dest.writeInt(mResultCode); + dest.writeTypedList(mMetadataList, flags); + } + + /** @hide */ + @Override + public int describeContents() { + return 0; + } + + /** + * Parcelable Creator for {@link MetadataResult}. + */ + @NonNull + public static final Creator CREATOR = new Creator<>() { + @Override + public MetadataResult createFromParcel(@NonNull Parcel in) { + return new MetadataResult(in); + } + + @Override + public MetadataResult[] newArray(int size) { + return new MetadataResult[size]; + } + }; + + /** + * Builder to construct {@link MetadataResult}. + */ + public static final class Builder { + @ResultCode + private final int mResultCode; + private List mMetadataList = Collections.emptyList(); + + /** + * Create Builder instance. + * @param resultCode indicates status of the request + */ + public Builder(@ResultCode int resultCode) { + mResultCode = resultCode; + } + + /** + * Sets the metadata list on the result. + */ + @NonNull + public Builder setMetadataList(@NonNull List metadataList) { + mMetadataList = metadataList; + return this; + } + + /** + * Constructs an immutable {@link MetadataResult} object. + */ + @NonNull + public MetadataResult build() { + return new MetadataResult(this); + } + } +} diff --git a/core/java/android/service/settings/preferences/SetValueRequest.aidl b/core/java/android/service/settings/preferences/SetValueRequest.aidl new file mode 100644 index 0000000000000000000000000000000000000000..198e333d5cb65c90408782bf7667c8f4e9334a8c --- /dev/null +++ b/core/java/android/service/settings/preferences/SetValueRequest.aidl @@ -0,0 +1,4 @@ +package android.service.settings.preferences; + +/** @hide */ +parcelable SetValueRequest; \ No newline at end of file diff --git a/core/java/android/service/settings/preferences/SetValueRequest.java b/core/java/android/service/settings/preferences/SetValueRequest.java new file mode 100644 index 0000000000000000000000000000000000000000..f7600aecdfaf3fc511112e275617054037a356cd --- /dev/null +++ b/core/java/android/service/settings/preferences/SetValueRequest.java @@ -0,0 +1,158 @@ +/* + * 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.service.settings.preferences; + +import android.annotation.FlaggedApi; +import android.os.Parcel; +import android.os.Parcelable; +import android.text.TextUtils; + +import androidx.annotation.NonNull; + +import com.android.settingslib.flags.Flags; + +import java.util.Objects; + +/** + * Request parameters to set the current value to a Settings Preference. + *

    This object passed to {@link SettingsPreferenceService#onSetPreferenceValue} will result in a + * {@link SetValueResult}. + *

      + *
    • {@link #getScreenKey} is a parameter to distinguish the container screen + * of a preference as a preference key may not be unique within its application. + *
    • {@link #getPreferenceKey} is a parameter to identify the preference for which the value is + * being requested. These keys will be unique with their Preference Screen, but may not be unique + * within their application, so it is required to pair this with {@link #getScreenKey} to + * ensure this request matches the intended target. + *
    • {@link #getPreferenceValue} is a parameter to specify the value that this request aims to + * set. If this value is invalid (malformed or does not match the type of the preference) then + * this request will fail. + *
    + */ +@FlaggedApi(Flags.FLAG_SETTINGS_CATALYST) +public final class SetValueRequest implements Parcelable { + + @NonNull + private final String mScreenKey; + @NonNull + private final String mPreferenceKey; + @NonNull + private final SettingsPreferenceValue mPreferenceValue; + + /** + * Returns the screen key of requested Preference. + */ + @NonNull + public String getScreenKey() { + return mScreenKey; + } + + /** + * Returns the key of requested Preference. + */ + @NonNull + public String getPreferenceKey() { + return mPreferenceKey; + } + + /** + * Returns the value of requested Preference. + */ + @NonNull + public SettingsPreferenceValue getPreferenceValue() { + return mPreferenceValue; + } + + private SetValueRequest(@NonNull Builder builder) { + mScreenKey = builder.mScreenKey; + mPreferenceKey = builder.mPreferenceKey; + mPreferenceValue = builder.mPreferenceValue; + } + + private SetValueRequest(@NonNull Parcel in) { + mScreenKey = Objects.requireNonNull(in.readString8()); + mPreferenceKey = Objects.requireNonNull(in.readString8()); + mPreferenceValue = Objects.requireNonNull(in.readParcelable( + SettingsPreferenceValue.class.getClassLoader(), SettingsPreferenceValue.class)); + } + + /** @hide */ + @Override + public void writeToParcel(@NonNull Parcel dest, int flags) { + dest.writeString8(mScreenKey); + dest.writeString8(mPreferenceKey); + dest.writeParcelable(mPreferenceValue, flags); + } + + /** @hide */ + @Override + public int describeContents() { + return 0; + } + + /** + * Parcelable Creator for {@link SetValueRequest}. + */ + @NonNull + public static final Creator CREATOR = new Creator() { + @Override + public SetValueRequest createFromParcel(@NonNull Parcel in) { + return new SetValueRequest(in); + } + + @Override + public SetValueRequest[] newArray(int size) { + return new SetValueRequest[size]; + } + }; + + /** + * Builder to construct {@link SetValueRequest}. + */ + public static final class Builder { + private final String mScreenKey; + private final String mPreferenceKey; + private final SettingsPreferenceValue mPreferenceValue; + + /** + * Create Builder instance. + * @param screenKey required to be not empty + * @param preferenceKey required to be not empty + * @param value value to set to requested Preference + */ + public Builder(@NonNull String screenKey, @NonNull String preferenceKey, + @NonNull SettingsPreferenceValue value) { + if (TextUtils.isEmpty(screenKey)) { + throw new IllegalArgumentException("screenKey cannot be empty"); + } + if (TextUtils.isEmpty(preferenceKey)) { + throw new IllegalArgumentException("preferenceKey cannot be empty"); + } + mScreenKey = screenKey; + mPreferenceKey = preferenceKey; + mPreferenceValue = value; + } + + /** + * Constructs an immutable {@link SetValueRequest} object. + */ + @NonNull + public SetValueRequest build() { + return new SetValueRequest(this); + } + } +} diff --git a/core/java/android/service/settings/preferences/SetValueResult.aidl b/core/java/android/service/settings/preferences/SetValueResult.aidl new file mode 100644 index 0000000000000000000000000000000000000000..f54813484d68f39affa1046aa08d2635821b2dfd --- /dev/null +++ b/core/java/android/service/settings/preferences/SetValueResult.aidl @@ -0,0 +1,4 @@ +package android.service.settings.preferences; + +/** @hide */ +parcelable SetValueResult; \ No newline at end of file diff --git a/core/java/android/service/settings/preferences/SetValueResult.java b/core/java/android/service/settings/preferences/SetValueResult.java new file mode 100644 index 0000000000000000000000000000000000000000..cb1776abd3bccbaf84feadc55dadab8aad20d740 --- /dev/null +++ b/core/java/android/service/settings/preferences/SetValueResult.java @@ -0,0 +1,179 @@ +/* + * 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.service.settings.preferences; + +import android.annotation.FlaggedApi; +import android.annotation.IntDef; +import android.os.Parcel; +import android.os.Parcelable; + +import androidx.annotation.NonNull; + +import com.android.settingslib.flags.Flags; + +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; + +/** + * Result object given a corresponding {@link SetValueRequest}. + *
      + *
    • If the request was successful, {@link #getResultCode} will be {@link #RESULT_OK}. + *
    • If the request is unsuccessful, {@link #getResultCode} be a value other than + * {@link #RESULT_OK} - see documentation for those possibilities to understand the cause + * of the failure. + *
    + */ +@FlaggedApi(Flags.FLAG_SETTINGS_CATALYST) +public final class SetValueResult implements Parcelable { + + @ResultCode + private final int mResultCode; + + /** + * Returns the result code indicating status of the request. + */ + @ResultCode + public int getResultCode() { + return mResultCode; + } + + /** @hide */ + @IntDef(prefix = { "RESULT_" }, value = { + RESULT_OK, + RESULT_UNSUPPORTED, + RESULT_DISABLED, + RESULT_RESTRICTED, + RESULT_UNAVAILABLE, + RESULT_REQUIRE_APP_PERMISSION, + RESULT_REQUIRE_USER_CONSENT, + RESULT_DISALLOW, + RESULT_INVALID_REQUEST, + RESULT_INTERNAL_ERROR + }) + @Retention(RetentionPolicy.SOURCE) + public @interface ResultCode { + } + + /** Request is successful and the value was set. */ + public static final int RESULT_OK = 0; + /** + * Requested preference is not supported by this API. + *

    Retry not advised. + */ + public static final int RESULT_UNSUPPORTED = 1; + /** + * Requested preference is disabled, thus unable to be set in this state. + *

    Retry may succeed if underlying conditions change. + */ + public static final int RESULT_DISABLED = 2; + /** + * Requested preference is restricted, thus unable to be set under this policy. + *

    Retry may succeed if underlying conditions change. + */ + public static final int RESULT_RESTRICTED = 3; + /** + * Preference is currently not available, likely due to device state or the state of + * a dependency. + *

    Retry may succeed if underlying conditions change. + */ + public static final int RESULT_UNAVAILABLE = 4; + /** + * Requested preference requires permissions not held by the calling application. + *

    Retry may succeed if necessary permissions are obtained. + */ + public static final int RESULT_REQUIRE_APP_PERMISSION = 5; + /** + * User consent was not approved for this operation. + *

    Retry may succeed if user provides consent. + */ + public static final int RESULT_REQUIRE_USER_CONSENT = 6; + /** + * Requested preference is not allowed for access in this API under the current device policy. + *

    Retry may succeed if underlying conditions change. + */ + public static final int RESULT_DISALLOW = 7; + /** + * Request object is not valid. + *

    Retry not advised with current parameters. + */ + public static final int RESULT_INVALID_REQUEST = 8; + /** + * API call failed due to an issue with the service binding. + *

    Retry may succeed. + */ + public static final int RESULT_INTERNAL_ERROR = 9; + + private SetValueResult(@NonNull Builder builder) { + mResultCode = builder.mResultCode; + } + + private SetValueResult(@NonNull Parcel in) { + mResultCode = in.readInt(); + } + + /** @hide */ + @Override + public void writeToParcel(@NonNull Parcel dest, int flags) { + dest.writeInt(mResultCode); + } + + /** @hide */ + @Override + public int describeContents() { + return 0; + } + + /** + * Parcelable Creator for {@link SetValueResult}. + */ + @NonNull + public static final Creator CREATOR = new Creator<>() { + @Override + public SetValueResult createFromParcel(@NonNull Parcel in) { + return new SetValueResult(in); + } + + @Override + public SetValueResult[] newArray(int size) { + return new SetValueResult[size]; + } + }; + + /** + * Builder to construct {@link SetValueResult}. + */ + public static final class Builder { + @ResultCode + private final int mResultCode; + + /** + * Create Builder instance. + * @param resultCode indicates status of the request + */ + public Builder(@ResultCode int resultCode) { + mResultCode = resultCode; + } + + /** + * Constructs an immutable {@link SetValueResult} object. + */ + @NonNull + public SetValueResult build() { + return new SetValueResult(this); + } + } +} diff --git a/core/java/android/service/settings/preferences/SettingsPreferenceMetadata.java b/core/java/android/service/settings/preferences/SettingsPreferenceMetadata.java new file mode 100644 index 0000000000000000000000000000000000000000..1d08c5217129b662439ebb9152ae497a50b873c4 --- /dev/null +++ b/core/java/android/service/settings/preferences/SettingsPreferenceMetadata.java @@ -0,0 +1,436 @@ +/* + * 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.service.settings.preferences; + +import android.annotation.FlaggedApi; +import android.annotation.IntDef; +import android.annotation.SuppressLint; +import android.app.PendingIntent; +import android.os.Bundle; +import android.os.Parcel; +import android.os.Parcelable; +import android.text.TextUtils; + +import androidx.annotation.NonNull; +import androidx.annotation.Nullable; + +import com.android.settingslib.flags.Flags; + +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; +import java.util.Objects; + +/** + * Data object representation of a Settings Preference definition and state. + */ +@FlaggedApi(Flags.FLAG_SETTINGS_CATALYST) +public final class SettingsPreferenceMetadata implements Parcelable { + + @NonNull + private final String mKey; + @NonNull + private final String mScreenKey; + @Nullable + private final String mTitle; + @Nullable + private final String mSummary; + @NonNull + private final List mBreadcrumbs; + @NonNull + private final List mReadPermissions; + @NonNull + private final List mWritePermissions; + private final boolean mEnabled; + private final boolean mAvailable; + private final boolean mWritable; + private final boolean mRestricted; + private final int mSensitivity; + @Nullable + private final PendingIntent mLaunchIntent; + @NonNull + private final Bundle mExtras; + + /** + * Returns the key of Preference. + */ + @NonNull + public String getKey() { + return mKey; + } + + /** + * Returns the screen key of Preference. + */ + @NonNull + public String getScreenKey() { + return mScreenKey; + } + + /** + * Returns the title of Preference. + */ + @Nullable + public String getTitle() { + return mTitle; + } + + /** + * Returns the summary of Preference. + */ + @Nullable + public String getSummary() { + return mSummary; + } + + /** + * Returns the breadcrumbs (navigation context) of Preference. + *

    May be empty. + */ + @NonNull + public List getBreadcrumbs() { + return mBreadcrumbs; + } + + /** + * Returns the permissions required to read this Preference's value. + *

    May be empty. + */ + @NonNull + public List getReadPermissions() { + return mReadPermissions; + } + + /** + * Returns the permissions required to write this Preference's value. + *

    May be empty. + */ + @NonNull + public List getWritePermissions() { + return mWritePermissions; + } + + /** + * Returns whether Preference is enabled. + */ + public boolean isEnabled() { + return mEnabled; + } + + /** + * Returns whether Preference is available. + */ + public boolean isAvailable() { + return mAvailable; + } + + /** + * Returns whether Preference is writable. + */ + public boolean isWritable() { + return mWritable; + } + + /** + * Returns whether Preference is restricted. + */ + public boolean isRestricted() { + return mRestricted; + } + + /** + * Returns the write-level sensitivity of Preference. + */ + @WriteSensitivity + public int getWriteSensitivity() { + return mSensitivity; + } + + /** + * Returns the intent to launch the host app page for this Preference. + */ + @Nullable + public PendingIntent getLaunchIntent() { + return mLaunchIntent; + } + + /** + * Returns any additional fields specific to this preference. + *

    Treat all data as optional. + */ + @NonNull + public Bundle getExtras() { + return mExtras; + } + + /** @hide */ + @IntDef(value = { + NOT_SENSITIVE, + SENSITIVE, + INTENT_ONLY + }) + @Retention(RetentionPolicy.SOURCE) + public @interface WriteSensitivity {} + + /** + * Preference is not sensitive, thus its value is writable without explicit consent, assuming + * all necessary permissions are granted. + */ + public static final int NOT_SENSITIVE = 0; + /** + * Preference is sensitive, meaning that in addition to necessary permissions, writing its value + * will also request explicit user consent. + */ + public static final int SENSITIVE = 1; + /** + * Preference is not permitted for write-access via API and must be changed via Settings page. + */ + public static final int INTENT_ONLY = 2; + + private SettingsPreferenceMetadata(@NonNull Builder builder) { + mKey = builder.mKey; + mScreenKey = builder.mScreenKey; + mTitle = builder.mTitle; + mSummary = builder.mSummary; + mBreadcrumbs = builder.mBreadcrumbs; + mReadPermissions = builder.mReadPermissions; + mWritePermissions = builder.mWritePermissions; + mEnabled = builder.mEnabled; + mAvailable = builder.mAvailable; + mWritable = builder.mWritable; + mRestricted = builder.mRestricted; + mSensitivity = builder.mSensitivity; + mLaunchIntent = builder.mLaunchIntent; + mExtras = Objects.requireNonNullElseGet(builder.mExtras, Bundle::new); + } + @SuppressLint("ParcelClassLoader") + private SettingsPreferenceMetadata(@NonNull Parcel in) { + mKey = Objects.requireNonNull(in.readString8()); + mScreenKey = Objects.requireNonNull(in.readString8()); + mTitle = in.readString8(); + mSummary = in.readString8(); + mBreadcrumbs = new ArrayList<>(); + in.readStringList(mBreadcrumbs); + mReadPermissions = new ArrayList<>(); + in.readStringList(mReadPermissions); + mWritePermissions = new ArrayList<>(); + in.readStringList(mWritePermissions); + mEnabled = in.readBoolean(); + mAvailable = in.readBoolean(); + mWritable = in.readBoolean(); + mRestricted = in.readBoolean(); + mSensitivity = in.readInt(); + mLaunchIntent = in.readParcelable(PendingIntent.class.getClassLoader(), + PendingIntent.class); + mExtras = Objects.requireNonNullElseGet(in.readBundle(), Bundle::new); + } + + /** @hide */ + @Override + public int describeContents() { + return 0; + } + + /** @hide */ + @Override + public void writeToParcel(@NonNull Parcel dest, int flags) { + dest.writeString8(mKey); + dest.writeString8(mScreenKey); + dest.writeString8(mTitle); + dest.writeString8(mSummary); + dest.writeStringList(mBreadcrumbs); + dest.writeStringList(mReadPermissions); + dest.writeStringList(mWritePermissions); + dest.writeBoolean(mEnabled); + dest.writeBoolean(mAvailable); + dest.writeBoolean(mWritable); + dest.writeBoolean(mRestricted); + dest.writeInt(mSensitivity); + dest.writeParcelable(mLaunchIntent, flags); + dest.writeBundle(mExtras); + } + + /** + * Parcelable Creator for {@link SettingsPreferenceMetadata}. + */ + @NonNull + public static final Creator CREATOR = new Creator<>() { + @Override + public SettingsPreferenceMetadata createFromParcel(@NonNull Parcel in) { + return new SettingsPreferenceMetadata(in); + } + + @Override + public SettingsPreferenceMetadata[] newArray(int size) { + return new SettingsPreferenceMetadata[size]; + } + }; + + /** + * Builder to construct {@link SettingsPreferenceMetadata}. + */ + public static final class Builder { + private final String mScreenKey; + private final String mKey; + private String mTitle; + private String mSummary; + private List mBreadcrumbs = Collections.emptyList(); + private List mReadPermissions = Collections.emptyList(); + private List mWritePermissions = Collections.emptyList(); + private boolean mEnabled = false; + private boolean mAvailable = false; + private boolean mWritable = false; + private boolean mRestricted = false; + @WriteSensitivity private int mSensitivity = INTENT_ONLY; + private PendingIntent mLaunchIntent; + private Bundle mExtras; + + /** + * Create Builder instance. + * @param screenKey required to be not empty + * @param key required to be not empty + */ + public Builder(@NonNull String screenKey, @NonNull String key) { + if (TextUtils.isEmpty(screenKey)) { + throw new IllegalArgumentException("screenKey cannot be empty"); + } + if (TextUtils.isEmpty(key)) { + throw new IllegalArgumentException("key cannot be empty"); + } + mScreenKey = screenKey; + mKey = key; + } + + /** + * Sets the preference title. + */ + @NonNull + public Builder setTitle(@Nullable String title) { + mTitle = title; + return this; + } + + /** + * Sets the preference summary. + */ + @NonNull + public Builder setSummary(@Nullable String summary) { + mSummary = summary; + return this; + } + + /** + * Sets the preference breadcrumbs (navigation context). + */ + @NonNull + public Builder setBreadcrumbs(@NonNull List breadcrumbs) { + mBreadcrumbs = breadcrumbs; + return this; + } + + /** + * Sets the permissions required for reading this preference. + */ + @NonNull + public Builder setReadPermissions(@NonNull List readPermissions) { + mReadPermissions = readPermissions; + return this; + } + + /** + * Sets the permissions required for writing this preference. + */ + @NonNull + public Builder setWritePermissions(@NonNull List writePermissions) { + mWritePermissions = writePermissions; + return this; + } + + /** + * Set whether the preference is enabled. + */ + @NonNull + public Builder setEnabled(boolean enabled) { + mEnabled = enabled; + return this; + } + + /** + * Sets whether the preference is available. + */ + @NonNull + public Builder setAvailable(boolean available) { + mAvailable = available; + return this; + } + + /** + * Sets whether the preference is writable. + */ + @NonNull + public Builder setWritable(boolean writable) { + mWritable = writable; + return this; + } + + /** + * Sets whether the preference is restricted. + */ + @NonNull + public Builder setRestricted(boolean restricted) { + mRestricted = restricted; + return this; + } + + /** + * Sets the preference write-level sensitivity. + */ + @NonNull + public Builder setWriteSensitivity(@WriteSensitivity int sensitivity) { + mSensitivity = sensitivity; + return this; + } + + /** + * Sets the intent to launch the host app page for this preference. + */ + @NonNull + public Builder setLaunchIntent(@Nullable PendingIntent launchIntent) { + mLaunchIntent = launchIntent; + return this; + } + + /** + * Sets additional fields specific to this preference. Treat all data as optional. + */ + @NonNull + public Builder setExtras(@NonNull Bundle extras) { + mExtras = extras; + return this; + } + + /** + * Constructs an immutable {@link SettingsPreferenceMetadata} object. + */ + @NonNull + public SettingsPreferenceMetadata build() { + return new SettingsPreferenceMetadata(this); + } + } +} diff --git a/core/java/android/service/settings/preferences/SettingsPreferenceService.java b/core/java/android/service/settings/preferences/SettingsPreferenceService.java new file mode 100644 index 0000000000000000000000000000000000000000..4a4b5d201f09579b0ea827af9d79c7da3e4c9a5f --- /dev/null +++ b/core/java/android/service/settings/preferences/SettingsPreferenceService.java @@ -0,0 +1,201 @@ +/* + * 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.service.settings.preferences; + +import android.Manifest; +import android.annotation.EnforcePermission; +import android.annotation.FlaggedApi; +import android.app.Service; +import android.content.Intent; +import android.content.pm.PackageManager; +import android.os.IBinder; +import android.os.OutcomeReceiver; +import android.os.PermissionEnforcer; +import android.os.RemoteException; + +import androidx.annotation.NonNull; +import androidx.annotation.Nullable; + +import com.android.settingslib.flags.Flags; + +/** + * Base class for a service that exposes its settings preferences to external access. + *

    This class is to be implemented by apps that contribute to the Android Settings surface. + * Access to this service is permission guarded by + * {@link android.permission.READ_SYSTEM_PREFERENCES} for binding and reading, and guarded by both + * {@link android.permission.READ_SYSTEM_PREFERENCES} and + * {@link android.permission.WRITE_SYSTEM_PREFERENCES} for writing. An additional checks for access + * control are the responsibility of the implementing class. + * + *

    This implementation must correspond to an exported service declaration in the host app + * AndroidManifest.xml as follows + *

    + * {@literal
    + * 
    + *     
    + *         
    + *     
    + * }
    + * 
    + * + *
      + *
    • It is recommended to expose the metadata for most, if not all, preferences within a + * settings app, thus implementing {@link #onGetAllPreferenceMetadata}. + *
    • Exposing preferences for read access of their values is up to the implementer, but any + * exposed must be a subset of the preferences exposed in {@link #onGetAllPreferenceMetadata}. + * To expose a preference for read access, the implementation will contain + * {@link #onGetPreferenceValue}. + *
    • Exposing a preference for write access of their values is up to the implementer, but should + * be done so with extra care and consideration, both for security and privacy. These must also + * be a subset of those exposed in {@link #onGetAllPreferenceMetadata}. To expose a preference for + * write access, the implementation will contain {@link #onSetPreferenceValue}. + *
    + */ +@FlaggedApi(Flags.FLAG_SETTINGS_CATALYST) +public abstract class SettingsPreferenceService extends Service { + + /** + * Intent Action corresponding to a {@link SettingsPreferenceService}. Note that any checks for + * such services must be accompanied by a check to ensure the host is a system application. + * Given an {@link android.content.pm.ApplicationInfo} you can check for + * {@link android.content.pm.ApplicationInfo#FLAG_SYSTEM}, or when querying + * {@link PackageManager#queryIntentServices} you can provide the flag + * {@link PackageManager#MATCH_SYSTEM_ONLY}. + */ + public static final String ACTION_PREFERENCE_SERVICE = + "android.service.settings.preferences.action.PREFERENCE_SERVICE"; + + /** @hide */ + @NonNull + @Override + public final IBinder onBind(@Nullable Intent intent) { + return new ISettingsPreferenceService.Stub( + PermissionEnforcer.fromContext(getApplicationContext())) { + @EnforcePermission(Manifest.permission.READ_SYSTEM_PREFERENCES) + @Override + public void getAllPreferenceMetadata(MetadataRequest request, + IMetadataCallback callback) { + getAllPreferenceMetadata_enforcePermission(); + onGetAllPreferenceMetadata(request, new OutcomeReceiver<>() { + @Override + public void onResult(MetadataResult result) { + try { + callback.onSuccess(result); + } catch (RemoteException e) { + e.rethrowFromSystemServer(); + } + } + + @Override + public void onError(@NonNull Exception error) { + try { + callback.onFailure(); + } catch (RemoteException e) { + e.rethrowFromSystemServer(); + } + } + }); + } + + @EnforcePermission(Manifest.permission.READ_SYSTEM_PREFERENCES) + @Override + public void getPreferenceValue(GetValueRequest request, IGetValueCallback callback) { + getPreferenceValue_enforcePermission(); + onGetPreferenceValue(request, new OutcomeReceiver<>() { + @Override + public void onResult(GetValueResult result) { + try { + callback.onSuccess(result); + } catch (RemoteException e) { + e.rethrowFromSystemServer(); + } + } + + @Override + public void onError(@NonNull Exception error) { + try { + callback.onFailure(); + } catch (RemoteException e) { + e.rethrowFromSystemServer(); + } + } + }); + } + + @EnforcePermission(allOf = { + Manifest.permission.READ_SYSTEM_PREFERENCES, + Manifest.permission.WRITE_SYSTEM_PREFERENCES + }) + @Override + public void setPreferenceValue(SetValueRequest request, ISetValueCallback callback) { + setPreferenceValue_enforcePermission(); + onSetPreferenceValue(request, new OutcomeReceiver<>() { + @Override + public void onResult(SetValueResult result) { + try { + callback.onSuccess(result); + } catch (RemoteException e) { + e.rethrowFromSystemServer(); + } + } + + @Override + public void onError(@NonNull Exception error) { + try { + callback.onFailure(); + } catch (RemoteException e) { + e.rethrowFromSystemServer(); + } + } + }); + } + }; + } + + /** + * Retrieve the metadata for all exposed settings preferences within this application. This + * data should be a snapshot of their state at the time of this method being called. + * @param request object to specify request parameters + * @param callback object to receive result or failure of request + */ + public abstract void onGetAllPreferenceMetadata( + @NonNull MetadataRequest request, + @NonNull OutcomeReceiver callback); + + /** + * Retrieve the current value of the requested settings preference. If this value is not exposed + * or cannot be obtained for some reason, the corresponding result code will be set on the + * result object. + * @param request object to specify request parameters + * @param callback object to receive result or failure of request + */ + public abstract void onGetPreferenceValue( + @NonNull GetValueRequest request, + @NonNull OutcomeReceiver callback); + + /** + * Set the value within the request to the target settings preference. If this value cannot + * be written for some reason, the corresponding result code will be set on the result object. + * @param request object to specify request parameters + * @param callback object to receive result or failure of request + */ + public abstract void onSetPreferenceValue( + @NonNull SetValueRequest request, + @NonNull OutcomeReceiver callback); +} diff --git a/core/java/android/service/settings/preferences/SettingsPreferenceServiceClient.java b/core/java/android/service/settings/preferences/SettingsPreferenceServiceClient.java new file mode 100644 index 0000000000000000000000000000000000000000..39995a47fcbe65a803803831c42c74eab78e922d --- /dev/null +++ b/core/java/android/service/settings/preferences/SettingsPreferenceServiceClient.java @@ -0,0 +1,248 @@ +/* + * 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.service.settings.preferences; + +import static android.service.settings.preferences.SettingsPreferenceService.ACTION_PREFERENCE_SERVICE; + +import android.annotation.CallbackExecutor; +import android.annotation.FlaggedApi; +import android.annotation.TestApi; +import android.content.ComponentName; +import android.content.Context; +import android.content.Intent; +import android.content.ServiceConnection; +import android.content.pm.PackageManager; +import android.content.pm.ResolveInfo; +import android.os.IBinder; +import android.os.OutcomeReceiver; +import android.os.RemoteException; + +import androidx.annotation.NonNull; +import androidx.annotation.Nullable; + +import com.android.settingslib.flags.Flags; + +import java.util.List; +import java.util.concurrent.Executor; + +/** + * Client class responsible for binding to and interacting with an instance of + * {@link SettingsPreferenceService}. + *

    This is a convenience class to handle the lifecycle of the service connection. + *

    This client will only interact with one instance at a time, + * so if the caller requires multiple instances (multiple applications that provide settings), then + * the caller must create multiple client classes, one for each instance required. To find all + * 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}). + */ +@FlaggedApi(Flags.FLAG_SETTINGS_CATALYST) +public class SettingsPreferenceServiceClient implements AutoCloseable { + + private final Context mContext; + private final Intent mServiceIntent; + private final ServiceConnection mServiceConnection; + private final boolean mSystemOnly; + 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 + */ + public SettingsPreferenceServiceClient(@NonNull Context context, + @NonNull String packageName) { + this(context, packageName, true, null); + } + + /** + * @hide Only to be called directly by test + */ + @TestApi + public SettingsPreferenceServiceClient(@NonNull Context context, + @NonNull String packageName, + boolean systemOnly, + @Nullable ServiceConnection connectionListener) { + 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); + } + } + + /** + * Retrieve the metadata for all exposed settings preferences within the application. + * @param request object to specify request parameters + * @param executor {@link Executor} on which to invoke the receiver + * @param receiver callback to receive the result or failure + */ + public void getAllPreferenceMetadata( + @NonNull MetadataRequest request, + @CallbackExecutor @NonNull Executor executor, + @NonNull OutcomeReceiver receiver) { + if (mRemoteService == null) { + executor.execute(() -> + receiver.onError(new IllegalStateException("Service not ready"))); + return; + } + try { + mRemoteService.getAllPreferenceMetadata(request, new IMetadataCallback.Stub() { + @Override + public void onSuccess(MetadataResult result) { + executor.execute(() -> receiver.onResult(result)); + } + + @Override + public void onFailure() { + executor.execute(() -> receiver.onError( + new IllegalStateException("Service call failure"))); + } + }); + } catch (RemoteException | RuntimeException e) { + executor.execute(() -> receiver.onError(e)); + } + } + + /** + * Retrieve the current value of the requested settings preference. + * @param request object to specify request parameters + * @param executor {@link Executor} on which to invoke the receiver + * @param receiver callback to receive the result or failure + */ + public void getPreferenceValue(@NonNull GetValueRequest request, + @CallbackExecutor @NonNull Executor executor, + @NonNull OutcomeReceiver receiver) { + if (mRemoteService == null) { + executor.execute(() -> + receiver.onError(new IllegalStateException("Service not ready"))); + return; + } + try { + mRemoteService.getPreferenceValue(request, new IGetValueCallback.Stub() { + @Override + public void onSuccess(GetValueResult result) { + executor.execute(() -> receiver.onResult(result)); + } + + @Override + public void onFailure() { + executor.execute(() -> receiver.onError( + new IllegalStateException("Service call failure"))); + } + }); + } catch (RemoteException | RuntimeException e) { + executor.execute(() -> receiver.onError(e)); + } + } + + /** + * Set the value on the target settings preference. + * @param request object to specify request parameters + * @param executor {@link Executor} on which to invoke the receiver + * @param receiver callback to receive the result or failure + */ + public void setPreferenceValue(@NonNull SetValueRequest request, + @CallbackExecutor @NonNull Executor executor, + @NonNull OutcomeReceiver receiver) { + if (mRemoteService == null) { + executor.execute(() -> + receiver.onError(new IllegalStateException("Service not ready"))); + return; + } + try { + mRemoteService.setPreferenceValue(request, new ISetValueCallback.Stub() { + @Override + public void onSuccess(SetValueResult result) { + executor.execute(() -> receiver.onResult(result)); + } + + @Override + public void onFailure() { + executor.execute(() -> receiver.onError( + new IllegalStateException("Service call failure"))); + } + }); + } catch (RemoteException | RuntimeException e) { + executor.execute(() -> receiver.onError(e)); + } + } + + @NonNull + private ServiceConnection createServiceConnection(@Nullable ServiceConnection listener) { + return new ServiceConnection() { + @Override + public void onServiceConnected(ComponentName name, IBinder service) { + mRemoteService = getPreferenceServiceInterface(service); + if (listener != null) { + listener.onServiceConnected(name, service); + } + } + + @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); + } + + /** + * 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(); + } +} diff --git a/core/java/android/service/settings/preferences/SettingsPreferenceValue.java b/core/java/android/service/settings/preferences/SettingsPreferenceValue.java new file mode 100644 index 0000000000000000000000000000000000000000..f056e34a0dd2f73d853c2a15d53cc01e100b6d86 --- /dev/null +++ b/core/java/android/service/settings/preferences/SettingsPreferenceValue.java @@ -0,0 +1,220 @@ +/* + * 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.service.settings.preferences; + +import android.annotation.FlaggedApi; +import android.annotation.IntDef; +import android.annotation.SuppressLint; +import android.os.Parcel; +import android.os.Parcelable; + +import androidx.annotation.NonNull; +import androidx.annotation.Nullable; + +import com.android.settingslib.flags.Flags; + +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; + +/** + * This objects represents a value that can be used for a particular settings preference. + *

    The data type for the value will correspond to {@link #getType}. For possible types, see + * constants below, such as {@link #TYPE_BOOLEAN} and {@link #TYPE_STRING}. + * Depending on the type, the corresponding getter will contain its value. All other getters will + * return default values (boolean returns false, String returns null) so they should not be used. + *

    See documentation on the constants for which getter method should be used. + */ +@FlaggedApi(Flags.FLAG_SETTINGS_CATALYST) +public final class SettingsPreferenceValue implements Parcelable { + + @Type + private final int mType; + private final boolean mBooleanValue; + private final long mLongValue; + private final double mDoubleValue; + @Nullable + private final String mStringValue; + + /** + * Returns the type indicator for Preference value. + */ + @Type + public int getType() { + return mType; + } + + /** + * Returns the boolean value for Preference if type is {@link #TYPE_BOOLEAN}. + */ + public boolean getBooleanValue() { + return mBooleanValue; + } + + /** + * Returns the long value for Preference if type is {@link #TYPE_LONG}. + */ + public long getLongValue() { + return mLongValue; + } + + /** + * Returns the double value for Preference if type is {@link #TYPE_DOUBLE}. + */ + public double getDoubleValue() { + return mDoubleValue; + } + + /** + * Returns the string value for Preference if type is {@link #TYPE_STRING}. + */ + @Nullable + public String getStringValue() { + return mStringValue; + } + + /** @hide */ + @IntDef(prefix = { "TYPE_" }, value = { + TYPE_BOOLEAN, + TYPE_LONG, + TYPE_DOUBLE, + TYPE_STRING, + }) + @Retention(RetentionPolicy.SOURCE) + public @interface Type {} + + /** Value is of type boolean. Access via {@link #getBooleanValue}. */ + public static final int TYPE_BOOLEAN = 0; + /** Value is of type long. Access via {@link #getLongValue()}. */ + public static final int TYPE_LONG = 1; + /** Value is of type double. Access via {@link #getDoubleValue()}. */ + public static final int TYPE_DOUBLE = 2; + /** Value is of type string. Access via {@link #getStringValue}. */ + public static final int TYPE_STRING = 3; + + private SettingsPreferenceValue(@NonNull Builder builder) { + mType = builder.mType; + mBooleanValue = builder.mBooleanValue; + mLongValue = builder.mLongValue; + mDoubleValue = builder.mDoubleValue; + mStringValue = builder.mStringValue; + } + + private SettingsPreferenceValue(@NonNull Parcel in) { + mType = in.readInt(); + mBooleanValue = in.readBoolean(); + mLongValue = in.readLong(); + mDoubleValue = in.readDouble(); + mStringValue = in.readString8(); + } + + /** @hide */ + @Override + public void writeToParcel(@NonNull Parcel dest, int flags) { + dest.writeInt(mType); + dest.writeBoolean(mBooleanValue); + dest.writeLong(mLongValue); + dest.writeDouble(mDoubleValue); + dest.writeString8(mStringValue); + } + + /** @hide */ + @Override + public int describeContents() { + return 0; + } + + /** + * Parcelable Creator for {@link SettingsPreferenceValue}. + */ + @NonNull + public static final Creator CREATOR = new Creator<>() { + @Override + public SettingsPreferenceValue createFromParcel(@NonNull Parcel in) { + return new SettingsPreferenceValue(in); + } + + @Override + public SettingsPreferenceValue[] newArray(int size) { + return new SettingsPreferenceValue[size]; + } + }; + + /** + * Builder to construct {@link SettingsPreferenceValue}. + */ + public static final class Builder { + @Type + private final int mType; + private boolean mBooleanValue; + private long mLongValue; + private double mDoubleValue; + private String mStringValue; + + /** + * Create Builder instance. + * @param type type indicator for preference value + */ + public Builder(@Type int type) { + mType = type; + } + + /** + * Sets boolean value for Preference. + */ + @SuppressLint("MissingGetterMatchingBuilder") + @NonNull + public Builder setBooleanValue(boolean booleanValue) { + mBooleanValue = booleanValue; + return this; + } + + /** + * Sets long value for Preference. + */ + @NonNull + public Builder setLongValue(long longValue) { + mLongValue = longValue; + return this; + } + + /** + * Sets floating point value for Preference. + */ + @NonNull + public Builder setDoubleValue(double doubleValue) { + mDoubleValue = doubleValue; + return this; + } + + /** + * Sets string value for Preference. + */ + @NonNull + public Builder setStringValue(@Nullable String stringValue) { + mStringValue = stringValue; + return this; + } + + /** + * Constructs an immutable {@link SettingsPreferenceValue} object. + */ + @NonNull + public SettingsPreferenceValue build() { + return new SettingsPreferenceValue(this); + } + } +} diff --git a/core/java/android/service/voice/AlwaysOnHotwordDetector.java b/core/java/android/service/voice/AlwaysOnHotwordDetector.java index 2e660fc1f1572e0bdbf4e88596f8273a5235717d..7d79fd3d44ea850dfbb9b3e213845287f2baac3b 100644 --- a/core/java/android/service/voice/AlwaysOnHotwordDetector.java +++ b/core/java/android/service/voice/AlwaysOnHotwordDetector.java @@ -1164,7 +1164,7 @@ public class AlwaysOnHotwordDetector extends AbstractDetector { public boolean startRecognition(@RecognitionFlags int recognitionFlags) { if (DBG) Slog.d(TAG, "startRecognition(" + recognitionFlags + ")"); synchronized (mLock) { - return startRecognitionLocked(recognitionFlags, null /* data */) == STATUS_OK; + return startRecognitionLocked(recognitionFlags, /* data= */new byte[0]) == STATUS_OK; } } @@ -1496,8 +1496,8 @@ public class AlwaysOnHotwordDetector extends AbstractDetector { } @GuardedBy("mLock") - private int startRecognitionLocked(int recognitionFlags, - @Nullable byte[] data) { + @SuppressWarnings("FlaggedApi") // RecognitionConfig.Builder is available internally. + private int startRecognitionLocked(int recognitionFlags, @NonNull byte[] data) { if (DBG) { Slog.d(TAG, "startRecognition(" + recognitionFlags diff --git a/core/java/android/service/wallpaper/IWallpaperService.aidl b/core/java/android/service/wallpaper/IWallpaperService.aidl index f76e6cee13f089ba29297c2ea805f8a7bb8054c3..bcdd4775c164219723b9adea6c8c0d133e893664 100644 --- a/core/java/android/service/wallpaper/IWallpaperService.aidl +++ b/core/java/android/service/wallpaper/IWallpaperService.aidl @@ -28,6 +28,6 @@ oneway interface IWallpaperService { void attach(IWallpaperConnection connection, IBinder windowToken, int windowType, boolean isPreview, int reqWidth, int reqHeight, in Rect padding, int displayId, int which, - in WallpaperInfo info, in @nullable WallpaperDescription description); + in WallpaperInfo info, in WallpaperDescription description); void detach(IBinder windowToken); } diff --git a/core/java/android/service/wallpaper/WallpaperService.java b/core/java/android/service/wallpaper/WallpaperService.java index 131fdc895841283cbfc50d3bd05252b6e8aab822..2061abac248e0b8d46e63ec6db6c9ff22d2a1e66 100644 --- a/core/java/android/service/wallpaper/WallpaperService.java +++ b/core/java/android/service/wallpaper/WallpaperService.java @@ -17,6 +17,7 @@ package android.service.wallpaper; import static android.app.Flags.FLAG_LIVE_WALLPAPER_CONTENT_HANDLING; +import static android.app.Flags.liveWallpaperContentHandling; import static android.app.WallpaperManager.COMMAND_FREEZE; import static android.app.WallpaperManager.COMMAND_UNFREEZE; import static android.app.WallpaperManager.SetWallpaperFlags; @@ -2624,7 +2625,7 @@ public abstract class WallpaperService extends Service { private void doAttachEngine() { Trace.beginSection("WPMS.onCreateEngine"); Engine engine; - if (mDescription != null) { + if (liveWallpaperContentHandling()) { engine = onCreateEngine(mDescription); } else { engine = onCreateEngine(); diff --git a/core/java/android/telephony/PhoneStateListener.java b/core/java/android/telephony/PhoneStateListener.java index bce51f297affa6b64470780305179de05be8a06d..1df3b433275488ca2d536f79cf8a70b57d3cacfa 100644 --- a/core/java/android/telephony/PhoneStateListener.java +++ b/core/java/android/telephony/PhoneStateListener.java @@ -37,6 +37,7 @@ import android.telephony.TelephonyManager.EmergencyCallbackModeType; import android.telephony.emergency.EmergencyNumber; import android.telephony.ims.ImsReasonInfo; import android.telephony.ims.MediaQualityStatus; +import android.telephony.satellite.NtnSignalStrength; import com.android.internal.annotations.VisibleForTesting; import com.android.internal.telephony.IPhoneStateListener; @@ -1706,6 +1707,11 @@ public class PhoneStateListener { @NetworkRegistrationInfo.ServiceType int[] availableServices) { // not supported on the deprecated interface - Use TelephonyCallback instead } + + public final void onCarrierRoamingNtnSignalStrengthChanged( + @NonNull NtnSignalStrength ntnSignalStrength) { + // not supported on the deprecated interface - Use TelephonyCallback instead + } } private void log(String s) { diff --git a/core/java/android/telephony/TelephonyCallback.java b/core/java/android/telephony/TelephonyCallback.java index 64a5533cbe69b5adfaf406471250e1405ee21085..0d1dc4611343a409a9b48dcda221514c10ba14cf 100644 --- a/core/java/android/telephony/TelephonyCallback.java +++ b/core/java/android/telephony/TelephonyCallback.java @@ -30,6 +30,7 @@ import android.telephony.emergency.EmergencyNumber; import android.telephony.ims.ImsReasonInfo; import android.telephony.ims.MediaQualityStatus; import android.telephony.ims.MediaThreshold; +import android.telephony.satellite.NtnSignalStrength; import android.util.Log; import com.android.internal.annotations.VisibleForTesting; @@ -694,6 +695,15 @@ public class TelephonyCallback { */ public static final int EVENT_CARRIER_ROAMING_NTN_AVAILABLE_SERVICES_CHANGED = 44; + /** + * Event for listening to carrier roaming non-terrestrial network signal strength changes. + * + * @see CarrierRoamingNtnModeListener + * + * @hide + */ + public static final int EVENT_CARRIER_ROAMING_NTN_SIGNAL_STRENGTH_CHANGED = 45; + /** * @hide */ @@ -741,7 +751,8 @@ public class TelephonyCallback { EVENT_SIMULTANEOUS_CELLULAR_CALLING_SUBSCRIPTIONS_CHANGED, EVENT_CARRIER_ROAMING_NTN_MODE_CHANGED, EVENT_CARRIER_ROAMING_NTN_ELIGIBLE_STATE_CHANGED, - EVENT_CARRIER_ROAMING_NTN_AVAILABLE_SERVICES_CHANGED + EVENT_CARRIER_ROAMING_NTN_AVAILABLE_SERVICES_CHANGED, + EVENT_CARRIER_ROAMING_NTN_SIGNAL_STRENGTH_CHANGED }) @Retention(RetentionPolicy.SOURCE) public @interface TelephonyEvent { @@ -1805,6 +1816,14 @@ public class TelephonyCallback { */ default void onCarrierRoamingNtnAvailableServicesChanged( @NetworkRegistrationInfo.ServiceType List availableServices) {} + + /** + * Callback invoked when carrier roaming non-terrestrial network signal strength changes. + * + * @param ntnSignalStrength non-terrestrial network signal strength. + */ + default void onCarrierRoamingNtnSignalStrengthChanged( + @NonNull NtnSignalStrength ntnSignalStrength) {} } /** @@ -2270,5 +2289,18 @@ public class TelephonyCallback { Binder.withCleanCallingIdentity(() -> mExecutor.execute( () -> listener.onCarrierRoamingNtnAvailableServicesChanged(ServiceList))); } + + public void onCarrierRoamingNtnSignalStrengthChanged( + @NonNull NtnSignalStrength ntnSignalStrength) { + if (!Flags.carrierRoamingNbIotNtn()) return; + + CarrierRoamingNtnModeListener listener = + (CarrierRoamingNtnModeListener) mTelephonyCallbackWeakRef.get(); + if (listener == null) return; + + Binder.withCleanCallingIdentity(() -> mExecutor.execute( + () -> listener.onCarrierRoamingNtnSignalStrengthChanged(ntnSignalStrength))); + + } } } diff --git a/core/java/android/telephony/TelephonyRegistryManager.java b/core/java/android/telephony/TelephonyRegistryManager.java index 1dab2cf755949f68f872023dacaa41a9a876d2fc..90b0bb34c145e37b95ee3d4c6a659c5fac5eb4a9 100644 --- a/core/java/android/telephony/TelephonyRegistryManager.java +++ b/core/java/android/telephony/TelephonyRegistryManager.java @@ -47,6 +47,7 @@ import android.telephony.emergency.EmergencyNumber; import android.telephony.ims.ImsCallSession; import android.telephony.ims.ImsReasonInfo; import android.telephony.ims.MediaQualityStatus; +import android.telephony.satellite.NtnSignalStrength; import android.telephony.satellite.SatelliteStateChangeListener; import android.util.ArrayMap; import android.util.ArraySet; @@ -1136,6 +1137,23 @@ public class TelephonyRegistryManager { } } + /** + * Notify external listeners that carrier roaming non-terrestrial network + * signal strength changed. + * @param subId subscription ID. + * @param ntnSignalStrength non-terrestrial network signal strength. + * @hide + */ + public final void notifyCarrierRoamingNtnSignalStrengthChanged(int subId, + @NonNull NtnSignalStrength ntnSignalStrength) { + try { + sRegistry.notifyCarrierRoamingNtnSignalStrengthChanged(subId, ntnSignalStrength); + } catch (RemoteException ex) { + // system server crash + throw ex.rethrowFromSystemServer(); + } + } + /** * Processes potential event changes from the provided {@link TelephonyCallback}. * @@ -1293,6 +1311,7 @@ public class TelephonyRegistryManager { eventList.add(TelephonyCallback.EVENT_CARRIER_ROAMING_NTN_MODE_CHANGED); eventList.add(TelephonyCallback.EVENT_CARRIER_ROAMING_NTN_ELIGIBLE_STATE_CHANGED); eventList.add(TelephonyCallback.EVENT_CARRIER_ROAMING_NTN_AVAILABLE_SERVICES_CHANGED); + eventList.add(TelephonyCallback.EVENT_CARRIER_ROAMING_NTN_SIGNAL_STRENGTH_CHANGED); } return eventList; } diff --git a/core/java/android/text/flags/flags.aconfig b/core/java/android/text/flags/flags.aconfig index e830d89d31165c9d7088de2fc22c55e0e7b181d8..02923eda308ef5d3a90ab56e3f2f28c8a331becc 100644 --- a/core/java/android/text/flags/flags.aconfig +++ b/core/java/android/text/flags/flags.aconfig @@ -202,3 +202,10 @@ flag { description: "Deprecate the Paint#elegantTextHeight API and stick it to true" bug: "349519475" } + +flag { + name: "vertical_text_layout" + namespace: "text" + description: "Make Paint class work for vertical layout text." + bug: "355296926" +} diff --git a/core/java/android/util/Log.java b/core/java/android/util/Log.java index 8358b9a51adb0fba061f28d0bb272d95a0c3d45f..1dd9d46fdfb7c0e04ea41d8e483f4db30d73b743 100644 --- a/core/java/android/util/Log.java +++ b/core/java/android/util/Log.java @@ -75,8 +75,7 @@ import java.net.UnknownHostException; @android.ravenwood.annotation.RavenwoodClassLoadHook( "com.android.platform.test.ravenwood.runtimehelper.ClassLoadHook.onClassLoaded") // Uncomment the following annotation to switch to the Java substitution version. -//@android.ravenwood.annotation.RavenwoodNativeSubstitutionClass( -// "com.android.platform.test.ravenwood.nativesubstitution.Log_host") +@android.ravenwood.annotation.RavenwoodRedirectionClass("Log_host") public final class Log { /** @hide */ @IntDef({ASSERT, ERROR, WARN, INFO, DEBUG, VERBOSE}) @@ -250,6 +249,7 @@ public final class Log { * tag limit of concern after this API level. */ @FastNative + @android.ravenwood.annotation.RavenwoodRedirect public static native boolean isLoggable(@Nullable String tag, @Level int level); /** @@ -425,6 +425,7 @@ public final class Log { * @hide */ @UnsupportedAppUsage + @android.ravenwood.annotation.RavenwoodRedirect public static native int println_native(int bufID, int priority, String tag, String msg); /** @@ -452,6 +453,7 @@ public final class Log { * Return the maximum payload the log daemon accepts without truncation. * @return LOGGER_ENTRY_MAX_PAYLOAD. */ + @android.ravenwood.annotation.RavenwoodRedirect private static native int logger_entry_max_payload_native(); /** diff --git a/core/java/android/view/Display.java b/core/java/android/view/Display.java index 910e644f7b6fd1c76e4a6741d8baea9b1d9faea4..0241e943795077e5b9f0d914b7567e8e54096aa5 100644 --- a/core/java/android/view/Display.java +++ b/core/java/android/view/Display.java @@ -1549,8 +1549,9 @@ public final class Display { // Although we only care about the HDR/SDR ratio changing, that can also come in the // form of the larger DISPLAY_CHANGED event mGlobal.registerDisplayListener(toRegister, executor, - DisplayManager.EVENT_FLAG_HDR_SDR_RATIO_CHANGED - | DisplayManagerGlobal.EVENT_DISPLAY_CHANGED, + DisplayManagerGlobal.INTERNAL_EVENT_FLAG_DISPLAY_CHANGED + | DisplayManagerGlobal + .INTERNAL_EVENT_FLAG_DISPLAY_HDR_SDR_RATIO_CHANGED, ActivityThread.currentPackageName()); } diff --git a/core/java/android/view/DisplayInfo.java b/core/java/android/view/DisplayInfo.java index 8f112f338a004c8dfe43e67b6f8735852c7c872d..4ff04d5c1fa6c3bf88bb6ddcefdf4024a780c39e 100644 --- a/core/java/android/view/DisplayInfo.java +++ b/core/java/android/view/DisplayInfo.java @@ -447,7 +447,6 @@ public final class DisplayInfo implements Parcelable { && Objects.equals(displayCutout, other.displayCutout) && rotation == other.rotation && modeId == other.modeId - && renderFrameRate == other.renderFrameRate && hasArrSupport == other.hasArrSupport && Objects.equals(frameRateCategoryRate, other.frameRateCategoryRate) && defaultModeId == other.defaultModeId @@ -705,6 +704,9 @@ public final class DisplayInfo implements Parcelable { if (refreshRateOverride > 0) { return refreshRateOverride; } + if (renderFrameRate > 0) { + return renderFrameRate; + } if (supportedModes.length == 0) { return 0; } diff --git a/core/java/android/view/HapticFeedbackConstants.java b/core/java/android/view/HapticFeedbackConstants.java index 1fe06d47480369bb927f993de46f90de720f5f48..66d64d711e58fe2058a840b2b862420487a2b566 100644 --- a/core/java/android/view/HapticFeedbackConstants.java +++ b/core/java/android/view/HapticFeedbackConstants.java @@ -176,7 +176,7 @@ public class HapticFeedbackConstants { /** * The user is executing a swipe/drag-style gesture, such as pull-to-refresh, where the - * gesture action is “eligible” at a certain threshold of movement, and can be cancelled by + * gesture action is "eligible" at a certain threshold of movement, and can be cancelled by * moving back past the threshold. This constant indicates that the user's motion has just * passed the threshold for the action to be activated on release. * @@ -186,7 +186,7 @@ public class HapticFeedbackConstants { /** * The user is executing a swipe/drag-style gesture, such as pull-to-refresh, where the - * gesture action is “eligible” at a certain threshold of movement, and can be cancelled by + * gesture action is "eligible" at a certain threshold of movement, and can be cancelled by * moving back past the threshold. This constant indicates that the user's motion has just * re-crossed back "under" the threshold for the action to be activated, meaning the gesture is * currently in a cancelled state. diff --git a/core/java/android/view/ImeBackAnimationController.java b/core/java/android/view/ImeBackAnimationController.java index b80146505a1bd2364a70e19a10b02f0e55dd0bf6..19e0913fbc659e0edbf40f5d045160274f77b102 100644 --- a/core/java/android/view/ImeBackAnimationController.java +++ b/core/java/android/view/ImeBackAnimationController.java @@ -33,6 +33,7 @@ import android.util.Log; import android.view.animation.BackGestureInterpolator; import android.view.animation.Interpolator; import android.view.animation.PathInterpolator; +import android.view.inputmethod.Flags; import android.view.inputmethod.ImeTracker; import android.window.BackEvent; import android.window.OnBackAnimationCallback; @@ -142,9 +143,15 @@ public class ImeBackAnimationController implements OnBackAnimationCallback { // control has been cancelled by the system. This can happen in multi-window mode for // example (i.e. split-screen or activity-embedding) notifyHideIme(); - return; + } else { + startPostCommitAnim(/*hideIme*/ true); + } + if (Flags.refactorInsetsController()) { + // Unregister all IME back callbacks so that back events are sent to the next callback + // even while the hide animation is playing + mInsetsController.getHost().getInputMethodManager().getImeOnBackInvokedDispatcher() + .preliminaryClear(); } - startPostCommitAnim(/*hideIme*/ true); } private void setPreCommitProgress(float progress) { diff --git a/core/java/android/view/InsetsController.java b/core/java/android/view/InsetsController.java index 25d2246424dee3a91904579d3e0d467eecfc033d..26ca813a9caac53540c8edeb2744afa51f7cc828 100644 --- a/core/java/android/view/InsetsController.java +++ b/core/java/android/view/InsetsController.java @@ -1344,6 +1344,11 @@ public class InsetsController implements WindowInsetsController, InsetsAnimation boolean fromPredictiveBack) { final boolean visible = layoutInsetsDuringAnimation == LAYOUT_INSETS_DURING_ANIMATION_SHOWN; + if (Flags.refactorInsetsController() && !fromPredictiveBack && !visible + && (types & ime()) != 0 && (mRequestedVisibleTypes & ime()) != 0) { + // Clear IME back callbacks if a IME hide animation is requested + mHost.getInputMethodManager().getImeOnBackInvokedDispatcher().preliminaryClear(); + } // Basically, we accept the requested visibilities from the upstream callers... setRequestedVisibleTypes(visible ? types : 0, types); @@ -1921,6 +1926,14 @@ public class InsetsController implements WindowInsetsController, InsetsAnimation final @InsetsType int requestedVisibleTypes = (mRequestedVisibleTypes & ~mask) | (visibleTypes & mask); if (mRequestedVisibleTypes != requestedVisibleTypes) { + if (Flags.refactorInsetsController() && (mRequestedVisibleTypes & ime()) == 0 + && (requestedVisibleTypes & ime()) != 0) { + // In case the IME back callbacks have been preliminarily cleared before, let's + // reregister them. This can happen if an IME hide animation was interrupted and the + // IME is requested to be shown again. + getHost().getInputMethodManager().getImeOnBackInvokedDispatcher() + .undoPreliminaryClear(); + } ProtoLog.d(IME_INSETS_CONTROLLER, "Setting requestedVisibleTypes to %d (was %d)", requestedVisibleTypes, mRequestedVisibleTypes); mRequestedVisibleTypes = requestedVisibleTypes; diff --git a/core/java/android/view/InsetsSourceControl.java b/core/java/android/view/InsetsSourceControl.java index 78773529294aa0118213fc62980178d715cd486e..acbd95bf6810c77f261f239e6a0d9151456b61ec 100644 --- a/core/java/android/view/InsetsSourceControl.java +++ b/core/java/android/view/InsetsSourceControl.java @@ -212,8 +212,7 @@ public class InsetsSourceControl implements Parcelable { && mInitiallyVisible == that.mInitiallyVisible && mSurfacePosition.equals(that.mSurfacePosition) && mInsetsHint.equals(that.mInsetsHint) - && mSkipAnimationOnce == that.mSkipAnimationOnce - && Objects.equals(mImeStatsToken, that.mImeStatsToken); + && mSkipAnimationOnce == that.mSkipAnimationOnce; } @Override diff --git a/core/java/android/view/KeyEvent.java b/core/java/android/view/KeyEvent.java index dddc408ed9db2afbf32cbe70be86e74547e2a57d..38e4e2760d2524fedaefa04b637180c0509fce15 100644 --- a/core/java/android/view/KeyEvent.java +++ b/core/java/android/view/KeyEvent.java @@ -935,7 +935,6 @@ public class KeyEvent extends InputEvent implements Parcelable { */ public static final int KEYCODE_MACRO_4 = 316; /** Key code constant: To open emoji picker */ - @FlaggedApi(Flags.FLAG_EMOJI_AND_SCREENSHOT_KEYCODES_AVAILABLE) public static final int KEYCODE_EMOJI_PICKER = 317; /** * Key code constant: To take a screenshot @@ -944,15 +943,80 @@ public class KeyEvent extends InputEvent implements Parcelable { * unlike {@code KEYCODE_SYSRQ} which is sent to the app first and only if the app * doesn't handle it, the framework handles it (to take a screenshot). */ - @FlaggedApi(Flags.FLAG_EMOJI_AND_SCREENSHOT_KEYCODES_AVAILABLE) public static final int KEYCODE_SCREENSHOT = 318; + /** Key code constant: To start dictate to an input field */ + @FlaggedApi(Flags.FLAG_ENABLE_NEW_25Q2_KEYCODES) + public static final int KEYCODE_DICTATE = 319; + /** + * Key code constant: AC New + * + * e.g. To create a new instance of a window, open a new tab, etc. + */ + @FlaggedApi(Flags.FLAG_ENABLE_NEW_25Q2_KEYCODES) + public static final int KEYCODE_NEW = 320; + /** + * Key code constant: AC Close + * + * e.g. To close current instance of the application window, close the current tab, etc. + */ + @FlaggedApi(Flags.FLAG_ENABLE_NEW_25Q2_KEYCODES) + public static final int KEYCODE_CLOSE = 321; + /** Key code constant: To toggle 'Do Not Disturb' mode */ + @FlaggedApi(Flags.FLAG_ENABLE_NEW_25Q2_KEYCODES) + public static final int KEYCODE_DO_NOT_DISTURB = 322; + /** Key code constant: To Print */ + @FlaggedApi(Flags.FLAG_ENABLE_NEW_25Q2_KEYCODES) + public static final int KEYCODE_PRINT = 323; + /** Key code constant: To Lock the screen */ + @FlaggedApi(Flags.FLAG_ENABLE_NEW_25Q2_KEYCODES) + public static final int KEYCODE_LOCK = 324; + /** Key code constant: To toggle fullscreen mode (on the current application) */ + @FlaggedApi(Flags.FLAG_ENABLE_NEW_25Q2_KEYCODES) + public static final int KEYCODE_FULLSCREEN = 325; + /** Key code constant: F13 key. */ + @FlaggedApi(Flags.FLAG_ENABLE_NEW_25Q2_KEYCODES) + public static final int KEYCODE_F13 = 326; + /** Key code constant: F14 key. */ + @FlaggedApi(Flags.FLAG_ENABLE_NEW_25Q2_KEYCODES) + public static final int KEYCODE_F14 = 327; + /** Key code constant: F15 key. */ + @FlaggedApi(Flags.FLAG_ENABLE_NEW_25Q2_KEYCODES) + public static final int KEYCODE_F15 = 328; + /** Key code constant: F16 key. */ + @FlaggedApi(Flags.FLAG_ENABLE_NEW_25Q2_KEYCODES) + public static final int KEYCODE_F16 = 329; + /** Key code constant: F17 key. */ + @FlaggedApi(Flags.FLAG_ENABLE_NEW_25Q2_KEYCODES) + public static final int KEYCODE_F17 = 330; + /** Key code constant: F18 key. */ + @FlaggedApi(Flags.FLAG_ENABLE_NEW_25Q2_KEYCODES) + public static final int KEYCODE_F18 = 331; + /** Key code constant: F19 key. */ + @FlaggedApi(Flags.FLAG_ENABLE_NEW_25Q2_KEYCODES) + public static final int KEYCODE_F19 = 332; + /** Key code constant: F20 key. */ + @FlaggedApi(Flags.FLAG_ENABLE_NEW_25Q2_KEYCODES) + public static final int KEYCODE_F20 = 333; + /** Key code constant: F21 key. */ + @FlaggedApi(Flags.FLAG_ENABLE_NEW_25Q2_KEYCODES) + public static final int KEYCODE_F21 = 334; + /** Key code constant: F22 key. */ + @FlaggedApi(Flags.FLAG_ENABLE_NEW_25Q2_KEYCODES) + public static final int KEYCODE_F22 = 335; + /** Key code constant: F23 key. */ + @FlaggedApi(Flags.FLAG_ENABLE_NEW_25Q2_KEYCODES) + public static final int KEYCODE_F23 = 336; + /** Key code constant: F24 key. */ + @FlaggedApi(Flags.FLAG_ENABLE_NEW_25Q2_KEYCODES) + public static final int KEYCODE_F24 = 337; /** * Integer value of the last KEYCODE. Increases as new keycodes are added to KeyEvent. * @hide */ @TestApi - public static final int LAST_KEYCODE = KEYCODE_SCREENSHOT; + @SuppressWarnings("FlaggedApi") + public static final int LAST_KEYCODE = KEYCODE_F24; /** @hide */ @IntDef(prefix = {"KEYCODE_"}, value = { @@ -1275,6 +1339,25 @@ public class KeyEvent extends InputEvent implements Parcelable { KEYCODE_MACRO_4, KEYCODE_EMOJI_PICKER, KEYCODE_SCREENSHOT, + KEYCODE_DICTATE, + KEYCODE_NEW, + KEYCODE_CLOSE, + KEYCODE_DO_NOT_DISTURB, + KEYCODE_PRINT, + KEYCODE_LOCK, + KEYCODE_FULLSCREEN, + KEYCODE_F13, + KEYCODE_F14, + KEYCODE_F15, + KEYCODE_F16, + KEYCODE_F17, + KEYCODE_F18, + KEYCODE_F19, + KEYCODE_F20, + KEYCODE_F21, + KEYCODE_F22, + KEYCODE_F23, + KEYCODE_F24, }) @Retention(RetentionPolicy.SOURCE) @interface KeyCode {} diff --git a/core/java/android/view/RoundScrollbarRenderer.java b/core/java/android/view/RoundScrollbarRenderer.java index 59c2598f00f031a58ba4b2fb40bde1663858abc6..5e1eadae09530f539833dad686691c54959ff05c 100644 --- a/core/java/android/view/RoundScrollbarRenderer.java +++ b/core/java/android/view/RoundScrollbarRenderer.java @@ -35,7 +35,9 @@ import android.view.flags.Flags; * @hide */ public class RoundScrollbarRenderer { - private static final String BLUECHIP_ENABLED_SYSPROP = "persist.cw_build.bluechip.enabled"; + /** @hide */ + public static final String BLUECHIP_ENABLED_SYSPROP = "persist.cw_build.bluechip.enabled"; + // The range of the scrollbar position represented as an angle in degrees. private static final float SCROLLBAR_ANGLE_RANGE = 28.8f; private static final float MAX_SCROLLBAR_ANGLE_SWIPE = 26.3f; // 90% diff --git a/core/java/android/view/SurfaceControl.java b/core/java/android/view/SurfaceControl.java index b8b22e283175abaff42c727d3620f48377bd53a7..206c7375608814709b273947665bdc5f8f1dfab1 100644 --- a/core/java/android/view/SurfaceControl.java +++ b/core/java/android/view/SurfaceControl.java @@ -312,6 +312,7 @@ public final class SurfaceControl implements Parcelable { private static native void nativeNotifyShutdown(); 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); /** * Transforms that can be applied to buffers as they are displayed to a window. @@ -2988,7 +2989,6 @@ public final class SurfaceControl implements Parcelable { private void apply(boolean sync, boolean oneWay) { applyResizedSurfaces(); notifyReparentedSurfaces(); - nativeApplyTransaction(mNativeObject, sync, oneWay); if (SurfaceControlRegistry.sCallStackDebuggingEnabled) { SurfaceControlRegistry.getProcessInstance().checkCallStackDebugging( @@ -2997,6 +2997,7 @@ public final class SurfaceControl implements Parcelable { if (mCalls != null) { mCalls.clear(); } + nativeApplyTransaction(mNativeObject, sync, oneWay); } /** @@ -4605,7 +4606,6 @@ public final class SurfaceControl implements Parcelable { } /** - * TODO(b/366484871): To be removed once we have some logging in native * This is called when BlastBufferQueue.mergeWithNextTransaction() is called from java, and * for the purposes of logging that path. */ @@ -4616,6 +4616,7 @@ public final class SurfaceControl implements Parcelable { if (mCalls != null) { mCalls.clear(); } + nativeEnableDebugLogCallPoints(mNativeObject); } } diff --git a/core/java/android/view/View.java b/core/java/android/view/View.java index e49eec69fff56fcfad17483a4b66279f09dda1ec..fa06831f65141854f45678b0cd76b11ebdd870e7 100644 --- a/core/java/android/view/View.java +++ b/core/java/android/view/View.java @@ -30,9 +30,11 @@ import static android.view.Surface.FRAME_RATE_COMPATIBILITY_FIXED_SOURCE; import static android.view.Surface.FRAME_RATE_COMPATIBILITY_GTE; import static android.view.WindowManager.LayoutParams.TYPE_INPUT_METHOD; import static android.view.accessibility.AccessibilityEvent.CONTENT_CHANGE_TYPE_UNDEFINED; +import static android.view.accessibility.Flags.FLAG_DEPRECATE_ACCESSIBILITY_ANNOUNCEMENT_APIS; import static android.view.accessibility.Flags.FLAG_SUPPLEMENTAL_DESCRIPTION; import static android.view.accessibility.Flags.removeChildHoverCheckForTouchExploration; import static android.view.accessibility.Flags.supplementalDescription; +import static android.view.accessibility.Flags.supportMultipleLabeledby; import static android.view.displayhash.DisplayHashResultCallback.DISPLAY_HASH_ERROR_INVALID_BOUNDS; import static android.view.displayhash.DisplayHashResultCallback.DISPLAY_HASH_ERROR_MISSING_WINDOW; import static android.view.displayhash.DisplayHashResultCallback.DISPLAY_HASH_ERROR_NOT_VISIBLE_ON_SCREEN; @@ -42,6 +44,7 @@ import static android.view.displayhash.DisplayHashResultCallback.EXTRA_DISPLAY_H import static android.view.flags.Flags.FLAG_SENSITIVE_CONTENT_APP_PROTECTION_API; import static android.view.flags.Flags.FLAG_TOOLKIT_SET_FRAME_RATE_READ_ONLY; import static android.view.flags.Flags.FLAG_VIEW_VELOCITY_API; +import static android.view.flags.Flags.calculateBoundsInParentFromBoundsInScreen; import static android.view.flags.Flags.enableUseMeasureCacheDuringForceLayout; import static android.view.flags.Flags.sensitiveContentAppProtection; import static android.view.flags.Flags.toolkitFrameRateAnimationBugfix25q1; @@ -969,6 +972,13 @@ public class View implements Drawable.Callback, KeyEvent.Callback, */ private static boolean sAlwaysRemeasureExactly = false; + /** + * When true calculates the bounds in parent from bounds in screen relative to its parents. + * This addresses the deprecated API (setBoundsInParent) in Compose, which causes empty + * getBoundsInParent call for Compose apps. + */ + private static boolean sCalculateBoundsInParentFromBoundsInScreenFlagValue = false; + /** * When true makes it possible to use onMeasure caches also when the force layout flag is * enabled. This helps avoiding multiple measures in the same frame with the same dimensions. @@ -2561,6 +2571,8 @@ public class View implements Drawable.Callback, KeyEvent.Callback, sToolkitSetFrameRateReadOnlyFlagValue = toolkitSetFrameRateReadOnly(); sToolkitMetricsForFrameRateDecisionFlagValue = toolkitMetricsForFrameRateDecision(); + sCalculateBoundsInParentFromBoundsInScreenFlagValue = + calculateBoundsInParentFromBoundsInScreen(); sUseMeasureCacheDuringForceLayoutFlagValue = enableUseMeasureCacheDuringForceLayout(); } @@ -8941,44 +8953,45 @@ public class View implements Drawable.Callback, KeyEvent.Callback, } /** - * Convenience method for sending a {@link AccessibilityEvent#TYPE_ANNOUNCEMENT} - * {@link AccessibilityEvent} to suggest that an accessibility service announce the - * specified text to its users. - *

    - * Note: The event generated with this API carries no semantic meaning, and is appropriate only - * in exceptional situations. Apps can generally achieve correct behavior for accessibility by - * accurately supplying the semantics of their UI. - * They should not need to specify what exactly is announced to users. + * Convenience method for sending a {@link AccessibilityEvent#TYPE_ANNOUNCEMENT} {@link + * AccessibilityEvent} to suggest that an accessibility service announce the specified text to + * its users. * - *

    - * In general, only announce transitions and don't generate a confirmation message for simple - * actions like a button press. Label your controls concisely and precisely instead, and for - * significant UI changes like window changes, use - * {@link android.app.Activity#setTitle(CharSequence)} and - * {@link #setAccessibilityPaneTitle(CharSequence)}. + *

    Note: The event generated with this API carries no semantic meaning, and accessibility + * services may choose to ignore it. Apps that accurately supply accessibility with the + * semantics of their UI should not need to specify what exactly is announced. * - *

    - * Use {@link #setAccessibilityLiveRegion(int)} to inform the user of changes to critical + *

    In general, do not attempt to generate announcements as confirmation message for simple + * actions like a button press. Label your controls concisely and precisely instead. + * + *

    To convey significant UI changes like window changes, use {@link + * android.app.Activity#setTitle(CharSequence)} and {@link + * #setAccessibilityPaneTitle(CharSequence)}. + * + *

    Use {@link #setAccessibilityLiveRegion(int)} to inform the user of changes to critical * views within the user interface. These should still be used sparingly as they may generate * announcements every time a View is updated. * - *

    - * For notifying users about errors, such as in a login screen with text that displays an - * "incorrect password" notification, that view should send an AccessibilityEvent of type - * {@link AccessibilityEvent#CONTENT_CHANGE_TYPE_ERROR} and set - * {@link AccessibilityNodeInfo#setError(CharSequence)} instead. Custom widgets should expose - * error-setting methods that support accessibility automatically. For example, instead of - * explicitly sending this event when using a TextView, use - * {@link android.widget.TextView#setError(CharSequence)}. - * - *

    - * Use {@link #setStateDescription(CharSequence)} to convey state changes to views within the + *

    Use {@link #setStateDescription(CharSequence)} to convey state changes to views within the * user interface. While a live region may send different types of events generated by the view, * state description will send {@link AccessibilityEvent#TYPE_WINDOW_CONTENT_CHANGED} events of * type {@link AccessibilityEvent#CONTENT_CHANGE_TYPE_STATE_DESCRIPTION}. * + *

    For notifying users about errors, such as in a login screen with text that displays an + * "incorrect password" notification, set {@link AccessibilityNodeInfo#setError(CharSequence)} + * and dispatch an {@link AccessibilityEvent#TYPE_WINDOW_CONTENT_CHANGED} event with a change + * type of {@link AccessibilityEvent#CONTENT_CHANGE_TYPE_ERROR}, instead. Some widgets may + * expose methods that convey error states to accessibility automatically, such as {@link + * android.widget.TextView#setError(CharSequence)}, which manages these accessibility semantics + * and event dispatch for callers. + * + * @deprecated Use one of the methods described in the documentation above to semantically + * describe UI instead of using an announcement, as accessibility services may choose to + * ignore events dispatched with this method. * @param text The announcement text. */ + @FlaggedApi(FLAG_DEPRECATE_ACCESSIBILITY_ANNOUNCEMENT_APIS) + @Deprecated public void announceForAccessibility(CharSequence text) { if (AccessibilityManager.getInstance(mContext).isEnabled() && mParent != null) { AccessibilityEvent event = AccessibilityEvent.obtain( @@ -9806,7 +9819,7 @@ public class View implements Drawable.Callback, KeyEvent.Callback, structure.setChildCount(1); final ViewStructure root = structure.newChild(0); if (info != null) { - populateVirtualStructure(root, provider, info, forAutofill); + populateVirtualStructure(root, provider, info, null, forAutofill); info.recycle(); } else { Log.w(AUTOFILL_LOG_TAG, "AccessibilityNodeInfo is null."); @@ -11105,11 +11118,19 @@ public class View implements Drawable.Callback, KeyEvent.Callback, private void populateVirtualStructure(ViewStructure structure, AccessibilityNodeProvider provider, AccessibilityNodeInfo info, - boolean forAutofill) { + @Nullable AccessibilityNodeInfo parentInfo, boolean forAutofill) { structure.setId(AccessibilityNodeInfo.getVirtualDescendantId(info.getSourceNodeId()), null, null, info.getViewIdResourceName()); Rect rect = structure.getTempRect(); - info.getBoundsInParent(rect); + // The bounds in parent for Jetpack Compose views aren't set as setBoundsInParent is + // deprecated, and only setBoundsInScreen is called. + // The bounds in parent can be calculated by diff'ing the child view's bounds in screen with + // the parent's. + if (sCalculateBoundsInParentFromBoundsInScreenFlagValue) { + getBoundsInParent(info, parentInfo, rect); + } else { + info.getBoundsInParent(rect); + } structure.setDimens(rect.left, rect.top, 0, 0, rect.width(), rect.height()); structure.setVisibility(VISIBLE); structure.setEnabled(info.isEnabled()); @@ -11193,13 +11214,32 @@ public class View implements Drawable.Callback, KeyEvent.Callback, AccessibilityNodeInfo.getVirtualDescendantId(info.getChildId(i))); if (cinfo != null) { ViewStructure child = structure.newChild(i); - populateVirtualStructure(child, provider, cinfo, forAutofill); + populateVirtualStructure(child, provider, cinfo, info, forAutofill); cinfo.recycle(); } } } } + private void getBoundsInParent(@NonNull AccessibilityNodeInfo info, + @Nullable AccessibilityNodeInfo parentInfo, @NonNull Rect rect) { + info.getBoundsInParent(rect); + // Fallback to calculate bounds in parent by diffing the bounds in + // screen if it's all 0. + if ((rect.left | rect.top | rect.right | rect.bottom) == 0) { + if (parentInfo != null) { + Rect parentBoundsInScreen = parentInfo.getBoundsInScreen(); + Rect boundsInScreen = info.getBoundsInScreen(); + rect.set(boundsInScreen.left - parentBoundsInScreen.left, + boundsInScreen.top - parentBoundsInScreen.top, + boundsInScreen.right - parentBoundsInScreen.left, + boundsInScreen.bottom - parentBoundsInScreen.top); + } else { + info.getBoundsInScreen(rect); + } + } + } + /** * Dispatch creation of {@link ViewStructure} down the hierarchy. The default * implementation calls {@link #onProvideStructure} and @@ -11363,7 +11403,11 @@ public class View implements Drawable.Callback, KeyEvent.Callback, View label = rootView.findLabelForView(this, mID); if (label != null) { - info.setLabeledBy(label); + if (supportMultipleLabeledby()) { + info.addLabeledBy(label); + } else { + info.setLabeledBy(label); + } } if ((mAttachInfo.mAccessibilityFetchFlags @@ -23838,12 +23882,12 @@ public class View implements Drawable.Callback, KeyEvent.Callback, } else { draw(canvas); } - } - // For VRR to vote the preferred frame rate - if (sToolkitSetFrameRateReadOnlyFlagValue - && sToolkitFrameRateViewEnablingReadOnlyFlagValue) { - votePreferredFrameRate(); + // For VRR to vote the preferred frame rate + if (sToolkitSetFrameRateReadOnlyFlagValue + && sToolkitFrameRateViewEnablingReadOnlyFlagValue) { + votePreferredFrameRate(); + } } } finally { renderNode.endRecording(); diff --git a/core/java/android/view/ViewRootImpl.java b/core/java/android/view/ViewRootImpl.java index 3ce6870bf2cab51fc4e6f485c1217a1b8cc62238..75d2da1b70e4cf963e8411d729a9f12964b3c80d 100644 --- a/core/java/android/view/ViewRootImpl.java +++ b/core/java/android/view/ViewRootImpl.java @@ -185,7 +185,6 @@ import android.graphics.RenderNode; import android.graphics.drawable.Drawable; import android.graphics.drawable.GradientDrawable; import android.hardware.SyncFence; -import android.hardware.display.DisplayManager; import android.hardware.display.DisplayManager.DisplayListener; import android.hardware.display.DisplayManagerGlobal; import android.hardware.input.InputManagerGlobal; @@ -1816,9 +1815,9 @@ public final class ViewRootImpl implements ViewParent, .registerDisplayListener( mDisplayListener, mHandler, - DisplayManager.EVENT_FLAG_DISPLAY_ADDED - | DisplayManager.EVENT_FLAG_DISPLAY_CHANGED - | DisplayManager.EVENT_FLAG_DISPLAY_REMOVED, + DisplayManagerGlobal.INTERNAL_EVENT_FLAG_DISPLAY_ADDED + | DisplayManagerGlobal.INTERNAL_EVENT_FLAG_DISPLAY_CHANGED + | DisplayManagerGlobal.INTERNAL_EVENT_FLAG_DISPLAY_REMOVED, mBasePackageName); if (forceInvertColor()) { @@ -9952,11 +9951,13 @@ public final class ViewRootImpl implements ViewParent, return false; } - if (!mIsDrawing) { - destroyHardwareRenderer(); - } else { - Log.e(mTag, "Attempting to destroy the window while drawing!\n" + - " window=" + this + ", title=" + mWindowAttributes.getTitle()); + if (!com.android.graphics.hwui.flags.Flags.removeVriSketchyDestroy()) { + if (!mIsDrawing) { + destroyHardwareRenderer(); + } else { + Log.e(mTag, "Attempting to destroy the window while drawing!\n" + + " window=" + this + ", title=" + mWindowAttributes.getTitle()); + } } mHandler.sendEmptyMessage(MSG_DIE); return true; @@ -9977,9 +9978,9 @@ public final class ViewRootImpl implements ViewParent, dispatchDetachedFromWindow(); } - if (mAdded && !mFirst) { - destroyHardwareRenderer(); + destroyHardwareRenderer(); + if (mAdded && !mFirst) { if (mView != null) { int viewVisibility = mView.getVisibility(); boolean viewVisibilityChanged = mViewVisibility != viewVisibility; diff --git a/core/java/android/view/WindowManager.java b/core/java/android/view/WindowManager.java index 5b39f62db2614b7be6e8ab376bd28c6df5714233..b4b0687eb4983cc1c57a28c22b607431d03faba1 100644 --- a/core/java/android/view/WindowManager.java +++ b/core/java/android/view/WindowManager.java @@ -1425,6 +1425,31 @@ public interface WindowManager extends ViewManager { String PROPERTY_COMPAT_ALLOW_USER_ASPECT_RATIO_FULLSCREEN_OVERRIDE = "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 + * {@link android.R.attr#screenOrientation fixed orientation}, + * {@link android.R.attr#minAspectRatio max aspect ratio}, + * {@link android.R.attr#maxAspectRatio min aspect ratio} + * {@link android.R.attr#resizeableActivity unresizable} on large screen devices with the + * ignore orientation request display setting enabled since Android 16 (API level 36) or higher. + * + *

    The default value is {@code false}. + * + *

    Syntax: + *

    +     * <activity>
    +     *   <property
    +     *     android:name="android.window.PROPERTY_COMPAT_ALLOW_RESTRICTED_RESIZABILITY"
    +     *     android:value="true"/>
    +     * </activity>
    +     * 
    + * @hide + */ + // TODO(b/357141415): Make this public API. + String PROPERTY_COMPAT_ALLOW_RESTRICTED_RESIZABILITY = + "android.window.PROPERTY_COMPAT_ALLOW_RESTRICTED_RESIZABILITY"; + /** * @hide */ diff --git a/core/java/android/view/accessibility/AccessibilityEvent.java b/core/java/android/view/accessibility/AccessibilityEvent.java index c690787e4a3356559286da978322bd337b0aeca4..0dfaf4149ce5b616954c386f221f517fd9e6a605 100644 --- a/core/java/android/view/accessibility/AccessibilityEvent.java +++ b/core/java/android/view/accessibility/AccessibilityEvent.java @@ -563,10 +563,13 @@ public final class AccessibilityEvent extends AccessibilityRecord implements Par /** * Represents the event of an application making an announcement. - *

    - * In general, follow the practices described in - * {@link View#announceForAccessibility(CharSequence)}. + * + * @deprecated Use one of the semantic alternative methods described in the documentation of + * {@link View#announceForAccessibility(CharSequence)} instead of using this event, as + * accessibility services may choose to ignore dispatch of this event type. */ + @FlaggedApi(Flags.FLAG_DEPRECATE_ACCESSIBILITY_ANNOUNCEMENT_APIS) + @Deprecated public static final int TYPE_ANNOUNCEMENT = 1 << 14; /** diff --git a/core/java/android/view/accessibility/AccessibilityNodeInfo.java b/core/java/android/view/accessibility/AccessibilityNodeInfo.java index 5e5f33ef41f8d076c1965b749fff50d792079d9b..0204517e869a466da20cf4e20f42bdfce6e686eb 100644 --- a/core/java/android/view/accessibility/AccessibilityNodeInfo.java +++ b/core/java/android/view/accessibility/AccessibilityNodeInfo.java @@ -857,14 +857,46 @@ public class AccessibilityNodeInfo implements Parcelable { *

    * The data can be retrieved from the {@code Bundle} returned by {@link #getExtras()} using this * string as a key for {@link Bundle#getParcelableArray(String, Class)}. The - * {@link android.graphics.RectF} will be null for characters that either do not exist or are - * off the screen. + * {@link android.graphics.RectF} will be {@code null} for characters that either do not exist + * or are off the screen. + *

    + * Note that character locations returned are modified by changes in display magnification. * * {@see #refreshWithExtraData(String, Bundle)} */ public static final String EXTRA_DATA_TEXT_CHARACTER_LOCATION_KEY = "android.view.accessibility.extra.DATA_TEXT_CHARACTER_LOCATION_KEY"; + /** + * Key used to request and locate extra data for text character location in + * window coordinates. This key requests that an array of + * {@link android.graphics.RectF}s be added to the extras. This request is made + * with {@link #refreshWithExtraData(String, Bundle)}. The arguments taken by + * this request are two integers: + * {@link #EXTRA_DATA_TEXT_CHARACTER_LOCATION_ARG_START_INDEX} and + * {@link #EXTRA_DATA_TEXT_CHARACTER_LOCATION_ARG_LENGTH}. The starting index + * must be valid inside the CharSequence returned by {@link #getText()}, and + * the length must be positive. + *

    + * Providers may advertise that they support text characters in window coordinates using + * {@link #setAvailableExtraData(List)}. Services may check if an implementation supports text + * characters in window coordinates with {@link #getAvailableExtraData()}. + *

    + * The data can be retrieved from the {@code Bundle} returned by + * {@link #getExtras()} using this string as a key for + * {@link Bundle#getParcelableArray(String, Class)}. The + * {@link android.graphics.RectF} will be {@code null} for characters that either do + * not exist or are outside of the window bounds. + *

    + * Note that character locations in window bounds are not modified by + * changes in display magnification. + * + * {@see #refreshWithExtraData(String, Bundle)} + */ + @FlaggedApi(Flags.FLAG_A11Y_CHARACTER_IN_WINDOW_API) + public static final String EXTRA_DATA_TEXT_CHARACTER_LOCATION_IN_WINDOW_KEY = + "android.view.accessibility.extra.DATA_TEXT_CHARACTER_LOCATION_IN_WINDOW_KEY"; + /** * Integer argument specifying the start index of the requested text location data. Must be * valid inside the CharSequence returned by {@link #getText()}. @@ -3834,8 +3866,14 @@ public class AccessibilityNodeInfo implements Parcelable { * Sets the view for which the view represented by this info serves as a * label for accessibility purposes. * + * @deprecated Use {@link #addLabeledBy(View)} on the labeled node instead, + * since {@link #getLabeledByList()} and {@link #getLabeledBy()} on the + * labeled node are not automatically populated when this method is used. + * * @param labeled The view for which this info serves as a label. */ + @FlaggedApi(Flags.FLAG_DEPRECATE_ANI_LABEL_FOR_APIS) + @Deprecated public void setLabelFor(View labeled) { setLabelFor(labeled, AccessibilityNodeProvider.HOST_VIEW_ID); } @@ -3856,9 +3894,15 @@ public class AccessibilityNodeInfo implements Parcelable { * This class is made immutable before being delivered to an AccessibilityService. *

    * + * @deprecated Use {@link #addLabeledBy(View)} on the labeled node instead, + * since {@link #getLabeledByList()} and {@link #getLabeledBy()} on the + * labeled node are not automatically populated when this method is used. + * * @param root The root whose virtual descendant serves as a label. * @param virtualDescendantId The id of the virtual descendant. */ + @FlaggedApi(Flags.FLAG_DEPRECATE_ANI_LABEL_FOR_APIS) + @Deprecated public void setLabelFor(View root, int virtualDescendantId) { enforceNotSealed(); final int rootAccessibilityViewId = (root != null) @@ -3870,8 +3914,14 @@ public class AccessibilityNodeInfo implements Parcelable { * Gets the node info for which the view represented by this info serves as * a label for accessibility purposes. * + * @deprecated Use {@link #getLabeledByList()} on the labeled node instead, + * since calling {@link #addLabeledBy(View)} or {@link #addLabeledBy(View, int)} + * on the labeled node do not automatically provide that node from this method. + * * @return The labeled info. */ + @FlaggedApi(Flags.FLAG_DEPRECATE_ANI_LABEL_FOR_APIS) + @Deprecated public AccessibilityNodeInfo getLabelFor() { enforceSealed(); return getNodeForAccessibilityId(mConnectionId, mWindowId, mLabelForId); @@ -4008,8 +4058,12 @@ public class AccessibilityNodeInfo implements Parcelable { * Sets the view which serves as the label of the view represented by * this info for accessibility purposes. * + * @deprecated Use {@link #addLabeledBy(View)} or {@link #removeLabeledBy(View)} instead. + * * @param label The view that labels this node's source. */ + @FlaggedApi(Flags.FLAG_SUPPORT_MULTIPLE_LABELEDBY) + @Deprecated public void setLabeledBy(View label) { setLabeledBy(label, AccessibilityNodeProvider.HOST_VIEW_ID); } @@ -4030,9 +4084,14 @@ public class AccessibilityNodeInfo implements Parcelable { * This class is made immutable before being delivered to an AccessibilityService. *

    * + * @deprecated Use {@link #addLabeledBy(View, int)} or {@link #removeLabeledBy(View, int)} + * instead. + * * @param root The root whose virtual descendant labels this node's source. * @param virtualDescendantId The id of the virtual descendant. */ + @FlaggedApi(Flags.FLAG_SUPPORT_MULTIPLE_LABELEDBY) + @Deprecated public void setLabeledBy(View root, int virtualDescendantId) { enforceNotSealed(); final int rootAccessibilityViewId = (root != null) @@ -4054,8 +4113,12 @@ public class AccessibilityNodeInfo implements Parcelable { * Gets the node info which serves as the label of the view represented by * this info for accessibility purposes. * + * @deprecated Use {@link #getLabeledByList()} instead. + * * @return The label. */ + @FlaggedApi(Flags.FLAG_SUPPORT_MULTIPLE_LABELEDBY) + @Deprecated public AccessibilityNodeInfo getLabeledBy() { enforceSealed(); return getNodeForAccessibilityId(mConnectionId, mWindowId, mLabeledById); @@ -5460,26 +5523,6 @@ public class AccessibilityNodeInfo implements Parcelable { } } - private static String getExpandedStateSymbolicName(int state) { - if (Flags.a11yExpansionStateApi()) { - switch (state) { - case EXPANDED_STATE_UNDEFINED: - return "EXPANDED_STATE_UNDEFINED"; - case EXPANDED_STATE_COLLAPSED: - return "EXPANDED_STATE_COLLAPSED"; - case EXPANDED_STATE_PARTIAL: - return "EXPANDED_STATE_PARTIAL"; - case EXPANDED_STATE_FULL: - return "EXPANDED_STATE_FULL"; - default: - throw new IllegalArgumentException("Unknown expanded state: " + state); - } - } else { - // TODO(b/362782158) Remove when flag is removed. - return ""; - } - } - private static boolean canPerformRequestOverConnection(int connectionId, int windowId, long accessibilityNodeId) { final boolean hasWindowId = windowId != AccessibilityWindowInfo.UNDEFINED_WINDOW_ID; @@ -5573,20 +5616,12 @@ public class AccessibilityNodeInfo implements Parcelable { builder.append("; maxTextLength: ").append(mMaxTextLength); builder.append("; stateDescription: ").append(mStateDescription); builder.append("; contentDescription: ").append(mContentDescription); - if (Flags.supplementalDescription()) { - builder.append("; supplementalDescription: ").append(mSupplementalDescription); - } builder.append("; tooltipText: ").append(mTooltipText); builder.append("; containerTitle: ").append(mContainerTitle); builder.append("; viewIdResName: ").append(mViewIdResourceName); builder.append("; uniqueId: ").append(mUniqueId); - builder.append("; expandedState: ").append(getExpandedStateSymbolicName(mExpandedState)); - builder.append("; checkable: ").append(isCheckable()); builder.append("; checked: ").append(isChecked()); - if (Flags.a11yIsRequiredApi()) { - builder.append("; required: ").append(isFieldRequired()); - } builder.append("; focusable: ").append(isFocusable()); builder.append("; focused: ").append(isFocused()); builder.append("; selected: ").append(isSelected()); diff --git a/core/java/android/view/accessibility/flags/accessibility_flags.aconfig b/core/java/android/view/accessibility/flags/accessibility_flags.aconfig index c07da410c7f9bade5e18a07612b76d4858fd344b..8a006fa5b509aec59b96970652316665e5ce22f0 100644 --- a/core/java/android/view/accessibility/flags/accessibility_flags.aconfig +++ b/core/java/android/view/accessibility/flags/accessibility_flags.aconfig @@ -83,6 +83,20 @@ flag { bug: "280130713" } +flag { + namespace: "accessibility" + name: "deprecate_accessibility_announcement_apis" + description: "Controls the deprecation of platform APIs related to disruptive accessibility announcements" + bug: "376727542" +} + +flag { + namespace: "accessibility" + name: "deprecate_ani_label_for_apis" + description: "Controls the deprecation of AccessibilityNodeInfo labelFor apis" + bug: "333783827" +} + flag { namespace: "accessibility" name: "fix_merged_content_change_event_v2" diff --git a/core/java/android/view/autofill/AutofillFeatureFlags.java b/core/java/android/view/autofill/AutofillFeatureFlags.java index 0ab51e45a951fbb64d7f624cb36ebcf3fc58c5a6..905f350ca6c50fd7468d24dc98c884cdfa0abe6c 100644 --- a/core/java/android/view/autofill/AutofillFeatureFlags.java +++ b/core/java/android/view/autofill/AutofillFeatureFlags.java @@ -316,6 +316,35 @@ public class AutofillFeatureFlags { // END AUTOFILL PCC CLASSIFICATION FLAGS + // START AUTOFILL REMOVE PRE_TRIGGER FLAGS + + /** + * Whether pre-trigger flow is disabled. + * + * @hide + */ + public static final String DEVICE_CONFIG_IMPROVE_FILL_DIALOG_ENABLED = "improve_fill_dialog"; + + /** + * Minimum amount of time (in milliseconds) to wait after IME animation finishes, and before + * starting fill dialog animation. + * + * @hide + */ + public static final String DEVICE_CONFIG_FILL_DIALOG_MIN_WAIT_AFTER_IME_ANIMATION_END_MS = + "fill_dialog_min_wait_after_animation_end_ms"; + + /** + * Sets a value of timeout in milliseconds, measured after animation end, during which fill + * dialog can be shown. If we are at time > animation_end_time + this timeout, fill dialog + * wouldn't be shown. + * + * @hide + */ + public static final String DEVICE_CONFIG_FILL_DIALOG_TIMEOUT_MS = "fill_dialog_timeout_ms"; + + // END AUTOFILL REMOVE PRE_TRIGGER FLAGS + /** * Define the max input length for autofill to show suggesiton UI * @@ -366,6 +395,17 @@ public class AutofillFeatureFlags { DEFAULT_AFAA_SHOULD_INCLUDE_ALL_AUTOFILL_TYPE_NOT_NONE_VIEWS_IN_ASSIST_STRUCTURE = true; // END AUTOFILL FOR ALL APPS DEFAULTS + // START AUTOFILL REMOVE PRE_TRIGGER FLAGS DEFAULTS + // Default for whether the pre trigger removal is enabled. + /** @hide */ + public static final boolean DEFAULT_IMPROVE_FILL_DIALOG_ENABLED = true; + // Default for whether the pre trigger removal is enabled. + /** @hide */ + public static final long DEFAULT_FILL_DIALOG_TIMEOUT_MS = 300; // 300 ms + /** @hide */ + public static final long DEFAULT_FILL_DIALOG_MIN_WAIT_AFTER_IME_ANIMATION_END_MS = 0; // 0 ms + // END AUTOFILL REMOVE PRE_TRIGGER FLAGS DEFAULTS + /** * @hide */ @@ -611,4 +651,48 @@ public class AutofillFeatureFlags { } // END AUTOFILL PCC CLASSIFICATION FUNCTIONS + + + // START AUTOFILL REMOVE PRE_TRIGGER + /** + * Whether Autofill Pre Trigger Removal is enabled. + * + * @hide + */ + public static boolean isImproveFillDialogEnabled() { + // TODO(b/266379948): Add condition for checking whether device has PCC first + + return DeviceConfig.getBoolean( + DeviceConfig.NAMESPACE_AUTOFILL, + DEVICE_CONFIG_IMPROVE_FILL_DIALOG_ENABLED, + DEFAULT_IMPROVE_FILL_DIALOG_ENABLED); + } + + /** + * Whether Autofill Pre Trigger Removal is enabled. + * + * @hide + */ + public static long getFillDialogTimeoutMs() { + // TODO(b/266379948): Add condition for checking whether device has PCC first + + return DeviceConfig.getLong( + DeviceConfig.NAMESPACE_AUTOFILL, + DEVICE_CONFIG_FILL_DIALOG_TIMEOUT_MS, + DEFAULT_FILL_DIALOG_TIMEOUT_MS); + } + + /** + * Whether Autofill Pre Trigger Removal is enabled. + * + * @hide + */ + public static long getFillDialogMinWaitAfterImeAnimationtEndMs() { + // TODO(b/266379948): Add condition for checking whether device has PCC first + + return DeviceConfig.getLong( + DeviceConfig.NAMESPACE_AUTOFILL, + DEVICE_CONFIG_FILL_DIALOG_MIN_WAIT_AFTER_IME_ANIMATION_END_MS, + DEFAULT_FILL_DIALOG_MIN_WAIT_AFTER_IME_ANIMATION_END_MS); + } } diff --git a/core/java/android/view/inputmethod/ImeTracker.java b/core/java/android/view/inputmethod/ImeTracker.java index 2ca62a0725df1e9d63f8c6195bbe8d2431d5dd8f..dd32d57bd6504de3f3b6c25e94f8737b877d7ee8 100644 --- a/core/java/android/view/inputmethod/ImeTracker.java +++ b/core/java/android/view/inputmethod/ImeTracker.java @@ -221,6 +221,7 @@ public interface ImeTracker { PHASE_WM_INVOKING_IME_REQUESTED_LISTENER, PHASE_CLIENT_ALREADY_HIDDEN, PHASE_CLIENT_VIEW_HANDLER_AVAILABLE, + PHASE_SERVER_UPDATE_CLIENT_VISIBILITY, }) @Retention(RetentionPolicy.SOURCE) @interface Phase {} @@ -430,6 +431,11 @@ public interface ImeTracker { * continue without. */ int PHASE_CLIENT_VIEW_HANDLER_AVAILABLE = ImeProtoEnums.PHASE_CLIENT_VIEW_HANDLER_AVAILABLE; + /** + * ImeInsetsSourceProvider sets the reported visibility of the caller/client window (either the + * app or the RemoteInsetsControlTarget). + */ + int PHASE_SERVER_UPDATE_CLIENT_VISIBILITY = ImeProtoEnums.PHASE_SERVER_UPDATE_CLIENT_VISIBILITY; /** * Called when an IME request is started. diff --git a/core/java/android/view/inputmethod/InputMethodManager.java b/core/java/android/view/inputmethod/InputMethodManager.java index 7dc77b175c7932b4ed3ac3a177eb002fbc48cb5a..73f9d9fc23dc90c2b7bfa872a06dcf39f1df7ccc 100644 --- a/core/java/android/view/inputmethod/InputMethodManager.java +++ b/core/java/android/view/inputmethod/InputMethodManager.java @@ -3666,6 +3666,14 @@ public final class InputMethodManager { 0 /* startInputFlags */, 0 /* softInputMode */, 0 /* windowFlags */); } + /** + * Returns the ImeOnBackInvokedDispatcher. + * @hide + */ + public ImeOnBackInvokedDispatcher getImeOnBackInvokedDispatcher() { + return mImeDispatcher; + } + /** * Check the next served view if needs to start input. */ diff --git a/core/java/android/view/inputmethod/InputMethodSubtype.java b/core/java/android/view/inputmethod/InputMethodSubtype.java index be91cfb9ebf83e4dd6f9a012431724c13a49ca32..a67ae7c96a54212da1905f6ad1033a68069bac32 100644 --- a/core/java/android/view/inputmethod/InputMethodSubtype.java +++ b/core/java/android/view/inputmethod/InputMethodSubtype.java @@ -17,8 +17,10 @@ package android.view.inputmethod; import android.annotation.AnyThread; +import android.annotation.FlaggedApi; import android.annotation.NonNull; import android.annotation.Nullable; +import android.annotation.StringRes; import android.content.Context; import android.content.pm.ApplicationInfo; import android.content.res.Configuration; @@ -87,8 +89,17 @@ public final class InputMethodSubtype implements Parcelable { private final boolean mIsAsciiCapable; private final int mSubtypeHashCode; private final int mSubtypeIconResId; + /** The subtype name resource identifier. */ private final int mSubtypeNameResId; + /** The untranslatable name of the subtype. */ + @NonNull private final CharSequence mSubtypeNameOverride; + /** The layout label string resource identifier. */ + @StringRes + private final int mLayoutLabelResId; + /** The non-localized layout label. */ + @NonNull + private final CharSequence mLayoutLabelNonLocalized; private final String mPkLanguageTag; private final String mPkLayoutType; private final int mSubtypeId; @@ -176,6 +187,7 @@ public final class InputMethodSubtype implements Parcelable { mSubtypeNameResId = subtypeNameResId; return this; } + /** The subtype name resource identifier. */ private int mSubtypeNameResId = 0; /** @@ -191,8 +203,55 @@ public final class InputMethodSubtype implements Parcelable { mSubtypeNameOverride = nameOverride; return this; } + /** The untranslatable name of the subtype. */ + @NonNull private CharSequence mSubtypeNameOverride = ""; + /** + * Sets the layout label string resource identifier. + * + * @param layoutLabelResId the layout label string resource identifier. + * + * @see #getLayoutDisplayName + */ + @FlaggedApi(Flags.FLAG_IME_SWITCHER_REVAMP_API) + @NonNull + public InputMethodSubtypeBuilder setLayoutLabelResource( + @StringRes int layoutLabelResId) { + if (!Flags.imeSwitcherRevampApi()) { + return this; + } + mLayoutLabelResId = layoutLabelResId; + return this; + } + /** The layout label string resource identifier. */ + @StringRes + private int mLayoutLabelResId = 0; + + /** + * Sets the non-localized layout label. This is used as the layout display name if the + * {@link #getLayoutLabelResource layoutLabelResource} is not set ({@code 0}). + * + * @param layoutLabelNonLocalized the non-localized layout label. + * + * @see #getLayoutDisplayName + */ + @FlaggedApi(Flags.FLAG_IME_SWITCHER_REVAMP_API) + @NonNull + public InputMethodSubtypeBuilder setLayoutLabelNonLocalized( + @NonNull CharSequence layoutLabelNonLocalized) { + if (!Flags.imeSwitcherRevampApi()) { + return this; + } + Objects.requireNonNull(layoutLabelNonLocalized, + "layoutLabelNonLocalized cannot be null"); + mLayoutLabelNonLocalized = layoutLabelNonLocalized; + return this; + } + /** The non-localized layout label. */ + @NonNull + private CharSequence mLayoutLabelNonLocalized = ""; + /** * Sets the physical keyboard hint information, such as language and layout. * @@ -350,6 +409,8 @@ public final class InputMethodSubtype implements Parcelable { private InputMethodSubtype(InputMethodSubtypeBuilder builder) { mSubtypeNameResId = builder.mSubtypeNameResId; mSubtypeNameOverride = builder.mSubtypeNameOverride; + mLayoutLabelResId = builder.mLayoutLabelResId; + mLayoutLabelNonLocalized = builder.mLayoutLabelNonLocalized; mPkLanguageTag = builder.mPkLanguageTag; mPkLayoutType = builder.mPkLayoutType; mSubtypeIconResId = builder.mSubtypeIconResId; @@ -376,6 +437,9 @@ public final class InputMethodSubtype implements Parcelable { mSubtypeNameResId = source.readInt(); CharSequence cs = TextUtils.CHAR_SEQUENCE_CREATOR.createFromParcel(source); mSubtypeNameOverride = cs != null ? cs : ""; + mLayoutLabelResId = source.readInt(); + cs = TextUtils.CHAR_SEQUENCE_CREATOR.createFromParcel(source); + mLayoutLabelNonLocalized = cs != null ? cs : ""; s = source.readString8(); mPkLanguageTag = s != null ? s : ""; s = source.readString8(); @@ -411,6 +475,24 @@ public final class InputMethodSubtype implements Parcelable { return mSubtypeNameOverride; } + /** + * Returns the layout label string resource identifier. + */ + @FlaggedApi(Flags.FLAG_IME_SWITCHER_REVAMP_API) + @StringRes + public int getLayoutLabelResource() { + return mLayoutLabelResId; + } + + /** + * Returns the non-localized layout label. + */ + @FlaggedApi(Flags.FLAG_IME_SWITCHER_REVAMP_API) + @NonNull + public CharSequence getLayoutLabelNonLocalized() { + return mLayoutLabelNonLocalized; + } + /** * Returns the physical keyboard BCP-47 language tag. * @@ -643,9 +725,47 @@ public final class InputMethodSubtype implements Parcelable { try { return String.format(subtypeNameString, replacementString); } catch (IllegalFormatException e) { - Slog.w(TAG, "Found illegal format in subtype name("+ subtypeName + "): " + e); + Slog.w(TAG, "Found illegal format in subtype name(" + subtypeName + "): " + e); + return ""; + } + } + + /** + * Returns the layout display name. + * + *

    If {@code layoutLabelResource} is non-zero (specified through + * {@link InputMethodSubtypeBuilder#setLayoutLabelResource setLayoutLabelResource}), the + * text generated from that resource will be returned. The localized string resource of the + * label should be capitalized for inclusion in UI lists. + * + *

    If {@code layoutLabelResource} is zero, the framework returns the non-localized + * layout label, if specified through + * {@link InputMethodSubtypeBuilder#setLayoutLabelNonLocalized setLayoutLabelNonLocalized}. + * + * @param context The context used for getting the + * {@link android.content.pm.PackageManager PackageManager}. + * @param imeAppInfo The {@link ApplicationInfo} of the input method. + * @return the layout display name. + */ + @NonNull + @FlaggedApi(Flags.FLAG_IME_SWITCHER_REVAMP_API) + public CharSequence getLayoutDisplayName(@NonNull Context context, + @NonNull ApplicationInfo imeAppInfo) { + if (!Flags.imeSwitcherRevampApi()) { + return ""; + } + Objects.requireNonNull(context, "context cannot be null"); + Objects.requireNonNull(imeAppInfo, "imeAppInfo cannot be null"); + if (mLayoutLabelResId == 0) { + return mLayoutLabelNonLocalized; + } + + final CharSequence subtypeLayoutName = context.getPackageManager().getText( + imeAppInfo.packageName, mLayoutLabelResId, imeAppInfo); + if (TextUtils.isEmpty(subtypeLayoutName)) { return ""; } + return subtypeLayoutName; } @Nullable @@ -778,6 +898,8 @@ public final class InputMethodSubtype implements Parcelable { public void writeToParcel(Parcel dest, int parcelableFlags) { dest.writeInt(mSubtypeNameResId); TextUtils.writeToParcel(mSubtypeNameOverride, dest, parcelableFlags); + dest.writeInt(mLayoutLabelResId); + TextUtils.writeToParcel(mLayoutLabelNonLocalized, dest, parcelableFlags); dest.writeString8(mPkLanguageTag); dest.writeString8(mPkLayoutType); dest.writeInt(mSubtypeIconResId); @@ -794,6 +916,7 @@ public final class InputMethodSubtype implements Parcelable { void dump(@NonNull Printer pw, @NonNull String prefix) { pw.println(prefix + "mSubtypeNameOverride=" + mSubtypeNameOverride + + " mLayoutLabelNonLocalized=" + mLayoutLabelNonLocalized + " mPkLanguageTag=" + mPkLanguageTag + " mPkLayoutType=" + mPkLayoutType + " mSubtypeId=" + mSubtypeId diff --git a/core/java/android/view/inputmethod/flags.aconfig b/core/java/android/view/inputmethod/flags.aconfig index aa4927ee9b9c1cbaf54b3de13f48bf912c4bb9d2..edd9d6cff799769a5cef5aab91b0b89e40316cec 100644 --- a/core/java/android/view/inputmethod/flags.aconfig +++ b/core/java/android/view/inputmethod/flags.aconfig @@ -158,3 +158,11 @@ flag { purpose: PURPOSE_BUGFIX } } + +flag { + name: "writing_tools" + namespace: "input_method" + description: "Writing tools API" + bug: "373788889" + is_fixed_read_only: true +} \ No newline at end of file diff --git a/core/java/android/widget/TextView.java b/core/java/android/widget/TextView.java index ef941da0e32dd1d120b21be71248c2d5192e0f70..d7750bd412a3790dce7a04f3eb9009a1d4518dbe 100644 --- a/core/java/android/widget/TextView.java +++ b/core/java/android/widget/TextView.java @@ -26,6 +26,9 @@ import static android.view.accessibility.AccessibilityNodeInfo.EXTRA_DATA_RENDER import static android.view.accessibility.AccessibilityNodeInfo.EXTRA_DATA_TEXT_CHARACTER_LOCATION_ARG_LENGTH; import static android.view.accessibility.AccessibilityNodeInfo.EXTRA_DATA_TEXT_CHARACTER_LOCATION_ARG_START_INDEX; import static android.view.accessibility.AccessibilityNodeInfo.EXTRA_DATA_TEXT_CHARACTER_LOCATION_KEY; +import static android.view.accessibility.AccessibilityNodeInfo.EXTRA_DATA_TEXT_CHARACTER_LOCATION_IN_WINDOW_KEY; +import static android.view.accessibility.Flags.FLAG_A11Y_CHARACTER_IN_WINDOW_API; +import static android.view.accessibility.Flags.a11yCharacterInWindowApi; import static android.view.inputmethod.CursorAnchorInfo.FLAG_HAS_VISIBLE_REGION; import static android.view.inputmethod.EditorInfo.STYLUS_HANDWRITING_ENABLED_ANDROIDX_EXTRAS_KEY; import static android.view.inputmethod.Flags.initiationWithoutInputConnection; @@ -492,6 +495,20 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener /** Accessibility action start id for "smart" actions. @hide */ static final int ACCESSIBILITY_ACTION_SMART_START_ID = 0x10001000; + // Stable extra data keys supported by TextView. + private static final List ACCESSIBILITY_EXTRA_DATA_KEYS = List.of( + EXTRA_DATA_RENDERING_INFO_KEY, + EXTRA_DATA_TEXT_CHARACTER_LOCATION_KEY + ); + + // Flagged and stable extra data keys supported by TextView. + @FlaggedApi(FLAG_A11Y_CHARACTER_IN_WINDOW_API) + private static final List ACCESSIBILITY_EXTRA_DATA_KEYS_FLAGGED = List.of( + EXTRA_DATA_RENDERING_INFO_KEY, + EXTRA_DATA_TEXT_CHARACTER_LOCATION_KEY, + EXTRA_DATA_TEXT_CHARACTER_LOCATION_IN_WINDOW_KEY + ); + /** * @hide */ @@ -14207,10 +14224,11 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener | AccessibilityNodeInfo.MOVEMENT_GRANULARITY_PARAGRAPH | AccessibilityNodeInfo.MOVEMENT_GRANULARITY_PAGE); info.addAction(AccessibilityNodeInfo.ACTION_SET_SELECTION); - info.setAvailableExtraData(Arrays.asList( - EXTRA_DATA_RENDERING_INFO_KEY, - EXTRA_DATA_TEXT_CHARACTER_LOCATION_KEY - )); + if (a11yCharacterInWindowApi()) { + info.setAvailableExtraData(ACCESSIBILITY_EXTRA_DATA_KEYS_FLAGGED); + } else { + info.setAvailableExtraData(ACCESSIBILITY_EXTRA_DATA_KEYS); + } info.setTextSelectable(isTextSelectable() || isTextEditable()); } else { info.setAvailableExtraData(Arrays.asList( @@ -14275,7 +14293,11 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener @Override public void addExtraDataToAccessibilityNodeInfo( AccessibilityNodeInfo info, String extraDataKey, Bundle arguments) { - if (arguments != null && extraDataKey.equals(EXTRA_DATA_TEXT_CHARACTER_LOCATION_KEY)) { + boolean isCharacterLocationKey = extraDataKey.equals( + EXTRA_DATA_TEXT_CHARACTER_LOCATION_KEY); + boolean isCharacterLocationInWindowKey = (a11yCharacterInWindowApi() && extraDataKey.equals( + EXTRA_DATA_TEXT_CHARACTER_LOCATION_IN_WINDOW_KEY)); + if (arguments != null && (isCharacterLocationKey || isCharacterLocationInWindowKey)) { int positionInfoStartIndex = arguments.getInt( EXTRA_DATA_TEXT_CHARACTER_LOCATION_ARG_START_INDEX, -1); int positionInfoLength = arguments.getInt( @@ -14297,7 +14319,11 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener RectF bounds = cursorAnchorInfo .getCharacterBounds(positionInfoStartIndex + i); if (bounds != null) { - mapRectFromViewToScreenCoords(bounds, true); + if (isCharacterLocationKey) { + mapRectFromViewToScreenCoords(bounds, true); + } else if (isCharacterLocationInWindowKey) { + mapRectFromViewToWindowCoords(bounds, true); + } boundingRects[i] = bounds; } } diff --git a/core/java/android/window/BackProgressAnimator.java b/core/java/android/window/BackProgressAnimator.java index a5be58b7b1831db97d628e216134e6edeebbe473..16eb43700aeff7aaf8a3a6e05a002abcf8e67560 100644 --- a/core/java/android/window/BackProgressAnimator.java +++ b/core/java/android/window/BackProgressAnimator.java @@ -16,8 +16,11 @@ package android.window; +import static android.window.BackEvent.EDGE_NONE; + import static com.android.internal.annotations.VisibleForTesting.Visibility.PACKAGE; import static com.android.window.flags.Flags.predictiveBackTimestampApi; +import static com.android.window.flags.Flags.predictiveBackSwipeEdgeNoneApi; import android.annotation.NonNull; import android.annotation.Nullable; @@ -60,6 +63,12 @@ public class BackProgressAnimator implements DynamicAnimation.OnAnimationUpdateL @Nullable private Runnable mBackInvokedFinishRunnable; private FlingAnimation mBackInvokedFlingAnim; + private final SpringForce mGestureSpringForce = new SpringForce() + .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) -> { if (mBackCancelledFinishRunnable != null) invokeBackCancelledRunnable(); @@ -109,9 +118,7 @@ public class BackProgressAnimator implements DynamicAnimation.OnAnimationUpdateL public BackProgressAnimator() { mSpring = new SpringAnimation(this, PROGRESS_PROP); mSpring.addUpdateListener(this); - mSpring.setSpring(new SpringForce() - .setStiffness(SpringForce.STIFFNESS_MEDIUM) - .setDampingRatio(SpringForce.DAMPING_RATIO_NO_BOUNCY)); + mSpring.setSpring(mGestureSpringForce); } /** @@ -123,6 +130,11 @@ public class BackProgressAnimator implements DynamicAnimation.OnAnimationUpdateL if (!mBackAnimationInProgress) { return; } + if (predictiveBackSwipeEdgeNoneApi()) { + if (event.getSwipeEdge() == EDGE_NONE) { + return; + } + } mLastBackEvent = event; if (mSpring == null) { return; @@ -143,7 +155,17 @@ public class BackProgressAnimator implements DynamicAnimation.OnAnimationUpdateL mBackAnimationInProgress = true; updateProgressValue(/* progress */ 0, /* velocity */ 0, /* frameTime */ System.nanoTime() / TimeUtils.NANOS_PER_MS); - onBackProgressed(event); + if (predictiveBackSwipeEdgeNoneApi()) { + if (event.getSwipeEdge() == EDGE_NONE) { + mSpring.setSpring(mButtonSpringForce); + mSpring.animateToFinalPosition(SCALE_FACTOR); + } else { + mSpring.setSpring(mGestureSpringForce); + onBackProgressed(event); + } + } else { + onBackProgressed(event); + } } /** diff --git a/core/java/android/window/DesktopModeFlags.java b/core/java/android/window/DesktopModeFlags.java index dae87ddcb1bd04ab5e2e41984604a4c96a245d64..6b5a367ab4602c8affeb98421c148ac018c1ef88 100644 --- a/core/java/android/window/DesktopModeFlags.java +++ b/core/java/android/window/DesktopModeFlags.java @@ -75,7 +75,8 @@ public enum DesktopModeFlags { Flags::enableDesktopAppLaunchAlttabTransitions, false), ENABLE_DESKTOP_APP_LAUNCH_TRANSITIONS( Flags::enableDesktopAppLaunchTransitions, false), - ENABLE_DESKTOP_WINDOWING_PERSISTENCE(Flags::enableDesktopWindowingPersistence, false); + ENABLE_DESKTOP_WINDOWING_PERSISTENCE(Flags::enableDesktopWindowingPersistence, false), + ENABLE_HANDLE_INPUT_FIX(Flags::enableHandleInputFix, true); private static final String TAG = "DesktopModeFlagsUtil"; // Function called to obtain aconfig flag value. diff --git a/core/java/android/window/ImeOnBackInvokedDispatcher.java b/core/java/android/window/ImeOnBackInvokedDispatcher.java index bd01899a649b6d2ca896a5a88402f09430f91a4f..c67b9cac250baa1a34e4ec3974d36f02844f8869 100644 --- a/core/java/android/window/ImeOnBackInvokedDispatcher.java +++ b/core/java/android/window/ImeOnBackInvokedDispatcher.java @@ -203,6 +203,34 @@ public class ImeOnBackInvokedDispatcher implements OnBackInvokedDispatcher, Parc mImeCallbacks.remove(callback); } + /** + * Unregisters all callbacks on the receiving dispatcher but keeps a reference of the callbacks + * in case the clearance is reverted in + * {@link ImeOnBackInvokedDispatcher#undoPreliminaryClear()}. + */ + public void preliminaryClear() { + // Unregister previously registered callbacks if there's any. + if (getReceivingDispatcher() != null) { + for (ImeOnBackInvokedCallback callback : mImeCallbacks) { + getReceivingDispatcher().unregisterOnBackInvokedCallback(callback); + } + } + } + + /** + * Reregisters all callbacks on the receiving dispatcher that have previously been cleared by + * calling {@link ImeOnBackInvokedDispatcher#preliminaryClear()}. This can happen if an IME hide + * animation is interrupted causing the IME to reappear. + */ + public void undoPreliminaryClear() { + if (getReceivingDispatcher() != null) { + for (ImeOnBackInvokedCallback callback : mImeCallbacks) { + getReceivingDispatcher().registerOnBackInvokedCallbackUnchecked(callback, + callback.mPriority); + } + } + } + /** Clears all registered callbacks on the instance. */ public void clear() { // Unregister previously registered callbacks if there's any. diff --git a/core/java/android/window/OnBackInvokedCallbackInfo.java b/core/java/android/window/OnBackInvokedCallbackInfo.java index bb5fe96fdec1b278e3ff62139f6e608013f45e93..44c7bd9ec61264ce1515108664ee6b4558629ab6 100644 --- a/core/java/android/window/OnBackInvokedCallbackInfo.java +++ b/core/java/android/window/OnBackInvokedCallbackInfo.java @@ -16,6 +16,8 @@ package android.window; +import static android.window.SystemOverrideOnBackInvokedCallback.OVERRIDE_UNDEFINED; + import android.annotation.NonNull; import android.os.Parcel; import android.os.Parcelable; @@ -29,19 +31,23 @@ public final class OnBackInvokedCallbackInfo implements Parcelable { private final IOnBackInvokedCallback mCallback; private @OnBackInvokedDispatcher.Priority int mPriority; private final boolean mIsAnimationCallback; + private final @SystemOverrideOnBackInvokedCallback.OverrideBehavior int mOverrideBehavior; public OnBackInvokedCallbackInfo(@NonNull IOnBackInvokedCallback callback, int priority, - boolean isAnimationCallback) { + boolean isAnimationCallback, + int overrideBehavior) { mCallback = callback; mPriority = priority; mIsAnimationCallback = isAnimationCallback; + mOverrideBehavior = overrideBehavior; } private OnBackInvokedCallbackInfo(@NonNull Parcel in) { mCallback = IOnBackInvokedCallback.Stub.asInterface(in.readStrongBinder()); mPriority = in.readInt(); mIsAnimationCallback = in.readBoolean(); + mOverrideBehavior = in.readInt(); } @Override @@ -54,6 +60,7 @@ public final class OnBackInvokedCallbackInfo implements Parcelable { dest.writeStrongInterface(mCallback); dest.writeInt(mPriority); dest.writeBoolean(mIsAnimationCallback); + dest.writeInt(mOverrideBehavior); } public static final Creator CREATOR = @@ -70,7 +77,8 @@ public final class OnBackInvokedCallbackInfo implements Parcelable { }; public boolean isSystemCallback() { - return mPriority == OnBackInvokedDispatcher.PRIORITY_SYSTEM; + return mPriority == OnBackInvokedDispatcher.PRIORITY_SYSTEM + || mOverrideBehavior != OVERRIDE_UNDEFINED; } @NonNull @@ -87,12 +95,18 @@ public final class OnBackInvokedCallbackInfo implements Parcelable { return mIsAnimationCallback; } + @SystemOverrideOnBackInvokedCallback.OverrideBehavior + public int getOverrideBehavior() { + return mOverrideBehavior; + } + @Override public String toString() { return "OnBackInvokedCallbackInfo{" + "mCallback=" + mCallback + ", mPriority=" + mPriority + ", mIsAnimationCallback=" + mIsAnimationCallback + + ", mOverrideBehavior=" + mOverrideBehavior + '}'; } } diff --git a/core/java/android/window/SystemOnBackInvokedCallbacks.java b/core/java/android/window/SystemOnBackInvokedCallbacks.java new file mode 100644 index 0000000000000000000000000000000000000000..f67520b1de96f052b7e9beb59d76173f3990328e --- /dev/null +++ b/core/java/android/window/SystemOnBackInvokedCallbacks.java @@ -0,0 +1,168 @@ +/* + * 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.annotation.FlaggedApi; +import android.annotation.NonNull; +import android.app.Activity; +import android.util.ArrayMap; + +import com.android.window.flags.Flags; + +import java.lang.ref.WeakReference; + +/** + * Utility class providing {@link OnBackInvokedCallback}s to override the default behavior when + * system back is invoked. e.g. {@link Activity#finish} + * + *

    By registering these callbacks with the {@link OnBackInvokedDispatcher}, the system can + * trigger specific behaviors and play corresponding ahead-of-time animations when the back + * gesture is invoked. + * + *

    For example, to trigger the {@link Activity#moveTaskToBack} behavior: + *

    + *   OnBackInvokedDispatcher dispatcher = activity.getOnBackInvokedDispatcher();
    + *   dispatcher.registerOnBackInvokedCallback(
    + *       OnBackInvokedDispatcher.PRIORITY_DEFAULT,
    + *       SystemOnBackInvokedCallbacks.moveTaskToBackCallback(activity));
    + * 
    + */ +@SuppressWarnings("SingularCallback") +@FlaggedApi(Flags.FLAG_PREDICTIVE_BACK_SYSTEM_OVERRIDE_CALLBACK) +public final class SystemOnBackInvokedCallbacks { + private static final OverrideCallbackFactory sMoveTaskToBackFactory = new + MoveTaskToBackCallbackFactory(); + private static final OverrideCallbackFactory sFinishAndRemoveTaskFactory = new + FinishAndRemoveTaskCallbackFactory(); + + private SystemOnBackInvokedCallbacks() { + throw new UnsupportedOperationException("This is a utility class and cannot be " + + "instantiated"); + } + + /** + *

    Get a callback to triggers {@link Activity#moveTaskToBack(boolean)} on the associated + * {@link Activity}, moving the task containing the activity to the background. The system + * will play the corresponding transition animation, regardless of whether the activity + * is the root activity of the task.

    + * + * @param activity The associated {@link Activity} + * @see Activity#moveTaskToBack(boolean) + */ + @FlaggedApi(Flags.FLAG_PREDICTIVE_BACK_SYSTEM_OVERRIDE_CALLBACK) + @NonNull + public static OnBackInvokedCallback moveTaskToBackCallback(@NonNull Activity activity) { + return sMoveTaskToBackFactory.getOverrideCallback(activity); + } + + /** + *

    Get a callback to triggers {@link Activity#finishAndRemoveTask()} on the associated + * {@link Activity}. If the activity is the root activity of its task, the entire task + * will be removed from the recents task. The activity will be finished in all cases. + * The system will play the corresponding transition animation.

    + * + * @param activity The associated {@link Activity} + * @see Activity#finishAndRemoveTask() + */ + @FlaggedApi(Flags.FLAG_PREDICTIVE_BACK_SYSTEM_OVERRIDE_CALLBACK) + @NonNull + public static OnBackInvokedCallback finishAndRemoveTaskCallback(@NonNull Activity activity) { + return sFinishAndRemoveTaskFactory.getOverrideCallback(activity); + } + + /** + * Abstract factory for creating system override {@link SystemOverrideOnBackInvokedCallback} + * instances. + * + *

    Concrete implementations of this factory are responsible for creating callbacks that + * override the default system back navigation behavior. These callbacks should be used + * exclusively for system overrides and should never be invoked directly.

    + */ + private abstract static class OverrideCallbackFactory { + private final ArrayMap, + WeakReference> mObjectMap = new ArrayMap<>(); + + protected abstract SystemOverrideOnBackInvokedCallback createCallback( + @NonNull TYPE context); + + @NonNull SystemOverrideOnBackInvokedCallback getOverrideCallback(@NonNull TYPE object) { + if (object == null) { + throw new NullPointerException("Input object cannot be null"); + } + synchronized (mObjectMap) { + WeakReference callback = null; + for (int i = mObjectMap.size() - 1; i >= 0; --i) { + final WeakReference next = mObjectMap.keyAt(i); + if (next.get() == object) { + callback = mObjectMap.get(next); + break; + } + } + if (callback != null) { + return callback.get(); + } + final SystemOverrideOnBackInvokedCallback contextCallback = createCallback(object); + if (contextCallback != null) { + mObjectMap.put(new WeakReference<>(object), + new WeakReference<>(contextCallback)); + } + return contextCallback; + } + } + } + + private static class MoveTaskToBackCallbackFactory extends OverrideCallbackFactory { + @Override + protected SystemOverrideOnBackInvokedCallback createCallback(Activity activity) { + final WeakReference activityRef = new WeakReference<>(activity); + return new SystemOverrideOnBackInvokedCallback() { + @Override + public void onBackInvoked() { + if (activityRef.get() != null) { + activityRef.get().moveTaskToBack(true /* nonRoot */); + } + } + + @Override + public int overrideBehavior() { + return OVERRIDE_MOVE_TASK_TO_BACK; + } + }; + } + } + + private static class FinishAndRemoveTaskCallbackFactory extends + OverrideCallbackFactory { + @Override + protected SystemOverrideOnBackInvokedCallback createCallback(Activity activity) { + final WeakReference activityRef = new WeakReference<>(activity); + return new SystemOverrideOnBackInvokedCallback() { + @Override + public void onBackInvoked() { + if (activityRef.get() != null) { + activityRef.get().finishAndRemoveTask(); + } + } + + @Override + public int overrideBehavior() { + return OVERRIDE_FINISH_AND_REMOVE_TASK; + } + }; + } + } +} diff --git a/core/java/android/window/SystemOverrideOnBackInvokedCallback.java b/core/java/android/window/SystemOverrideOnBackInvokedCallback.java new file mode 100644 index 0000000000000000000000000000000000000000..3360a199682eb472ac20511a09f32cef103d80a2 --- /dev/null +++ b/core/java/android/window/SystemOverrideOnBackInvokedCallback.java @@ -0,0 +1,61 @@ +/* + * 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.annotation.IntDef; + +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; + +/** + * Non-default ahead-of-time system OnBackInvokedCallback. + * @hide + */ +public interface SystemOverrideOnBackInvokedCallback extends OnBackInvokedCallback { + /** + * No override request + */ + int OVERRIDE_UNDEFINED = 0; + + /** + * Navigating back will bring the task to back + */ + int OVERRIDE_MOVE_TASK_TO_BACK = 1; + + /** + * Navigating back will finish activity, and remove the task if this activity is root activity. + */ + int OVERRIDE_FINISH_AND_REMOVE_TASK = 2; + + /** @hide */ + @IntDef({ + OVERRIDE_UNDEFINED, + OVERRIDE_MOVE_TASK_TO_BACK, + OVERRIDE_FINISH_AND_REMOVE_TASK, + }) + @Retention(RetentionPolicy.SOURCE) + @interface OverrideBehavior { + } + + /** + * @return Override type of this callback. + */ + @OverrideBehavior + default int overrideBehavior() { + return OVERRIDE_UNDEFINED; + } +} diff --git a/core/java/android/window/TransitionFilter.java b/core/java/android/window/TransitionFilter.java index 8bb4c526b20ded5e06c65494250f50e404802f3d..61fc6226f822e00a82319818422362c62a5630d1 100644 --- a/core/java/android/window/TransitionFilter.java +++ b/core/java/android/window/TransitionFilter.java @@ -17,6 +17,7 @@ package android.window; import static android.app.WindowConfiguration.ACTIVITY_TYPE_UNDEFINED; +import static android.app.WindowConfiguration.WINDOWING_MODE_UNDEFINED; import static android.view.WindowManager.TransitionType; import android.annotation.IntDef; @@ -189,6 +190,8 @@ public final class TransitionFilter implements Parcelable { public Boolean mCustomAnimation = null; public IBinder mTaskFragmentToken = null; + public int mWindowingMode = WINDOWING_MODE_UNDEFINED; + public Requirement() { } @@ -206,6 +209,7 @@ public final class TransitionFilter implements Parcelable { final int customAnimRaw = in.readInt(); mCustomAnimation = customAnimRaw == 0 ? null : Boolean.valueOf(customAnimRaw == 2); mTaskFragmentToken = in.readStrongBinder(); + mWindowingMode = in.readInt(); } /** Go through changes and find if at-least one change matches this filter */ @@ -270,6 +274,12 @@ public final class TransitionFilter implements Parcelable { continue; } } + if (mWindowingMode != WINDOWING_MODE_UNDEFINED) { + if (change.getTaskInfo() == null + || change.getTaskInfo().getWindowingMode() != mWindowingMode) { + continue; + } + } return true; } return false; @@ -322,6 +332,7 @@ public final class TransitionFilter implements Parcelable { int customAnimRaw = mCustomAnimation == null ? 0 : (mCustomAnimation ? 2 : 1); dest.writeInt(customAnimRaw); dest.writeStrongBinder(mTaskFragmentToken); + dest.writeInt(mWindowingMode); } @NonNull @@ -369,6 +380,8 @@ public final class TransitionFilter implements Parcelable { if (mTaskFragmentToken != null) { out.append(" taskFragmentToken=").append(mTaskFragmentToken); } + out.append(" windowingMode=" + + WindowConfiguration.windowingModeToString(mWindowingMode)); out.append("}"); return out.toString(); } diff --git a/core/java/android/window/TransitionInfo.java b/core/java/android/window/TransitionInfo.java index 14505f5271953010ae309c6b1389e6238763395e..0f2dd10d7f474cdfb788cda7c779a3fb5ca2c42a 100644 --- a/core/java/android/window/TransitionInfo.java +++ b/core/java/android/window/TransitionInfo.java @@ -169,8 +169,11 @@ public final class TransitionInfo implements Parcelable { /** This change represents its start configuration for the duration of the animation. */ public static final int FLAG_CONFIG_AT_END = 1 << 22; + /** This change represents one of a Task Display Area. */ + public static final int FLAG_IS_TASK_DISPLAY_AREA = 1 << 23; + /** The first unused bit. This can be used by remotes to attach custom flags to this change. */ - public static final int FLAG_FIRST_CUSTOM = 1 << 23; + public static final int FLAG_FIRST_CUSTOM = 1 << 24; /** The change belongs to a window that won't contain activities. */ public static final int FLAGS_IS_NON_APP_WINDOW = @@ -205,6 +208,7 @@ public final class TransitionInfo implements Parcelable { FLAG_MOVED_TO_TOP, FLAG_SYNC, FLAG_CONFIG_AT_END, + FLAG_IS_TASK_DISPLAY_AREA, FLAG_FIRST_CUSTOM }, flag = true) public @interface ChangeFlags {} @@ -553,6 +557,9 @@ public final class TransitionInfo implements Parcelable { if ((flags & FLAG_MOVED_TO_TOP) != 0) { sb.append(sb.length() == 0 ? "" : "|").append("MOVE_TO_TOP"); } + if ((flags & FLAG_IS_TASK_DISPLAY_AREA) != 0) { + sb.append(sb.length() == 0 ? "" : "|").append("FLAG_IS_TASK_DISPLAY_AREA"); + } return sb.toString(); } diff --git a/core/java/android/window/WindowOnBackInvokedDispatcher.java b/core/java/android/window/WindowOnBackInvokedDispatcher.java index c9d458f22463e87908fd29d9563636f333751b6a..0ea4bb41d3a4bb368ec8cd1f67184e48dd995f12 100644 --- a/core/java/android/window/WindowOnBackInvokedDispatcher.java +++ b/core/java/android/window/WindowOnBackInvokedDispatcher.java @@ -16,6 +16,9 @@ package android.window; +import static android.window.SystemOverrideOnBackInvokedCallback.OVERRIDE_UNDEFINED; + +import static com.android.window.flags.Flags.predictiveBackSystemOverrideCallback; import static com.android.window.flags.Flags.predictiveBackPrioritySystemNavigationObserver; import static com.android.window.flags.Flags.predictiveBackTimestampApi; @@ -201,6 +204,15 @@ public class WindowOnBackInvokedDispatcher implements OnBackInvokedDispatcher { mImeDispatcher.registerOnBackInvokedCallback(priority, callback); return; } + if (predictiveBackPrioritySystemNavigationObserver() + && predictiveBackSystemOverrideCallback()) { + if (priority == PRIORITY_SYSTEM_NAVIGATION_OBSERVER + && callback instanceof SystemOverrideOnBackInvokedCallback) { + Log.e(TAG, "System override callbacks cannot be registered to " + + "NAVIGATION_OBSERVER"); + return; + } + } if (predictiveBackPrioritySystemNavigationObserver()) { if (priority == PRIORITY_SYSTEM_NAVIGATION_OBSERVER) { registerSystemNavigationObserverCallback(callback); @@ -365,7 +377,8 @@ public class WindowOnBackInvokedDispatcher implements OnBackInvokedDispatcher { public void tryInvokeSystemNavigationObserverCallback() { OnBackInvokedCallback topCallback = getTopCallback(); Integer callbackPriority = mAllCallbacks.getOrDefault(topCallback, null); - if (callbackPriority != null && callbackPriority == PRIORITY_SYSTEM) { + final boolean isSystemOverride = topCallback instanceof SystemOverrideOnBackInvokedCallback; + if ((callbackPriority != null && callbackPriority == PRIORITY_SYSTEM) || isSystemOverride) { invokeSystemNavigationObserverCallback(); } } @@ -384,14 +397,22 @@ public class WindowOnBackInvokedDispatcher implements OnBackInvokedDispatcher { OnBackInvokedCallbackInfo callbackInfo = null; if (callback != null) { int priority = mAllCallbacks.get(callback); + int overrideAnimation = OVERRIDE_UNDEFINED; + if (callback instanceof SystemOverrideOnBackInvokedCallback) { + overrideAnimation = ((SystemOverrideOnBackInvokedCallback) callback) + .overrideBehavior(); + } + final boolean isSystemCallback = priority == PRIORITY_SYSTEM + || overrideAnimation != OVERRIDE_UNDEFINED; final IOnBackInvokedCallback iCallback = new OnBackInvokedCallbackWrapper(callback, mTouchTracker, mProgressAnimator, mHandler, this::callOnKeyPreIme, this::invokeSystemNavigationObserverCallback, - /*isSystemCallback*/ priority == PRIORITY_SYSTEM); + isSystemCallback /*isSystemCallback*/); callbackInfo = new OnBackInvokedCallbackInfo( iCallback, priority, - callback instanceof OnBackAnimationCallback); + callback instanceof OnBackAnimationCallback, + overrideAnimation); } mWindowSession.setOnBackInvokedCallbackInfo(mWindow, callbackInfo); } catch (RemoteException e) { diff --git a/core/java/android/window/flags/lse_desktop_experience.aconfig b/core/java/android/window/flags/lse_desktop_experience.aconfig index 731d10048d7cbd51bce4046f86f0cac1174527ec..d39ecabbb2d25bc46eb26c599a84e3b96a5d45d3 100644 --- a/core/java/android/window/flags/lse_desktop_experience.aconfig +++ b/core/java/android/window/flags/lse_desktop_experience.aconfig @@ -95,6 +95,16 @@ flag { } } +flag { + name: "enable_accessible_custom_headers" + namespace: "lse_desktop_experience" + description: "Enables a11y-friendly custom header input handling" + bug: "339302584" + metadata { + purpose: PURPOSE_BUGFIX + } +} + flag { name: "enable_app_header_with_task_density" namespace: "lse_desktop_experience" diff --git a/core/java/android/window/flags/responsible_apis.aconfig b/core/java/android/window/flags/responsible_apis.aconfig index fd5de91c80ca29b1e358582d76f9daf01254db35..b2f125dd2821b19f955552f45d1448a850103539 100644 --- a/core/java/android/window/flags/responsible_apis.aconfig +++ b/core/java/android/window/flags/responsible_apis.aconfig @@ -15,13 +15,6 @@ flag { bug: "296478675" } -flag { - name: "bal_show_toasts" - namespace: "responsible_apis" - description: "Enable toasts to indicate (potential) BAL blocking." - bug: "308059069" -} - flag { name: "bal_show_toasts_blocked" namespace: "responsible_apis" @@ -64,14 +57,6 @@ flag { bug: "339720406" } -# replaced by bal_strict_mode_ro -flag { - name: "bal_strict_mode" - namespace: "responsible_apis" - description: "Strict mode flag" - bug: "324089586" -} - flag { name: "bal_strict_mode_ro" namespace: "responsible_apis" diff --git a/core/java/android/window/flags/window_surfaces.aconfig b/core/java/android/window/flags/window_surfaces.aconfig index 460df310348842123614be1bc4a4be93ca17d814..392c307de7ba7ce5864b8c5261f4470a09ba10ba 100644 --- a/core/java/android/window/flags/window_surfaces.aconfig +++ b/core/java/android/window/flags/window_surfaces.aconfig @@ -11,14 +11,6 @@ flag { bug: "292032926" } -flag { - namespace: "window_surfaces" - name: "explicit_refresh_rate_hints" - description: "Performance related hints during transitions" - is_fixed_read_only: true - bug: "300019131" -} - flag { namespace: "window_surfaces" name: "delete_capture_display" diff --git a/core/java/android/window/flags/windowing_frontend.aconfig b/core/java/android/window/flags/windowing_frontend.aconfig index 3a035087be7f2c8ec6bc21f06c422a45dcfa6600..68e78fed29c5e1a2d0a817349da9622d6b1f8d2a 100644 --- a/core/java/android/window/flags/windowing_frontend.aconfig +++ b/core/java/android/window/flags/windowing_frontend.aconfig @@ -48,6 +48,17 @@ flag { } } +flag { + name: "respect_animation_clip" + namespace: "windowing_frontend" + description: "Fix missing clip transformation of animation" + bug: "376601866" + is_fixed_read_only: true + metadata { + purpose: PURPOSE_BUGFIX + } +} + flag { name: "edge_to_edge_by_default" namespace: "windowing_frontend" @@ -64,6 +75,14 @@ flag { is_fixed_read_only: true } +flag { + name: "disable_opt_out_edge_to_edge" + namespace: "windowing_frontend" + description: "Deprecate and disable windowOptOutEdgeToEdgeEnforcement" + bug: "377864165" + is_fixed_read_only: true +} + flag { name: "keyguard_going_away_timeout" namespace: "windowing_frontend" @@ -349,6 +368,17 @@ flag { is_fixed_read_only: true } +flag { + name: "defer_predictive_animation_if_no_snapshot" + namespace: "windowing_frontend" + description: "If no snapshot for previous window, start animation until the client has draw." + bug: "374621014" + is_fixed_read_only: true + metadata { + purpose: PURPOSE_BUGFIX + } +} + flag { name: "disallow_app_progress_embedded_window" namespace: "windowing_frontend" @@ -358,4 +388,19 @@ flag { metadata { purpose: PURPOSE_BUGFIX } -} \ No newline at end of file +} + +flag { + name: "predictive_back_system_override_callback" + namespace: "windowing_frontend" + description: "Provide pre-make predictive back API extension" + is_fixed_read_only: true + bug: "362938401" +} + +flag { + name: "predictive_back_three_button_nav" + namespace: "systemui" + description: "Enable Predictive Back Animation for 3-button-nav" + bug: "373544911" +} diff --git a/core/java/com/android/internal/accessibility/common/ShortcutConstants.java b/core/java/com/android/internal/accessibility/common/ShortcutConstants.java index 44dceb9b7edb31cfae1241e61de16e53d8c389a0..4a49bb6720effd18801466e0060a9b8cdbff83ff 100644 --- a/core/java/com/android/internal/accessibility/common/ShortcutConstants.java +++ b/core/java/com/android/internal/accessibility/common/ShortcutConstants.java @@ -63,6 +63,8 @@ public final class ShortcutConstants { * quickly tapping screen 2 times with two fingers as preferred shortcut. * {@code QUICK_SETTINGS} for displaying specifying the accessibility services or features which * choose Quick Settings as preferred shortcut. + * {@code KEY_GESTURE} for shortcuts which are directly from key gestures and should be + * activated always. */ @Retention(RetentionPolicy.SOURCE) @IntDef({ @@ -73,6 +75,7 @@ public final class ShortcutConstants { UserShortcutType.TWOFINGER_DOUBLETAP, UserShortcutType.QUICK_SETTINGS, UserShortcutType.GESTURE, + UserShortcutType.KEY_GESTURE, UserShortcutType.ALL }) public @interface UserShortcutType { @@ -84,8 +87,10 @@ public final class ShortcutConstants { int TWOFINGER_DOUBLETAP = 1 << 3; int QUICK_SETTINGS = 1 << 4; int GESTURE = 1 << 5; + int KEY_GESTURE = 1 << 6; // LINT.ThenChange(:shortcut_type_array) - int ALL = SOFTWARE | HARDWARE | TRIPLETAP | TWOFINGER_DOUBLETAP | QUICK_SETTINGS | GESTURE; + int ALL = SOFTWARE | HARDWARE | TRIPLETAP | TWOFINGER_DOUBLETAP | QUICK_SETTINGS | GESTURE + | KEY_GESTURE; } /** @@ -99,7 +104,8 @@ public final class ShortcutConstants { UserShortcutType.TRIPLETAP, UserShortcutType.TWOFINGER_DOUBLETAP, UserShortcutType.QUICK_SETTINGS, - UserShortcutType.GESTURE + UserShortcutType.GESTURE, + UserShortcutType.KEY_GESTURE // LINT.ThenChange(:shortcut_type_intdef) }; diff --git a/core/java/com/android/internal/accessibility/util/ShortcutUtils.java b/core/java/com/android/internal/accessibility/util/ShortcutUtils.java index 2e0ff3db6c5073e223708a15f9e501152fc6d74e..14ca0f8cae69dd3aabd29594f1b335668dad6a51 100644 --- a/core/java/com/android/internal/accessibility/util/ShortcutUtils.java +++ b/core/java/com/android/internal/accessibility/util/ShortcutUtils.java @@ -27,6 +27,7 @@ import static com.android.internal.accessibility.common.ShortcutConstants.SERVIC import static com.android.internal.accessibility.common.ShortcutConstants.USER_SHORTCUT_TYPES; import static com.android.internal.accessibility.common.ShortcutConstants.UserShortcutType.GESTURE; import static com.android.internal.accessibility.common.ShortcutConstants.UserShortcutType.HARDWARE; +import static com.android.internal.accessibility.common.ShortcutConstants.UserShortcutType.KEY_GESTURE; import static com.android.internal.accessibility.common.ShortcutConstants.UserShortcutType.QUICK_SETTINGS; import static com.android.internal.accessibility.common.ShortcutConstants.UserShortcutType.SOFTWARE; import static com.android.internal.accessibility.common.ShortcutConstants.UserShortcutType.TRIPLETAP; @@ -187,6 +188,7 @@ public final class ShortcutUtils { case TWOFINGER_DOUBLETAP -> Settings.Secure.ACCESSIBILITY_MAGNIFICATION_TWO_FINGER_TRIPLE_TAP_ENABLED; case QUICK_SETTINGS -> Settings.Secure.ACCESSIBILITY_QS_TARGETS; + case KEY_GESTURE -> Settings.Secure.ACCESSIBILITY_KEY_GESTURE_TARGETS; default -> throw new IllegalArgumentException( "Unsupported user shortcut type: " + type); }; @@ -209,6 +211,7 @@ public final class ShortcutUtils { TRIPLETAP; case Settings.Secure.ACCESSIBILITY_MAGNIFICATION_TWO_FINGER_TRIPLE_TAP_ENABLED -> TWOFINGER_DOUBLETAP; + case Settings.Secure.ACCESSIBILITY_KEY_GESTURE_TARGETS -> KEY_GESTURE; default -> throw new IllegalArgumentException( "Unsupported user shortcut key: " + key); }; diff --git a/core/java/com/android/internal/compat/AndroidBuildClassifier.java b/core/java/com/android/internal/compat/AndroidBuildClassifier.java index 364db06976a0a0aac2f464a68482142f71b76fd9..19f8889996dcbc73d21e8e7f6e86bd2322ceccc0 100644 --- a/core/java/com/android/internal/compat/AndroidBuildClassifier.java +++ b/core/java/com/android/internal/compat/AndroidBuildClassifier.java @@ -22,6 +22,7 @@ import android.os.Build; * Platform private class for determining the type of Android build installed. * */ +@android.ravenwood.annotation.RavenwoodKeepWholeClass public class AndroidBuildClassifier { public boolean isDebuggableBuild() { diff --git a/core/java/com/android/internal/compat/ChangeReporter.java b/core/java/com/android/internal/compat/ChangeReporter.java index f61157175f9d8d0ec79a1b8be69bd0bdd1306061..f714098e8bc46e3eb2758555068a700f8a792e01 100644 --- a/core/java/com/android/internal/compat/ChangeReporter.java +++ b/core/java/com/android/internal/compat/ChangeReporter.java @@ -42,6 +42,7 @@ import java.util.function.Function; * * @hide */ +@android.ravenwood.annotation.RavenwoodKeepWholeClass public class ChangeReporter { private static final String TAG = "CompatChangeReporter"; private static final Function> NEW_CHANGE_REPORT_SET = diff --git a/core/java/com/android/internal/compat/CompatibilityChangeConfig.java b/core/java/com/android/internal/compat/CompatibilityChangeConfig.java index 182dba71d0d7fbd46c3e46594342d9750e5b7e79..8fd914aecf55791e1d87d3170b630d28ba41fa73 100644 --- a/core/java/com/android/internal/compat/CompatibilityChangeConfig.java +++ b/core/java/com/android/internal/compat/CompatibilityChangeConfig.java @@ -28,6 +28,7 @@ import java.util.Set; * Parcelable containing compat config overrides for a given application. * @hide */ +@android.ravenwood.annotation.RavenwoodKeepWholeClass public final class CompatibilityChangeConfig implements Parcelable { private final ChangeConfig mChangeConfig; diff --git a/core/java/com/android/internal/compat/CompatibilityChangeInfo.java b/core/java/com/android/internal/compat/CompatibilityChangeInfo.java index 03fe4551c249efdc14ee25bbbc49dbe93e790474..505fd2319a6b43fbc8bc736c264be35fbadfb4b1 100644 --- a/core/java/com/android/internal/compat/CompatibilityChangeInfo.java +++ b/core/java/com/android/internal/compat/CompatibilityChangeInfo.java @@ -25,6 +25,7 @@ import android.os.Parcelable; * * @hide */ +@android.ravenwood.annotation.RavenwoodKeepWholeClass public class CompatibilityChangeInfo implements Parcelable { private final long mChangeId; private final @Nullable String mName; diff --git a/core/java/com/android/internal/compat/CompatibilityOverrideConfig.java b/core/java/com/android/internal/compat/CompatibilityOverrideConfig.java index 9a02b7b7aae997a327d695bcafdb86679cdf5fae..32206c9950dd2afae911f1c5b0bc886feee04843 100644 --- a/core/java/com/android/internal/compat/CompatibilityOverrideConfig.java +++ b/core/java/com/android/internal/compat/CompatibilityOverrideConfig.java @@ -28,6 +28,7 @@ import java.util.Map; * Parcelable containing compat config overrides for a given application. * @hide */ +@android.ravenwood.annotation.RavenwoodKeepWholeClass public final class CompatibilityOverrideConfig implements Parcelable { public final Map overrides; diff --git a/core/java/com/android/internal/compat/CompatibilityOverridesByPackageConfig.java b/core/java/com/android/internal/compat/CompatibilityOverridesByPackageConfig.java index 8652bb6d05e4cf8c0f71103a8a6eac5a232e6d1c..998b48a8a76e0fa3f0c8452e37680eb541264b5f 100644 --- a/core/java/com/android/internal/compat/CompatibilityOverridesByPackageConfig.java +++ b/core/java/com/android/internal/compat/CompatibilityOverridesByPackageConfig.java @@ -26,6 +26,7 @@ import java.util.Map; * Parcelable containing compat config overrides by application. * @hide */ +@android.ravenwood.annotation.RavenwoodKeepWholeClass public final class CompatibilityOverridesByPackageConfig implements Parcelable { public final Map packageNameToOverrides; diff --git a/core/java/com/android/internal/compat/CompatibilityOverridesToRemoveByPackageConfig.java b/core/java/com/android/internal/compat/CompatibilityOverridesToRemoveByPackageConfig.java index b408d644007034a4748046143e5990b2ab97d59d..c0e2217d509e1940dc7bf12e6c4882fbe5828562 100644 --- a/core/java/com/android/internal/compat/CompatibilityOverridesToRemoveByPackageConfig.java +++ b/core/java/com/android/internal/compat/CompatibilityOverridesToRemoveByPackageConfig.java @@ -29,6 +29,7 @@ import java.util.Map; * IDs. * @hide */ +@android.ravenwood.annotation.RavenwoodKeepWholeClass public final class CompatibilityOverridesToRemoveByPackageConfig implements Parcelable { public final Map packageNameToOverridesToRemove; diff --git a/core/java/com/android/internal/compat/CompatibilityOverridesToRemoveConfig.java b/core/java/com/android/internal/compat/CompatibilityOverridesToRemoveConfig.java index e85afefdc39ac9cb0f59b5fde25b9283b6c36559..10461ec0b4c685fd01284b976ffab397f7366a5a 100644 --- a/core/java/com/android/internal/compat/CompatibilityOverridesToRemoveConfig.java +++ b/core/java/com/android/internal/compat/CompatibilityOverridesToRemoveConfig.java @@ -30,6 +30,7 @@ import java.util.Set; *

    This class is separate from CompatibilityOverrideConfig since we only need change IDs. * @hide */ +@android.ravenwood.annotation.RavenwoodKeepWholeClass public final class CompatibilityOverridesToRemoveConfig implements Parcelable { public final Set changeIds; diff --git a/core/java/com/android/internal/compat/OverrideAllowedState.java b/core/java/com/android/internal/compat/OverrideAllowedState.java index e408be2ab471cac444e0421e245337c4b24f25d3..f018c3a830bde4d20a16eedee3dd795341fe8eed 100644 --- a/core/java/com/android/internal/compat/OverrideAllowedState.java +++ b/core/java/com/android/internal/compat/OverrideAllowedState.java @@ -27,6 +27,7 @@ import java.lang.annotation.RetentionPolicy; /** * This class contains all the possible override allowed states. */ +@android.ravenwood.annotation.RavenwoodKeepWholeClass public final class OverrideAllowedState implements Parcelable { @IntDef({ ALLOWED, diff --git a/core/java/com/android/internal/display/BrightnessSynchronizer.java b/core/java/com/android/internal/display/BrightnessSynchronizer.java index 21fbf9d03c7118b993d36cbbc1065eecda38c832..a50dbb0223b7ea63343431a07ca7153d4931b210 100644 --- a/core/java/com/android/internal/display/BrightnessSynchronizer.java +++ b/core/java/com/android/internal/display/BrightnessSynchronizer.java @@ -600,8 +600,8 @@ public class BrightnessSynchronizer { final ContentResolver cr = mContext.getContentResolver(); cr.registerContentObserver(BRIGHTNESS_URI, false, createBrightnessContentObserver(handler), UserHandle.USER_ALL); - mDisplayManager.registerDisplayListener(mListener, handler, - DisplayManager.EVENT_FLAG_DISPLAY_BRIGHTNESS); + mDisplayManager.registerDisplayListener(mListener, handler, /* eventFlags */ 0, + DisplayManager.PRIVATE_EVENT_FLAG_DISPLAY_BRIGHTNESS); mIsObserving = true; } } diff --git a/core/java/com/android/internal/jank/DisplayResolutionTracker.java b/core/java/com/android/internal/jank/DisplayResolutionTracker.java index ca6c54dc02853d42df4eaca12f673c869289405f..0c2fd4bbd7aefd553b54aeffd9611b6e7ecb4796 100644 --- a/core/java/com/android/internal/jank/DisplayResolutionTracker.java +++ b/core/java/com/android/internal/jank/DisplayResolutionTracker.java @@ -147,8 +147,9 @@ public class DisplayResolutionTracker { @Override public void registerDisplayListener(DisplayManager.DisplayListener listener) { manager.registerDisplayListener(listener, handler, - DisplayManager.EVENT_FLAG_DISPLAY_ADDED - | DisplayManager.EVENT_FLAG_DISPLAY_CHANGED, + DisplayManagerGlobal.INTERNAL_EVENT_FLAG_DISPLAY_ADDED + | DisplayManagerGlobal + .INTERNAL_EVENT_FLAG_DISPLAY_CHANGED, ActivityThread.currentPackageName()); } diff --git a/core/java/com/android/internal/os/KernelSingleUidTimeReader.java b/core/java/com/android/internal/os/KernelSingleUidTimeReader.java index de3edeb22a40051e2aa80bec29c09666ec677d42..15736ed3f4e1ae4e962509fbf77174a8b56d1a12 100644 --- a/core/java/com/android/internal/os/KernelSingleUidTimeReader.java +++ b/core/java/com/android/internal/os/KernelSingleUidTimeReader.java @@ -18,14 +18,13 @@ package com.android.internal.os; import static com.android.internal.annotations.VisibleForTesting.Visibility.PACKAGE; import android.annotation.NonNull; +import android.annotation.Nullable; import android.util.Slog; import android.util.SparseArray; import com.android.internal.annotations.GuardedBy; import com.android.internal.annotations.VisibleForTesting; -import dalvik.annotation.optimization.CriticalNative; - import java.io.IOException; import java.nio.ByteBuffer; import java.nio.ByteOrder; @@ -255,8 +254,8 @@ public class KernelSingleUidTimeReader { * the delta in the supplied array container. */ public void addDelta(int uid, LongArrayMultiStateCounter counter, long timestampMs, - LongArrayMultiStateCounter.LongArrayContainer deltaContainer) { - mInjector.addDelta(uid, counter, timestampMs, deltaContainer); + long[] delta) { + mInjector.addDelta(uid, counter, timestampMs, delta); } @VisibleForTesting @@ -274,15 +273,13 @@ public class KernelSingleUidTimeReader { * The delta is also returned via the optional deltaOut parameter. */ public boolean addDelta(int uid, LongArrayMultiStateCounter counter, long timestampMs, - LongArrayMultiStateCounter.LongArrayContainer deltaOut) { - return addDeltaFromBpf(uid, counter.mNativeObject, timestampMs, - deltaOut != null ? deltaOut.mNativeObject : 0); + long[] deltaOut) { + return addDeltaFromBpf(uid, counter.mNativeObject, timestampMs, deltaOut); } - @CriticalNative private static native boolean addDeltaFromBpf(int uid, long longArrayMultiStateCounterNativePointer, long timestampMs, - long longArrayContainerNativePointer); + @Nullable long[] deltaOut); /** * Used for testing. @@ -291,14 +288,14 @@ public class KernelSingleUidTimeReader { */ public boolean addDeltaForTest(int uid, LongArrayMultiStateCounter counter, long timestampMs, long[][] timeInFreqDataNanos, - LongArrayMultiStateCounter.LongArrayContainer deltaOut) { + long[] deltaOut) { return addDeltaForTest(uid, counter.mNativeObject, timestampMs, timeInFreqDataNanos, - deltaOut != null ? deltaOut.mNativeObject : 0); + deltaOut); } private static native boolean addDeltaForTest(int uid, long longArrayMultiStateCounterNativePointer, long timestampMs, - long[][] timeInFreqDataNanos, long longArrayContainerNativePointer); + long[][] timeInFreqDataNanos, long[] deltaOut); } @VisibleForTesting diff --git a/core/java/com/android/internal/os/LongArrayMultiStateCounter.java b/core/java/com/android/internal/os/LongArrayMultiStateCounter.java index 489721fbc10e481b2144ef81a3cea7e577813e7e..2931bd2c83dd72ccaf5048a8c835e334846ce057 100644 --- a/core/java/com/android/internal/os/LongArrayMultiStateCounter.java +++ b/core/java/com/android/internal/os/LongArrayMultiStateCounter.java @@ -30,9 +30,6 @@ import dalvik.annotation.optimization.FastNative; import libcore.util.NativeAllocationRegistry; -import java.util.Arrays; -import java.util.concurrent.atomic.AtomicReference; - /** * Performs per-state counting of multi-element values over time. The class' behavior is illustrated * by this example: @@ -44,15 +41,14 @@ import java.util.concurrent.atomic.AtomicReference; * counter.setState(1, 1000); * * // At 3000 ms, the tracked values are updated to {30, 300} - * arrayContainer.setValues(new long[]{{30, 300}}; - * counter.updateValues(arrayContainer, 3000); + * counter.updateValues(arrayContainer, new long[]{{30, 300}, 3000); * * // The values are distributed between states 0 and 1 according to the time * // spent in those respective states. In this specific case, 1000 and 2000 ms. - * counter.getValues(arrayContainer, 0); - * // arrayContainer now has values {10, 100} - * counter.getValues(arrayContainer, 1); - * // arrayContainer now has values {20, 200} + * counter.getCounts(array, 0); + * // array now has values {10, 100} + * counter.getCounts(array, 1); + * // array now has values {20, 200} *

  • * * The tracked values are expected to increase monotonically. @@ -60,112 +56,9 @@ import java.util.concurrent.atomic.AtomicReference; * @hide */ @RavenwoodKeepWholeClass -@RavenwoodRedirectionClass("LongArrayMultiStateCounter_host") +@RavenwoodRedirectionClass("LongArrayMultiStateCounter_ravenwood") public final class LongArrayMultiStateCounter implements Parcelable { - - /** - * Container for a native equivalent of a long[]. - */ - @RavenwoodKeepWholeClass - @RavenwoodRedirectionClass("LongArrayContainer_host") - public static class LongArrayContainer { - private static NativeAllocationRegistry sRegistry; - - // Visible to other objects in this package so that it can be passed to @CriticalNative - // methods. - final long mNativeObject; - private final int mLength; - - public LongArrayContainer(int length) { - mLength = length; - mNativeObject = native_init(length); - registerNativeAllocation(); - } - - @RavenwoodReplace - private void registerNativeAllocation() { - if (sRegistry == null) { - synchronized (LongArrayMultiStateCounter.class) { - if (sRegistry == null) { - sRegistry = NativeAllocationRegistry.createMalloced( - LongArrayContainer.class.getClassLoader(), native_getReleaseFunc()); - } - } - } - sRegistry.registerNativeAllocation(this, mNativeObject); - } - - private void registerNativeAllocation$ravenwood() { - // No-op under ravenwood - } - - /** - * Copies the supplied values into the underlying native array. - */ - public void setValues(long[] array) { - if (array.length != mLength) { - throw new IllegalArgumentException( - "Invalid array length: " + array.length + ", expected: " + mLength); - } - native_setValues(mNativeObject, array); - } - - /** - * Copies the underlying native array values to the supplied array. - */ - public void getValues(long[] array) { - if (array.length != mLength) { - throw new IllegalArgumentException( - "Invalid array length: " + array.length + ", expected: " + mLength); - } - native_getValues(mNativeObject, array); - } - - /** - * Combines contained values into a smaller array by aggregating them - * according to an index map. - */ - public boolean combineValues(long[] array, int[] indexMap) { - if (indexMap.length != mLength) { - throw new IllegalArgumentException( - "Wrong index map size " + indexMap.length + ", expected " + mLength); - } - return native_combineValues(mNativeObject, array, indexMap); - } - - @Override - public String toString() { - final long[] array = new long[mLength]; - getValues(array); - return Arrays.toString(array); - } - - @CriticalNative - @RavenwoodRedirect - private static native long native_init(int length); - - @CriticalNative - @RavenwoodRedirect - private static native long native_getReleaseFunc(); - - @FastNative - @RavenwoodRedirect - private static native void native_setValues(long nativeObject, long[] array); - - @FastNative - @RavenwoodRedirect - private static native void native_getValues(long nativeObject, long[] array); - - @FastNative - @RavenwoodRedirect - private static native boolean native_combineValues(long nativeObject, long[] array, - int[] indexMap); - } - private static volatile NativeAllocationRegistry sRegistry; - private static final AtomicReference sTmpArrayContainer = - new AtomicReference<>(); - private final int mStateCount; private final int mLength; @@ -257,41 +150,14 @@ public final class LongArrayMultiStateCounter implements Parcelable { throw new IllegalArgumentException( "Invalid array length: " + values.length + ", expected: " + mLength); } - LongArrayContainer container = sTmpArrayContainer.getAndSet(null); - if (container == null || container.mLength != values.length) { - container = new LongArrayContainer(values.length); - } - container.setValues(values); - native_setValues(mNativeObject, state, container.mNativeObject); - sTmpArrayContainer.set(container); - } - - /** - * Sets the new values. The delta between the previously set values and these values - * is distributed among the state according to the time the object spent in those states - * since the previous call to updateValues. - */ - public void updateValues(long[] values, long timestampMs) { - LongArrayContainer container = sTmpArrayContainer.getAndSet(null); - if (container == null || container.mLength != values.length) { - container = new LongArrayContainer(values.length); - } - container.setValues(values); - updateValues(container, timestampMs); - sTmpArrayContainer.set(container); + native_setValues(mNativeObject, state, values); } /** * Adds the supplied values to the current accumulated values in the counter. */ public void incrementValues(long[] values, long timestampMs) { - LongArrayContainer container = sTmpArrayContainer.getAndSet(null); - if (container == null || container.mLength != values.length) { - container = new LongArrayContainer(values.length); - } - container.setValues(values); - native_incrementValues(mNativeObject, container.mNativeObject, timestampMs); - sTmpArrayContainer.set(container); + native_incrementValues(mNativeObject, values, timestampMs); } /** @@ -299,24 +165,23 @@ public final class LongArrayMultiStateCounter implements Parcelable { * is distributed among the state according to the time the object spent in those states * since the previous call to updateValues. */ - public void updateValues(LongArrayContainer longArrayContainer, long timestampMs) { - if (longArrayContainer.mLength != mLength) { + public void updateValues(long[] values, long timestampMs) { + if (values.length != mLength) { throw new IllegalArgumentException( - "Invalid array length: " + longArrayContainer.mLength + ", expected: " - + mLength); + "Invalid array length: " + values.length + ", expected: " + mLength); } - native_updateValues(mNativeObject, longArrayContainer.mNativeObject, timestampMs); + native_updateValues(mNativeObject, values, timestampMs); } /** * Adds the supplied values to the current accumulated values in the counter. */ - public void addCounts(LongArrayContainer counts) { - if (counts.mLength != mLength) { + public void addCounts(long[] counts) { + if (counts.length != mLength) { throw new IllegalArgumentException( - "Invalid array length: " + counts.mLength + ", expected: " + mLength); + "Invalid array length: " + counts.length + ", expected: " + mLength); } - native_addCounts(mNativeObject, counts.mNativeObject); + native_addCounts(mNativeObject, counts); } /** @@ -330,29 +195,15 @@ public final class LongArrayMultiStateCounter implements Parcelable { * Populates the array with the accumulated counts for the specified state. */ public void getCounts(long[] counts, int state) { - LongArrayContainer container = sTmpArrayContainer.getAndSet(null); - if (container == null || container.mLength != counts.length) { - container = new LongArrayContainer(counts.length); - } - getCounts(container, state); - container.getValues(counts); - sTmpArrayContainer.set(container); - } - - /** - * Populates longArrayContainer with the accumulated counts for the specified state. - */ - public void getCounts(LongArrayContainer longArrayContainer, int state) { if (state < 0 || state >= mStateCount) { throw new IllegalArgumentException( "State: " + state + ", outside the range: [0-" + mStateCount + "]"); } - if (longArrayContainer.mLength != mLength) { + if (counts.length != mLength) { throw new IllegalArgumentException( - "Invalid array length: " + longArrayContainer.mLength - + ", expected: " + mLength); + "Invalid array length: " + counts.length + ", expected: " + mLength); } - native_getCounts(mNativeObject, longArrayContainer.mNativeObject, state); + native_getCounts(mNativeObject, counts, state); } @Override @@ -370,18 +221,17 @@ public final class LongArrayMultiStateCounter implements Parcelable { return 0; } - public static final Creator CREATOR = - new Creator() { - @Override - public LongArrayMultiStateCounter createFromParcel(Parcel in) { - return new LongArrayMultiStateCounter(in); - } + public static final Creator CREATOR = new Creator<>() { + @Override + public LongArrayMultiStateCounter createFromParcel(Parcel in) { + return new LongArrayMultiStateCounter(in); + } - @Override - public LongArrayMultiStateCounter[] newArray(int size) { - return new LongArrayMultiStateCounter[size]; - } - }; + @Override + public LongArrayMultiStateCounter[] newArray(int size) { + return new LongArrayMultiStateCounter[size]; + } + }; @CriticalNative @@ -406,34 +256,31 @@ public final class LongArrayMultiStateCounter implements Parcelable { private static native void native_copyStatesFrom(long nativeObjectTarget, long nativeObjectSource); - @CriticalNative + @FastNative @RavenwoodRedirect - private static native void native_setValues(long nativeObject, int state, - long longArrayContainerNativeObject); + private static native void native_setValues(long nativeObject, int state, long[] values); - @CriticalNative + @FastNative @RavenwoodRedirect - private static native void native_updateValues(long nativeObject, - long longArrayContainerNativeObject, long timestampMs); + private static native void native_updateValues(long nativeObject, long[] values, + long timestampMs); - @CriticalNative + @FastNative @RavenwoodRedirect - private static native void native_incrementValues(long nativeObject, - long longArrayContainerNativeObject, long timestampMs); + private static native void native_incrementValues(long nativeObject, long[] values, + long timestampMs); - @CriticalNative + @FastNative @RavenwoodRedirect - private static native void native_addCounts(long nativeObject, - long longArrayContainerNativeObject); + private static native void native_addCounts(long nativeObject, long[] counts); @CriticalNative @RavenwoodRedirect private static native void native_reset(long nativeObject); - @CriticalNative + @FastNative @RavenwoodRedirect - private static native void native_getCounts(long nativeObject, - long longArrayContainerNativeObject, int state); + private static native void native_getCounts(long nativeObject, long[] counts, int state); @FastNative @RavenwoodRedirect diff --git a/ravenwood/runtime-helper-src/framework/com/android/internal/os/LongArrayMultiStateCounter_host.java b/core/java/com/android/internal/os/LongArrayMultiStateCounter_ravenwood.java similarity index 92% rename from ravenwood/runtime-helper-src/framework/com/android/internal/os/LongArrayMultiStateCounter_host.java rename to core/java/com/android/internal/os/LongArrayMultiStateCounter_ravenwood.java index 9ce8ea8e16eface3a60e2a2cd53eb11f28e41c9b..7030d8e84b709d384db11ae5fa7e84e1b708f380 100644 --- a/ravenwood/runtime-helper-src/framework/com/android/internal/os/LongArrayMultiStateCounter_host.java +++ b/core/java/com/android/internal/os/LongArrayMultiStateCounter_ravenwood.java @@ -18,6 +18,7 @@ package com.android.internal.os; import android.os.BadParcelableException; import android.os.Parcel; +import android.ravenwood.annotation.RavenwoodKeepWholeClass; import java.util.Arrays; import java.util.HashMap; @@ -25,7 +26,8 @@ import java.util.HashMap; /** * Native implementation substitutions for the LongArrayMultiStateCounter class. */ -public class LongArrayMultiStateCounter_host { +@RavenwoodKeepWholeClass +class LongArrayMultiStateCounter_ravenwood { /** * A reimplementation of {@link LongArrayMultiStateCounter}, only in @@ -286,15 +288,12 @@ public class LongArrayMultiStateCounter_host { return getInstance(instanceId).mArrayLength; } - public static void native_setValues(long instanceId, int state, long containerInstanceId) { - getInstance(instanceId).setValue(state, - LongArrayContainer_host.getInstance(containerInstanceId)); + public static void native_setValues(long instanceId, int state, long[] values) { + getInstance(instanceId).setValue(state, values); } - public static void native_updateValues(long instanceId, long containerInstanceId, - long timestampMs) { - getInstance(instanceId).updateValue( - LongArrayContainer_host.getInstance(containerInstanceId), timestampMs); + public static void native_updateValues(long instanceId, long[] values, long timestampMs) { + getInstance(instanceId).updateValue(values, timestampMs); } public static void native_setState(long instanceId, int state, long timestampMs) { @@ -305,19 +304,16 @@ public class LongArrayMultiStateCounter_host { getInstance(targetInstanceId).copyStatesFrom(getInstance(sourceInstanceId)); } - public static void native_incrementValues(long instanceId, long containerInstanceId, - long timestampMs) { - getInstance(instanceId).incrementValues( - LongArrayContainer_host.getInstance(containerInstanceId), timestampMs); + public static void native_incrementValues(long instanceId, long[] delta, long timestampMs) { + getInstance(instanceId).incrementValues(delta, timestampMs); } - public static void native_addCounts(long instanceId, long containerInstanceId) { - getInstance(instanceId).addCounts(LongArrayContainer_host.getInstance(containerInstanceId)); + public static void native_addCounts(long instanceId, long[] counts) { + getInstance(instanceId).addCounts(counts); } - public static void native_getCounts(long instanceId, long containerInstanceId, int state) { - getInstance(instanceId).getValues(LongArrayContainer_host.getInstance(containerInstanceId), - state); + public static void native_getCounts(long instanceId, long[] counts, int state) { + getInstance(instanceId).getValues(counts, state); } public static void native_reset(long instanceId) { diff --git a/core/java/com/android/internal/os/LongMultiStateCounter.java b/core/java/com/android/internal/os/LongMultiStateCounter.java index c386a86f590638c0c5a68d8f961e0816ef561d16..ee855d58c874c419fa97eba619acf2adb123fcd8 100644 --- a/core/java/com/android/internal/os/LongMultiStateCounter.java +++ b/core/java/com/android/internal/os/LongMultiStateCounter.java @@ -60,7 +60,7 @@ import libcore.util.NativeAllocationRegistry; * @hide */ @RavenwoodKeepWholeClass -@RavenwoodRedirectionClass("LongMultiStateCounter_host") +@RavenwoodRedirectionClass("LongMultiStateCounter_ravenwood") public final class LongMultiStateCounter implements Parcelable { private static NativeAllocationRegistry sRegistry; diff --git a/ravenwood/runtime-helper-src/framework/com/android/internal/os/LongMultiStateCounter_host.java b/core/java/com/android/internal/os/LongMultiStateCounter_ravenwood.java similarity index 98% rename from ravenwood/runtime-helper-src/framework/com/android/internal/os/LongMultiStateCounter_host.java rename to core/java/com/android/internal/os/LongMultiStateCounter_ravenwood.java index 1d95aa143549c9b1c4f81638137f5205776051a4..42db37f1f82f115a433c72cbc7d0b5ac2620b4c6 100644 --- a/ravenwood/runtime-helper-src/framework/com/android/internal/os/LongMultiStateCounter_host.java +++ b/core/java/com/android/internal/os/LongMultiStateCounter_ravenwood.java @@ -18,13 +18,15 @@ package com.android.internal.os; import android.os.BadParcelableException; import android.os.Parcel; +import android.ravenwood.annotation.RavenwoodKeepWholeClass; import java.util.HashMap; /** * Native implementation substitutions for the LongMultiStateCounter class. */ -public class LongMultiStateCounter_host { +@RavenwoodKeepWholeClass +class LongMultiStateCounter_ravenwood { /** * A reimplementation of {@link com.android.internal.os.LongMultiStateCounter}, only in diff --git a/core/java/com/android/internal/ravenwood/RavenwoodEnvironment.java b/core/java/com/android/internal/ravenwood/RavenwoodEnvironment.java index 30b160ab161bc236f4cca7df7bf7cf20adc4dec3..3303d875c4279d5987ee3463060ad827c5f07bb9 100644 --- a/core/java/com/android/internal/ravenwood/RavenwoodEnvironment.java +++ b/core/java/com/android/internal/ravenwood/RavenwoodEnvironment.java @@ -15,6 +15,12 @@ */ package com.android.internal.ravenwood; +import static android.os.Build.VERSION_CODES.S; +import static android.os.Build.VERSION_CODES.UPSIDE_DOWN_CAKE; + +import android.compat.annotation.ChangeId; +import android.compat.annotation.Disabled; +import android.compat.annotation.EnabledAfter; import android.ravenwood.annotation.RavenwoodKeepWholeClass; import android.ravenwood.annotation.RavenwoodRedirect; import android.ravenwood.annotation.RavenwoodRedirectionClass; @@ -28,19 +34,9 @@ import android.ravenwood.annotation.RavenwoodReplace; public final class RavenwoodEnvironment { public static final String TAG = "RavenwoodEnvironment"; - private static final RavenwoodEnvironment sInstance; - private static final Workaround sWorkaround; - - private RavenwoodEnvironment() { - } - - static { - sInstance = new RavenwoodEnvironment(); - sWorkaround = new Workaround(); - ensureRavenwoodInitialized(); - } + private static RavenwoodEnvironment sInstance = new RavenwoodEnvironment(); - public static RuntimeException notSupportedOnDevice() { + private static RuntimeException notSupportedOnDevice() { return new UnsupportedOperationException("This method can only be used on Ravenwood"); } @@ -51,15 +47,6 @@ public final class RavenwoodEnvironment { return sInstance; } - /** - * Initialize the ravenwood environment if it hasn't happened already, if running on Ravenwood. - * - * No-op if called on the device side. - */ - @RavenwoodRedirect - public static void ensureRavenwoodInitialized() { - } - /** * USE IT SPARINGLY! Returns true if it's running on Ravenwood, hostside test environment. * @@ -90,18 +77,6 @@ public final class RavenwoodEnvironment { throw notSupportedOnDevice(); } - /** - * See {@link Workaround}. It's only usable on Ravenwood. - */ - @RavenwoodReplace - public static Workaround workaround() { - throw notSupportedOnDevice(); - } - - private static Workaround workaround$ravenwood() { - return sWorkaround; - } - /** * @return the "ravenwood-runtime" directory. */ @@ -110,19 +85,19 @@ public final class RavenwoodEnvironment { throw notSupportedOnDevice(); } - /** - * A set of APIs used to work around missing features on Ravenwood. Ideally, this class should - * be empty, and all its APIs should be able to be implemented properly. - */ - public static class Workaround { - Workaround() { - } + /** @hide */ + public static class CompatIdsForTest { + // Enabled by default + @ChangeId + public static final long TEST_COMPAT_ID_1 = 368131859L; + + @Disabled + @ChangeId public static final long TEST_COMPAT_ID_2 = 368131701L; + + @EnabledAfter(targetSdkVersion = S) + @ChangeId public static final long TEST_COMPAT_ID_3 = 368131659L; - /** - * @return whether the app's target SDK level is at least Q. - */ - public boolean isTargetSdkAtLeastQ() { - return true; - } + @EnabledAfter(targetSdkVersion = UPSIDE_DOWN_CAKE) + @ChangeId public static final long TEST_COMPAT_ID_4 = 368132057L; } } diff --git a/core/java/com/android/internal/statusbar/StatusBarIcon.java b/core/java/com/android/internal/statusbar/StatusBarIcon.java index 1938cdb0ba847f8fd5c5aeec8c3d4ba516c3a329..40161023eae425f559a81ab6336ea922980f7882 100644 --- a/core/java/com/android/internal/statusbar/StatusBarIcon.java +++ b/core/java/com/android/internal/statusbar/StatusBarIcon.java @@ -40,9 +40,6 @@ public class StatusBarIcon implements Parcelable { public enum Type { // Notification: the sender avatar for important conversations PeopleAvatar, - // Notification: the monochrome version of the app icon if available; otherwise fall back to - // the small icon - MaybeMonochromeAppIcon, // Notification: the small icon from the notification NotifSmallIcon, // The wi-fi, cellular or battery icon. diff --git a/core/java/com/android/internal/telephony/IPhoneStateListener.aidl b/core/java/com/android/internal/telephony/IPhoneStateListener.aidl index b5c87868af1223112d160fa2fec2d1ec1897f2a8..0e85e046e1b68691de6bc21430600aaf81a09891 100644 --- a/core/java/com/android/internal/telephony/IPhoneStateListener.aidl +++ b/core/java/com/android/internal/telephony/IPhoneStateListener.aidl @@ -27,6 +27,7 @@ import android.telephony.PhoneCapability; import android.telephony.PhysicalChannelConfig; import android.telephony.PreciseCallState; import android.telephony.PreciseDataConnectionState; +import android.telephony.satellite.NtnSignalStrength; import android.telephony.ServiceState; import android.telephony.SignalStrength; import android.telephony.emergency.EmergencyNumber; @@ -85,4 +86,5 @@ oneway interface IPhoneStateListener { void onCarrierRoamingNtnModeChanged(in boolean active); void onCarrierRoamingNtnEligibleStateChanged(in boolean eligible); void onCarrierRoamingNtnAvailableServicesChanged(in int[] availableServices); + void onCarrierRoamingNtnSignalStrengthChanged(in NtnSignalStrength ntnSignalStrength); } diff --git a/core/java/com/android/internal/telephony/ITelephonyRegistry.aidl b/core/java/com/android/internal/telephony/ITelephonyRegistry.aidl index 1c76a6cd4bba241c0f6e4ebbb268fa37011c745c..0f268d5de62bab58a5d00458d2c5ae8b9ab3944a 100644 --- a/core/java/com/android/internal/telephony/ITelephonyRegistry.aidl +++ b/core/java/com/android/internal/telephony/ITelephonyRegistry.aidl @@ -29,6 +29,7 @@ import android.telephony.ims.ImsReasonInfo; import android.telephony.PhoneCapability; import android.telephony.PhysicalChannelConfig; import android.telephony.PreciseDataConnectionState; +import android.telephony.satellite.NtnSignalStrength; import android.telephony.ServiceState; import android.telephony.SignalStrength; import android.telephony.emergency.EmergencyNumber; @@ -125,8 +126,10 @@ interface ITelephonyRegistry { void notifyCarrierRoamingNtnModeChanged(int subId, in boolean active); void notifyCarrierRoamingNtnEligibleStateChanged(int subId, in boolean eligible); void notifyCarrierRoamingNtnAvailableServicesChanged(int subId, in int[] availableServices); + void notifyCarrierRoamingNtnSignalStrengthChanged(int subId, in NtnSignalStrength ntnSignalStrength); void addSatelliteStateChangeListener(ISatelliteStateChangeListener listener, String pkg, String featureId); void removeSatelliteStateChangeListener(ISatelliteStateChangeListener listener, String pkg); void notifySatelliteStateChanged(boolean isEnabled); + } diff --git a/core/java/com/android/internal/widget/NotificationProgressDrawable.java b/core/java/com/android/internal/widget/NotificationProgressDrawable.java index 30deb499594cd0667e70cb45e56a094bb2d92293..fb6937c94a3e1867f263b4cd9036f6d887d627cb 100644 --- a/core/java/com/android/internal/widget/NotificationProgressDrawable.java +++ b/core/java/com/android/internal/widget/NotificationProgressDrawable.java @@ -63,6 +63,7 @@ public final class NotificationProgressDrawable extends Drawable { private final ArrayList mParts = new ArrayList<>(); + private final RectF mSegRectF = new RectF(); private final Rect mPointRect = new Rect(); private final RectF mPointRectF = new RectF(); @@ -198,22 +199,42 @@ public final class NotificationProgressDrawable extends Drawable { mState.mSegSegGap, x + segWidth, totalWidth); final float end = x + segWidth - endOffset; - // Transparent is not allowed (and also is the default in the data), so use that - // as a sentinel to be replaced by default - mStrokePaint.setColor(segment.mColor != Color.TRANSPARENT ? segment.mColor - : mState.mStrokeColor); - mDashedStrokePaint.setColor(segment.mColor != Color.TRANSPARENT ? segment.mColor - : mState.mFadedStrokeColor); - - // Leave space for the rounded line cap which extends beyond start/end. - final float capWidth = mStrokePaint.getStrokeWidth() / 2F; - - canvas.drawLine(start + capWidth, centerY, end - capWidth, centerY, - segment.mDashed ? mDashedStrokePaint : mStrokePaint); - // Advance the current position to account for the segment's fraction of the total // width (ignoring offset and padding) x += segWidth; + + // No space left to draw the segment + if (start > end) continue; + + if (segment.mDashed) { + // No caps when the segment is dashed. + + mDashedStrokePaint.setColor(segment.mColor != Color.TRANSPARENT ? segment.mColor + : mState.mFadedStrokeColor); + canvas.drawLine(start, centerY, end, centerY, mDashedStrokePaint); + } else if (end - start < mState.mStrokeWidth) { + // Not enough segment length to draw the caps + + final float rad = (end - start) / 2F; + final float capWidth = mStrokePaint.getStrokeWidth() / 2F; + + mFillPaint.setColor(segment.mColor != Color.TRANSPARENT ? segment.mColor + : mState.mStrokeColor); + + mSegRectF.set(start, centerY - capWidth, end, centerY + capWidth); + canvas.drawRoundRect(mSegRectF, rad, rad, mFillPaint); + } else { + // Leave space for the rounded line cap which extends beyond start/end. + final float capWidth = mStrokePaint.getStrokeWidth() / 2F; + + // Transparent is not allowed (and also is the default in the data), so use that + // as a sentinel to be replaced by default + mStrokePaint.setColor(segment.mColor != Color.TRANSPARENT ? segment.mColor + : mState.mStrokeColor); + + canvas.drawLine(start + capWidth, centerY, end - capWidth, centerY, + mStrokePaint); + } } else if (part instanceof Point point) { final float pointWidth = 2 * pointRadius; float start = x - pointRadius; @@ -232,7 +253,7 @@ public final class NotificationProgressDrawable extends Drawable { } else { // TODO: b/367804171 - actually use a vector asset for the default point // rather than drawing it as a box? - mPointRectF.set(mPointRect); + mPointRectF.set(start, centerY - pointRadius, end, centerY + pointRadius); final float inset = mState.mPointRectInset; final float cornerRadius = mState.mPointRectCornerRadius; mPointRectF.inset(inset, inset); diff --git a/core/java/com/android/internal/widget/NotificationRowIconView.java b/core/java/com/android/internal/widget/NotificationRowIconView.java index adcc0f64b598098c7fae4dbdd108e276ee23a20c..5fc61b00e331401256000dceb3f1177c1b70affe 100644 --- a/core/java/com/android/internal/widget/NotificationRowIconView.java +++ b/core/java/com/android/internal/widget/NotificationRowIconView.java @@ -22,11 +22,7 @@ import android.content.Context; import android.graphics.Bitmap; import android.graphics.BitmapShader; import android.graphics.Canvas; -import android.graphics.Color; -import android.graphics.ColorFilter; import android.graphics.Paint; -import android.graphics.PorterDuff; -import android.graphics.PorterDuffColorFilter; import android.graphics.Rect; import android.graphics.drawable.BitmapDrawable; import android.graphics.drawable.Drawable; @@ -35,8 +31,6 @@ import android.util.AttributeSet; import android.view.RemotableViewMethod; import android.widget.RemoteViews; -import com.android.internal.R; - /** * An image view that holds the icon displayed at the start of a notification row. * This can generally either display the "small icon" of a notification set via @@ -48,7 +42,6 @@ public class NotificationRowIconView extends CachingIconView { private NotificationIconProvider mIconProvider; private boolean mApplyCircularCrop = false; - private boolean mShouldShowAppIcon = false; private Drawable mAppIcon = null; // Padding, background and colors set on the view prior to being overridden when showing the app @@ -77,17 +70,6 @@ public class NotificationRowIconView extends CachingIconView { super(context, attrs, defStyleAttr, defStyleRes); } - @Override - protected void onFinishInflate() { - // If showing the app icon, we don't need background or padding. - if (Flags.notificationsUseAppIcon()) { - setPadding(0, 0, 0, 0); - setBackground(null); - } - - super.onFinishInflate(); - } - /** * Sets the icon provider for this view. This is used to determine whether we should show the * app icon instead of the small icon, and to fetch the app icon if needed. @@ -153,37 +135,12 @@ public class NotificationRowIconView extends CachingIconView { return super.setImageIconAsync(icon); } - /** Whether the icon represents the app icon (instead of the small icon). */ - @RemotableViewMethod - public void setShouldShowAppIcon(boolean shouldShowAppIcon) { - if (Flags.notificationsUseAppIconInRow()) { - if (mShouldShowAppIcon == shouldShowAppIcon) { - return; // no change - } - - mShouldShowAppIcon = shouldShowAppIcon; - if (mShouldShowAppIcon) { - adjustViewForAppIcon(); - } else { - // Restore original padding and background if needed - restoreViewForSmallIcon(); - } - } - } - /** * Override padding and background from the view to display the app icon. */ private void adjustViewForAppIcon() { removePadding(); - - if (Flags.notificationsUseAppIconInRow()) { - addWhiteBackground(); - } else { - // No need to set the background for notification redesign, since the icon - // factory already does that for us. - removeBackground(); - } + removeBackground(); } /** @@ -221,21 +178,6 @@ public class NotificationRowIconView extends CachingIconView { setBackground(null); } - private void addWhiteBackground() { - if (mOriginalBackground == null) { - mOriginalBackground = getBackground(); - } - - // Make the background white in case the icon itself doesn't have one. - ColorFilter colorFilter = new PorterDuffColorFilter(Color.WHITE, - PorterDuff.Mode.SRC_ATOP); - - if (mOriginalBackground == null) { - setBackground(getContext().getDrawable(R.drawable.notification_icon_circle)); - } - getBackground().mutate().setColorFilter(colorFilter); - } - private void restoreBackground() { // NOTE: This will not work if the original background was null, but that's better than // accidentally clearing the background. We expect that there's generally going to be one diff --git a/core/java/com/android/internal/widget/floatingtoolbar/LocalFloatingToolbarPopup.java b/core/java/com/android/internal/widget/floatingtoolbar/LocalFloatingToolbarPopup.java index b6383d9f0754fccceefd08499cf3a0e615ebea96..38685b652c5081e5c576a03dfc9c1f2bda723ce7 100644 --- a/core/java/com/android/internal/widget/floatingtoolbar/LocalFloatingToolbarPopup.java +++ b/core/java/com/android/internal/widget/floatingtoolbar/LocalFloatingToolbarPopup.java @@ -530,8 +530,26 @@ public final class LocalFloatingToolbarPopup implements FloatingToolbarPopup { int rootViewTopOnWindow = mTmpCoords[1]; int windowLeftOnScreen = rootViewLeftOnScreen - rootViewLeftOnWindow; int windowTopOnScreen = rootViewTopOnScreen - rootViewTopOnWindow; - mCoordsOnWindow.set( - Math.max(0, x - windowLeftOnScreen), Math.max(0, y - windowTopOnScreen)); + // In some cases, app can have specific Window for Android UI components such as EditText. + // In this case, Window bounds != App bounds. Hence, instead of ensuring non-negative + // PopupWindow coords, app bounds should be used to limit the coords. For instance, + // ____ <- | + // | | |W1 & App bounds + // |___| | + // |W2 | | W2 has smaller bounds and contain EditText where PopupWindow will be opened. + // ---- <-| + // Here, we'll open PopupWindow upwards, but as PopupWindow is anchored based on W2, it + // will have negative Y coords. This negative Y is safe to use because it's still within app + // bounds. However, if it gets out of app bounds, we should clamp it to 0. + Rect appBounds = mContext + .getResources().getConfiguration().windowConfiguration.getAppBounds(); + mCoordsOnWindow.set(x - windowLeftOnScreen, y - windowTopOnScreen); + if (rootViewLeftOnScreen + mCoordsOnWindow.x < appBounds.left) { + mCoordsOnWindow.x = 0; + } + if (rootViewTopOnScreen + mCoordsOnWindow.y < appBounds.top) { + mCoordsOnWindow.y = 0; + } } /** 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 212df02b1bd32ba0641261d5b4fe9acf05cc98b5..0761a244b9f2119604e4f92087a93b376f9dbfa8 100644 --- a/core/java/com/android/internal/widget/remotecompose/core/CoreDocument.java +++ b/core/java/com/android/internal/widget/remotecompose/core/CoreDocument.java @@ -15,12 +15,14 @@ */ package com.android.internal.widget.remotecompose.core; +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.IntegerExpression; import com.android.internal.widget.remotecompose.core.operations.NamedVariable; import com.android.internal.widget.remotecompose.core.operations.RootContentBehavior; import com.android.internal.widget.remotecompose.core.operations.Theme; -import com.android.internal.widget.remotecompose.core.operations.layout.ClickModifierEnd; import com.android.internal.widget.remotecompose.core.operations.layout.ClickModifierOperation; import com.android.internal.widget.remotecompose.core.operations.layout.Component; import com.android.internal.widget.remotecompose.core.operations.layout.ComponentEnd; @@ -28,7 +30,11 @@ import com.android.internal.widget.remotecompose.core.operations.layout.Componen import com.android.internal.widget.remotecompose.core.operations.layout.LayoutComponent; import com.android.internal.widget.remotecompose.core.operations.layout.LoopEnd; import com.android.internal.widget.remotecompose.core.operations.layout.LoopOperation; +import com.android.internal.widget.remotecompose.core.operations.layout.OperationsListEnd; import com.android.internal.widget.remotecompose.core.operations.layout.RootLayoutComponent; +import com.android.internal.widget.remotecompose.core.operations.layout.TouchCancelModifierOperation; +import com.android.internal.widget.remotecompose.core.operations.layout.TouchDownModifierOperation; +import com.android.internal.widget.remotecompose.core.operations.layout.TouchUpModifierOperation; import com.android.internal.widget.remotecompose.core.operations.layout.modifiers.ComponentModifiers; import com.android.internal.widget.remotecompose.core.operations.layout.modifiers.ModifierOperation; import com.android.internal.widget.remotecompose.core.operations.utilities.StringSerializer; @@ -49,12 +55,12 @@ public class CoreDocument { ArrayList mOperations; - RootLayoutComponent mRootLayoutComponent = null; + @Nullable RootLayoutComponent mRootLayoutComponent = null; RemoteComposeState mRemoteComposeState = new RemoteComposeState(); - TimeVariables mTimeVariables = new TimeVariables(); + @NonNull TimeVariables mTimeVariables = new TimeVariables(); // Semantic version of the document - Version mVersion = new Version(0, 1, 0); + @NonNull Version mVersion = new Version(0, 1, 0); String mContentDescription; // text description of the document (used for accessibility) @@ -72,6 +78,8 @@ public class CoreDocument { private final HashMap mIntegerExpressions = new HashMap<>(); + private HashSet mAppliedTouchOperations = new HashSet<>(); + private int mLastId = 1; // last component id when inflating the file public String getContentDescription() { @@ -272,6 +280,7 @@ public class CoreDocument { * * @return list of click areas in document coordinates */ + @NonNull public Set getClickAreas() { return mClickAreas; } @@ -281,6 +290,7 @@ public class CoreDocument { * * @return returns the root component if it exists, null otherwise */ + @Nullable public RootLayoutComponent getRootLayoutComponent() { return mRootLayoutComponent; } @@ -298,6 +308,7 @@ public class CoreDocument { * @param id component id * @return the component if it exists, null otherwise */ + @Nullable public Component getComponent(int id) { if (mRootLayoutComponent != null) { return mRootLayoutComponent.getComponent(id); @@ -310,6 +321,7 @@ public class CoreDocument { * * @return a standardized string representation of the component hierarchy */ + @NonNull public String displayHierarchy() { StringSerializer serializer = new StringSerializer(); for (Operation op : mOperations) { @@ -329,7 +341,8 @@ public class CoreDocument { * @param targetId the id of the value to update with the expression * @param context the current context */ - public void evaluateIntExpression(long expressionId, int targetId, RemoteContext context) { + public void evaluateIntExpression( + long expressionId, int targetId, @NonNull RemoteContext context) { IntegerExpression expression = mIntegerExpressions.get(expressionId); if (expression != null) { int v = expression.evaluate(context); @@ -337,22 +350,46 @@ public class CoreDocument { } } + // ============== Haptic support ================== + public interface HapticEngine { + void haptic(int type); + } + + HapticEngine mHapticEngine; + + public void setHapticEngine(HapticEngine engine) { + mHapticEngine = engine; + } + + public void haptic(int type) { + if (mHapticEngine != null) { + mHapticEngine.haptic(type); + } + } + + // ============== Haptic support ================== + + public void appliedTouchOperation(Component operation) { + mAppliedTouchOperations.add(operation); + } + /** Callback interface for host actions */ public interface ActionCallback { - // TODO: add payload support - void onAction(String name); + void onAction(String name, Object value); } - HashSet mActionListeners = new HashSet(); + @NonNull HashSet mActionListeners = new HashSet(); /** * Warn action listeners for the given named action * * @param name the action name + * @param value a parameter to the action */ - public void runNamedAction(String name) { + public void runNamedAction(String name, Object value) { + // TODO: we might add an interface to group all valid parameter types for (ActionCallback callback : mActionListeners) { - callback.onAction(name); + callback.onAction(name, value); } } @@ -374,8 +411,9 @@ public class CoreDocument { void click(int id, String metadata); } - HashSet mClickListeners = new HashSet<>(); - HashSet mClickAreas = new HashSet<>(); + @NonNull HashSet mClickListeners = new HashSet<>(); + @NonNull HashSet mTouchListeners = new HashSet<>(); + @NonNull HashSet mClickAreas = new HashSet<>(); static class Version { public final int major; @@ -456,7 +494,7 @@ public class CoreDocument { } /** Load operations from the given buffer */ - public void initFromBuffer(RemoteComposeBuffer buffer) { + public void initFromBuffer(@NonNull RemoteComposeBuffer buffer) { mOperations = new ArrayList(); buffer.inflateFromBuffer(mOperations); for (Operation op : mOperations) { @@ -484,12 +522,16 @@ public class CoreDocument { * @param operations flat list of operations * @return nested list of operations / components */ - private ArrayList inflateComponents(ArrayList operations) { + @NonNull + private ArrayList inflateComponents(@NonNull ArrayList operations) { Component currentComponent = null; ArrayList components = new ArrayList<>(); ArrayList finalOperationsList = new ArrayList<>(); ArrayList ops = finalOperationsList; ClickModifierOperation currentClickModifier = null; + TouchDownModifierOperation currentTouchDownModifier = null; + TouchUpModifierOperation currentTouchUpModifier = null; + TouchCancelModifierOperation currentTouchCancelModifier = null; LoopOperation currentLoop = null; mLastId = -1; @@ -519,10 +561,30 @@ public class CoreDocument { // TODO: refactor to add container <- component... currentClickModifier = (ClickModifierOperation) o; ops = currentClickModifier.getList(); - } else if (o instanceof ClickModifierEnd) { + } else if (o instanceof TouchDownModifierOperation) { + currentTouchDownModifier = (TouchDownModifierOperation) o; + ops = currentTouchDownModifier.getList(); + } else if (o instanceof TouchUpModifierOperation) { + currentTouchUpModifier = (TouchUpModifierOperation) o; + ops = currentTouchUpModifier.getList(); + } else if (o instanceof TouchCancelModifierOperation) { + currentTouchCancelModifier = (TouchCancelModifierOperation) o; + ops = currentTouchCancelModifier.getList(); + } else if (o instanceof OperationsListEnd) { ops = currentComponent.getList(); - ops.add(currentClickModifier); - currentClickModifier = null; + if (currentClickModifier != null) { + ops.add(currentClickModifier); + currentClickModifier = null; + } else if (currentTouchDownModifier != null) { + ops.add(currentTouchDownModifier); + currentTouchDownModifier = null; + } else if (currentTouchUpModifier != null) { + ops.add(currentTouchUpModifier); + currentTouchUpModifier = null; + } else if (currentTouchCancelModifier != null) { + ops.add(currentTouchCancelModifier); + currentTouchCancelModifier = null; + } } else if (o instanceof LoopOperation) { currentLoop = (LoopOperation) o; ops = currentLoop.getList(); @@ -541,9 +603,9 @@ public class CoreDocument { return ops; } - private HashMap mComponentMap = new HashMap(); + @NonNull private HashMap mComponentMap = new HashMap(); - private void registerVariables(RemoteContext context, ArrayList list) { + private void registerVariables(RemoteContext context, @NonNull ArrayList list) { for (Operation op : list) { if (op instanceof VariableSupport) { ((VariableSupport) op).updateVariables(context); @@ -578,7 +640,7 @@ public class CoreDocument { * Called when an initialization is needed, allowing the document to eg load resources / cache * them. */ - public void initializeContext(RemoteContext context) { + public void initializeContext(@NonNull RemoteContext context) { mRemoteComposeState.reset(); mRemoteComposeState.setContext(context); mClickAreas.clear(); @@ -650,6 +712,15 @@ public class CoreDocument { id, contentDescription, left, top, right, bottom, metadata)); } + /** + * Called by commands to listen to touch events + * + * @param listener + */ + public void addTouchListener(TouchListener listener) { + mTouchListeners.add(listener); + } + /** * Add a click listener. This will get called when a click is detected on the document * @@ -664,6 +735,7 @@ public class CoreDocument { * * @return set of click listeners */ + @NonNull public HashSet getClickListeners() { return mClickListeners; } @@ -700,12 +772,98 @@ public class CoreDocument { } /** Warn click listeners when a click area is activated */ - private void warnClickListeners(ClickAreaRepresentation clickArea) { + private void warnClickListeners(@NonNull ClickAreaRepresentation clickArea) { for (ClickCallbacks listener : mClickListeners) { listener.click(clickArea.mId, clickArea.mMetadata); } } + /** + * Returns true if the document has touch listeners + * + * @return true if the document needs to react to touch events + */ + public boolean hasTouchListener() { + boolean hasComponentsTouchListeners = + mRootLayoutComponent != null && mRootLayoutComponent.hasTouchListeners(); + return hasComponentsTouchListeners || !mTouchListeners.isEmpty(); + } + + // TODO support velocity estimate support, support regions + /** + * Support touch drag events on commands supporting touch + * + * @param x position of touch + * @param y position of touch + */ + public boolean touchDrag(RemoteContext context, float x, float y) { + context.loadFloat(RemoteContext.ID_TOUCH_POS_X, x); + context.loadFloat(RemoteContext.ID_TOUCH_POS_Y, y); + for (TouchListener clickArea : mTouchListeners) { + clickArea.touchDrag(context, x, y); + } + if (!mTouchListeners.isEmpty()) { + return true; + } + return false; + } + + /** + * Support touch down events on commands supporting touch + * + * @param x position of touch + * @param y position of touch + */ + public void touchDown(RemoteContext context, float x, float y) { + context.loadFloat(RemoteContext.ID_TOUCH_POS_X, x); + context.loadFloat(RemoteContext.ID_TOUCH_POS_Y, y); + for (TouchListener clickArea : mTouchListeners) { + clickArea.touchDown(context, x, y); + } + if (mRootLayoutComponent != null) { + mRootLayoutComponent.onTouchDown(context, this, x, y); + } + mRepaintNext = 1; + } + + /** + * Support touch up events on commands supporting touch + * + * @param x position of touch + * @param y position of touch + */ + public void touchUp(RemoteContext context, float x, float y, float dx, float dy) { + context.loadFloat(RemoteContext.ID_TOUCH_POS_X, x); + context.loadFloat(RemoteContext.ID_TOUCH_POS_Y, y); + for (TouchListener clickArea : mTouchListeners) { + clickArea.touchUp(context, x, y, dx, dy); + } + if (mRootLayoutComponent != null) { + for (Component component : mAppliedTouchOperations) { + component.onTouchUp(context, this, x, y, true); + } + mAppliedTouchOperations.clear(); + } + mRepaintNext = 1; + } + + /** + * Support touch cancel events on commands supporting touch + * + * @param x position of touch + * @param y position of touch + */ + public void touchCancel(RemoteContext context, float x, float y, float dx, float dy) { + if (mRootLayoutComponent != null) { + for (Component component : mAppliedTouchOperations) { + component.onTouchCancel(context, this, x, y, true); + } + mAppliedTouchOperations.clear(); + } + mRepaintNext = 1; + } + + @NonNull @Override public String toString() { StringBuilder builder = new StringBuilder(); @@ -721,12 +879,22 @@ public class CoreDocument { * * @return array of named colors or null */ + @Nullable public String[] getNamedColors() { + return getNamedVariables(NamedVariable.COLOR_TYPE); + } + + /** + * Gets the names of all named Variables. + * + * @return array of named variables or null + */ + public String[] getNamedVariables(int type) { int count = 0; for (Operation op : mOperations) { if (op instanceof NamedVariable) { NamedVariable n = (NamedVariable) op; - if (n.mVarType == NamedVariable.COLOR_TYPE) { + if (n.mVarType == type) { count++; } } @@ -739,7 +907,7 @@ public class CoreDocument { for (Operation op : mOperations) { if (op instanceof NamedVariable) { NamedVariable n = (NamedVariable) op; - if (n.mVarType == NamedVariable.COLOR_TYPE) { + if (n.mVarType == type) { ret[i++] = n.mVarName; } } @@ -770,10 +938,9 @@ public class CoreDocument { * @param context the provided PaintContext * @param theme the theme we want to use for this document. */ - public void paint(RemoteContext context, int theme) { + public void paint(@NonNull RemoteContext context, int theme) { context.getPaintContext().clearNeedsRepaint(); context.mMode = RemoteContext.ContextMode.UNSET; - // current theme starts as UNSPECIFIED, until a Theme setter // operation gets executed and modify it. context.setTheme(Theme.UNSPECIFIED); @@ -807,6 +974,7 @@ public class CoreDocument { } // TODO -- this should be specifically about applying animation, not paint mRootLayoutComponent.paint(context.getPaintContext()); + context.mPaintContext.reset(); // TODO -- should be able to remove this mRootLayoutComponent.updateVariables(context); if (DEBUG) { @@ -843,6 +1011,7 @@ public class CoreDocument { } } + @NonNull public String[] getStats() { ArrayList ret = new ArrayList<>(); WireBuffer buffer = new WireBuffer(); @@ -875,7 +1044,7 @@ public class CoreDocument { return ret.toArray(new String[0]); } - private int sizeOfComponent(Operation com, WireBuffer tmp) { + private int sizeOfComponent(@NonNull Operation com, @NonNull WireBuffer tmp) { tmp.reset(100); com.write(tmp); int size = tmp.getSize(); @@ -883,7 +1052,8 @@ public class CoreDocument { return size; } - private int addChildren(Component base, HashMap map, WireBuffer tmp) { + private int addChildren( + @NonNull Component base, @NonNull HashMap map, @NonNull WireBuffer tmp) { int count = base.mList.size(); for (Operation mOperation : base.mList) { Class c = mOperation.getClass(); @@ -903,6 +1073,7 @@ public class CoreDocument { return count; } + @NonNull public String toNestedString() { StringBuilder ret = new StringBuilder(); for (Operation mOperation : mOperations) { @@ -915,7 +1086,8 @@ public class CoreDocument { return ret.toString(); } - private void toNestedString(Component base, StringBuilder ret, String indent) { + private void toNestedString( + @NonNull Component base, @NonNull StringBuilder ret, String indent) { for (Operation mOperation : base.mList) { ret.append(mOperation.toString()); ret.append("\n"); 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 9f565a2915fb201924d8dba9e4c10ee757042c71..f1885f942ee19d60f40220b314314a2200684812 100644 --- a/core/java/com/android/internal/widget/remotecompose/core/Operation.java +++ b/core/java/com/android/internal/widget/remotecompose/core/Operation.java @@ -15,6 +15,8 @@ */ package com.android.internal.widget.remotecompose.core; +import android.annotation.Nullable; + /** Base interface for RemoteCompose operations */ public interface Operation { @@ -29,5 +31,6 @@ public interface Operation { void apply(RemoteContext context); /** Debug utility to display an operation + indentation */ + @Nullable String deepToString(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 acebe0761b79aacef61e79c064a7058a01768414..53c45fac826c80561b8b9758c9b792d6d0769671 100644 --- a/core/java/com/android/internal/widget/remotecompose/core/Operations.java +++ b/core/java/com/android/internal/widget/remotecompose/core/Operations.java @@ -15,6 +15,8 @@ */ package com.android.internal.widget.remotecompose.core; +import android.annotation.NonNull; + import com.android.internal.widget.remotecompose.core.operations.BitmapData; import com.android.internal.widget.remotecompose.core.operations.ClickArea; import com.android.internal.widget.remotecompose.core.operations.ClipPath; @@ -65,15 +67,19 @@ import com.android.internal.widget.remotecompose.core.operations.TextLookupInt; import com.android.internal.widget.remotecompose.core.operations.TextMeasure; import com.android.internal.widget.remotecompose.core.operations.TextMerge; import com.android.internal.widget.remotecompose.core.operations.Theme; +import com.android.internal.widget.remotecompose.core.operations.TouchExpression; import com.android.internal.widget.remotecompose.core.operations.layout.CanvasContent; -import com.android.internal.widget.remotecompose.core.operations.layout.ClickModifierEnd; import com.android.internal.widget.remotecompose.core.operations.layout.ClickModifierOperation; import com.android.internal.widget.remotecompose.core.operations.layout.ComponentEnd; import com.android.internal.widget.remotecompose.core.operations.layout.ComponentStart; import com.android.internal.widget.remotecompose.core.operations.layout.LayoutComponentContent; import com.android.internal.widget.remotecompose.core.operations.layout.LoopEnd; import com.android.internal.widget.remotecompose.core.operations.layout.LoopOperation; +import com.android.internal.widget.remotecompose.core.operations.layout.OperationsListEnd; import com.android.internal.widget.remotecompose.core.operations.layout.RootLayoutComponent; +import com.android.internal.widget.remotecompose.core.operations.layout.TouchCancelModifierOperation; +import com.android.internal.widget.remotecompose.core.operations.layout.TouchDownModifierOperation; +import com.android.internal.widget.remotecompose.core.operations.layout.TouchUpModifierOperation; import com.android.internal.widget.remotecompose.core.operations.layout.animation.AnimationSpec; import com.android.internal.widget.remotecompose.core.operations.layout.managers.BoxLayout; import com.android.internal.widget.remotecompose.core.operations.layout.managers.CanvasLayout; @@ -85,15 +91,19 @@ import com.android.internal.widget.remotecompose.core.operations.layout.modifier import com.android.internal.widget.remotecompose.core.operations.layout.modifiers.BorderModifierOperation; import com.android.internal.widget.remotecompose.core.operations.layout.modifiers.ClipRectModifierOperation; import com.android.internal.widget.remotecompose.core.operations.layout.modifiers.ComponentVisibilityOperation; +import com.android.internal.widget.remotecompose.core.operations.layout.modifiers.GraphicsLayerModifierOperation; import com.android.internal.widget.remotecompose.core.operations.layout.modifiers.HeightModifierOperation; import com.android.internal.widget.remotecompose.core.operations.layout.modifiers.HostActionOperation; import com.android.internal.widget.remotecompose.core.operations.layout.modifiers.HostNamedActionOperation; +import com.android.internal.widget.remotecompose.core.operations.layout.modifiers.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.ValueFloatChangeActionOperation; 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; import com.android.internal.widget.remotecompose.core.operations.layout.modifiers.WidthModifierOperation; +import com.android.internal.widget.remotecompose.core.operations.layout.modifiers.ZIndexModifierOperation; import com.android.internal.widget.remotecompose.core.operations.utilities.IntMap; import com.android.internal.widget.remotecompose.core.types.BooleanConstant; import com.android.internal.widget.remotecompose.core.types.IntegerConstant; @@ -165,6 +175,7 @@ public class Operations { public static final int DATA_MAP_LOOKUP = 154; public static final int TEXT_MEASURE = 155; public static final int TEXT_LENGTH = 156; + public static final int TOUCH_EXPRESSION = 157; ///////////////////////////////////////// ====================== @@ -194,8 +205,16 @@ public class Operations { public static final int MODIFIER_ROUNDED_CLIP_RECT = 54; public static final int MODIFIER_CLICK = 59; + public static final int MODIFIER_TOUCH_DOWN = 219; + public static final int MODIFIER_TOUCH_UP = 220; + public static final int MODIFIER_TOUCH_CANCEL = 225; + + public static final int OPERATIONS_LIST_END = 214; + + 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_CLICK_END = 214; public static final int LOOP_START = 215; public static final int LOOP_END = 216; @@ -206,12 +225,13 @@ public class Operations { public static final int VALUE_INTEGER_CHANGE_ACTION = 212; 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 ANIMATION_SPEC = 14; public static final int COMPONENT_VALUE = 150; - public static UniqueIntMap map = new UniqueIntMap<>(); + @NonNull public static UniqueIntMap map = new UniqueIntMap<>(); static class UniqueIntMap extends IntMap { @Override @@ -289,8 +309,16 @@ public class Operations { map.put(MODIFIER_ROUNDED_CLIP_RECT, RoundedClipRectModifierOperation::read); map.put(MODIFIER_CLIP_RECT, ClipRectModifierOperation::read); map.put(MODIFIER_CLICK, ClickModifierOperation::read); - map.put(MODIFIER_CLICK_END, ClickModifierEnd::read); + map.put(MODIFIER_TOUCH_DOWN, TouchDownModifierOperation::read); + map.put(MODIFIER_TOUCH_UP, TouchUpModifierOperation::read); + map.put(MODIFIER_TOUCH_CANCEL, TouchCancelModifierOperation::read); map.put(MODIFIER_VISIBILITY, ComponentVisibilityOperation::read); + map.put(MODIFIER_OFFSET, OffsetModifierOperation::read); + map.put(MODIFIER_ZINDEX, ZIndexModifierOperation::read); + map.put(MODIFIER_GRAPHICS_LAYER, GraphicsLayerModifierOperation::read); + + map.put(OPERATIONS_LIST_END, OperationsListEnd::read); + map.put(HOST_ACTION, HostActionOperation::read); map.put(HOST_NAMED_ACTION, HostNamedActionOperation::read); map.put(VALUE_INTEGER_CHANGE_ACTION, ValueIntegerChangeActionOperation::read); @@ -298,6 +326,7 @@ public class Operations { VALUE_INTEGER_EXPRESSION_CHANGE_ACTION, ValueIntegerExpressionChangeActionOperation::read); map.put(VALUE_STRING_CHANGE_ACTION, ValueStringChangeActionOperation::read); + map.put(VALUE_FLOAT_CHANGE_ACTION, ValueFloatChangeActionOperation::read); map.put(LAYOUT_ROOT, RootLayoutComponent::read); map.put(LAYOUT_CONTENT, LayoutComponentContent::read); @@ -315,5 +344,6 @@ public class Operations { map.put(DATA_MAP_LOOKUP, DataMapLookup::read); map.put(TEXT_MEASURE, TextMeasure::read); map.put(TEXT_LENGTH, TextLength::read); + map.put(TOUCH_EXPRESSION, TouchExpression::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 13d6f783a58656a94619115320ecfb11776b6d7a..1a71afe068bdc2f765db41cd130ad932c7015f82 100644 --- a/core/java/com/android/internal/widget/remotecompose/core/PaintContext.java +++ b/core/java/com/android/internal/widget/remotecompose/core/PaintContext.java @@ -271,4 +271,24 @@ public abstract class PaintContext { public void needsRepaint() { mNeedsRepaint = true; } + + public abstract void startGraphicsLayer(int w, int h); + + public abstract void setGraphicsLayer( + float scaleX, + float scaleY, + float rotationX, + float rotationY, + float rotationZ, + float shadowElevation, + float transformOriginX, + float transformOriginY, + float alpha, + int renderEffectId); + + public abstract void endGraphicsLayer(); + + public boolean isVisualDebug() { + return mContext.isVisualDebug(); + } } 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 9b7b50f775b0f73a3754b825ab53ef2b865779a7..049e47744ce833d74abcee932fac882a2ee931ac 100644 --- a/core/java/com/android/internal/widget/remotecompose/core/PaintOperation.java +++ b/core/java/com/android/internal/widget/remotecompose/core/PaintOperation.java @@ -15,6 +15,8 @@ */ package com.android.internal.widget.remotecompose.core; +import android.annotation.NonNull; + /** * PaintOperation interface, used for operations aimed at painting (while any operation _can_ paint, * this make it a little more explicit) @@ -22,7 +24,7 @@ package com.android.internal.widget.remotecompose.core; public abstract class PaintOperation implements Operation { @Override - public void apply(RemoteContext context) { + public void apply(@NonNull RemoteContext context) { if (context.getMode() == RemoteContext.ContextMode.PAINT) { PaintContext paintContext = context.getPaintContext(); if (paintContext != null) { @@ -31,6 +33,7 @@ public abstract class PaintOperation implements Operation { } } + @NonNull @Override public String deepToString(String indent) { return indent + toString(); 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 6725e7e6ac2b409d11a086fef33732919ea49ac6..7fbcfae54bcb104b072059f74028d5728321c855 100644 --- a/core/java/com/android/internal/widget/remotecompose/core/Platform.java +++ b/core/java/com/android/internal/widget/remotecompose/core/Platform.java @@ -15,16 +15,30 @@ */ package com.android.internal.widget.remotecompose.core; +import android.annotation.Nullable; + /** Services that are needed to be provided by the platform during encoding. */ public interface Platform { + @Nullable byte[] imageToByteArray(Object image); int getImageWidth(Object image); int getImageHeight(Object image); + @Nullable float[] pathToFloatArray(Object path); + enum LogCategory { + DEBUG, + INFO, + WARN, + ERROR, + TODO, + } + + void log(LogCategory category, String message); + Platform None = new Platform() { @Override @@ -46,5 +60,8 @@ public interface Platform { public float[] pathToFloatArray(Object path) { throw new UnsupportedOperationException(); } + + @Override + public void log(LogCategory category, String message) {} }; } 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 5b5adc28a676f6d41edfef93f0ff47513bfbecbd..7d9439dd186b692246033ec0376756bc831358d8 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 android.annotation.NonNull; +import android.annotation.Nullable; + import com.android.internal.widget.remotecompose.core.operations.BitmapData; import com.android.internal.widget.remotecompose.core.operations.ClickArea; import com.android.internal.widget.remotecompose.core.operations.ClipPath; @@ -64,6 +67,7 @@ import com.android.internal.widget.remotecompose.core.operations.TextLookupInt; import com.android.internal.widget.remotecompose.core.operations.TextMeasure; import com.android.internal.widget.remotecompose.core.operations.TextMerge; import com.android.internal.widget.remotecompose.core.operations.Theme; +import com.android.internal.widget.remotecompose.core.operations.TouchExpression; import com.android.internal.widget.remotecompose.core.operations.Utils; import com.android.internal.widget.remotecompose.core.operations.layout.CanvasContent; import com.android.internal.widget.remotecompose.core.operations.layout.ComponentEnd; @@ -81,8 +85,11 @@ import com.android.internal.widget.remotecompose.core.operations.layout.managers import com.android.internal.widget.remotecompose.core.operations.layout.modifiers.BackgroundModifierOperation; import com.android.internal.widget.remotecompose.core.operations.layout.modifiers.BorderModifierOperation; import com.android.internal.widget.remotecompose.core.operations.layout.modifiers.ClipRectModifierOperation; +import com.android.internal.widget.remotecompose.core.operations.layout.modifiers.GraphicsLayerModifierOperation; +import com.android.internal.widget.remotecompose.core.operations.layout.modifiers.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.ZIndexModifierOperation; import com.android.internal.widget.remotecompose.core.operations.paint.PaintBundle; import com.android.internal.widget.remotecompose.core.operations.utilities.NanMap; import com.android.internal.widget.remotecompose.core.operations.utilities.easing.FloatAnimation; @@ -111,7 +118,7 @@ public class RemoteComposeBuffer { 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(); - Platform mPlatform = null; + @Nullable Platform mPlatform = null; RemoteComposeState mRemoteComposeState; private static final boolean DEBUG = false; @@ -143,6 +150,7 @@ public class RemoteComposeBuffer { return mLastComponentId; } + @Nullable public Platform getPlatform() { return mPlatform; } @@ -172,7 +180,11 @@ public class RemoteComposeBuffer { * @param capabilities bitmask indicating needed capabilities (unused for now) */ public void header( - int width, int height, String contentDescription, float density, long capabilities) { + int width, + int height, + @Nullable String contentDescription, + float density, + long capabilities) { Header.apply(mBuffer, width, height, density, capabilities); int contentDescriptionId = 0; if (contentDescription != null) { @@ -219,7 +231,7 @@ public class RemoteComposeBuffer { int dstTop, int dstRight, int dstBottom, - String contentDescription) { + @Nullable String contentDescription) { int imageId = mRemoteComposeState.dataGetId(image); if (imageId == -1) { imageId = mRemoteComposeState.cacheData(image); @@ -267,7 +279,7 @@ public class RemoteComposeBuffer { * * @param text the string to inject in the buffer */ - public int addText(String text) { + public int addText(@NonNull String text) { int id = mRemoteComposeState.dataGetId(text); if (id == -1) { id = mRemoteComposeState.cacheData(text); @@ -289,12 +301,12 @@ public class RemoteComposeBuffer { */ public void addClickArea( int id, - String contentDescription, + @Nullable String contentDescription, float left, float top, float right, float bottom, - String metadata) { + @Nullable String metadata) { int contentDescriptionId = 0; if (contentDescription != null) { contentDescriptionId = addText(contentDescription); @@ -380,7 +392,7 @@ public class RemoteComposeBuffer { float top, float right, float bottom, - String contentDescription) { + @Nullable String contentDescription) { int imageId = mRemoteComposeState.dataGetId(image); if (imageId == -1) { imageId = mRemoteComposeState.cacheData(image); @@ -411,7 +423,7 @@ public class RemoteComposeBuffer { float top, float right, float bottom, - String contentDescription) { + @Nullable String contentDescription) { int contentDescriptionId = 0; if (contentDescription != null) { contentDescriptionId = addText(contentDescription); @@ -445,7 +457,7 @@ public class RemoteComposeBuffer { float dstBottom, int scaleType, float scaleFactor, - String contentDescription) { + @Nullable String contentDescription) { int imageId = mRemoteComposeState.dataGetId(image); if (imageId == -1) { imageId = mRemoteComposeState.cacheData(image); @@ -500,7 +512,7 @@ public class RemoteComposeBuffer { * @param image drawScaledBitmap * @return id of the image useful with */ - public int addBitmap(Object image, String name) { + public int addBitmap(Object image, @NonNull String name) { int imageId = mRemoteComposeState.dataGetId(image); if (imageId == -1) { imageId = mRemoteComposeState.cacheData(image); @@ -521,7 +533,7 @@ public class RemoteComposeBuffer { * @param id of the Bitmap * @param name Name of the color */ - public void setBitmapName(int id, String name) { + public void setBitmapName(int id, @NonNull String name) { NamedVariable.apply(mBuffer, id, NamedVariable.IMAGE_TYPE, name); } @@ -551,7 +563,7 @@ public class RemoteComposeBuffer { float dstBottom, int scaleType, float scaleFactor, - String contentDescription) { + @Nullable String contentDescription) { int contentDescriptionId = 0; if (contentDescription != null) { contentDescriptionId = addText(contentDescription); @@ -669,7 +681,7 @@ 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(String text, Object path, float hOffset, float vOffset) { + public void addDrawTextOnPath(@NonNull String text, Object path, float hOffset, float vOffset) { int pathId = mRemoteComposeState.dataGetId(path); if (pathId == -1) { // never been seen before pathId = addPathData(path); @@ -692,7 +704,7 @@ public class RemoteComposeBuffer { * @param rtl Draw RTTL */ public void addDrawTextRun( - String text, + @NonNull String text, int start, int end, int contextStart, @@ -749,7 +761,8 @@ public class RemoteComposeBuffer { * @param panY position text -1.0=above, 0.0=center, 1.0=below, Nan=baseline * @param flags 1 = RTL */ - public void drawTextAnchored(String text, float x, float y, float panX, float panY, int flags) { + public void drawTextAnchored( + @NonNull String text, float x, float y, float panX, float panY, int flags) { int textId = addText(text); DrawTextAnchored.apply(mBuffer, textId, x, y, panX, panY, flags); } @@ -760,7 +773,7 @@ public class RemoteComposeBuffer { * @param text * @return */ - public int createTextId(String text) { + public int createTextId(@NonNull String text) { return addText(text); } @@ -891,7 +904,7 @@ public class RemoteComposeBuffer { * * @param paint */ - public void addPaint(PaintBundle paint) { + public void addPaint(@NonNull PaintBundle paint) { PaintData.apply(mBuffer, paint); } @@ -912,7 +925,8 @@ public class RemoteComposeBuffer { } } - public static void readNextOperation(WireBuffer buffer, ArrayList operations) { + public static void readNextOperation( + @NonNull WireBuffer buffer, ArrayList operations) { int opId = buffer.readByte(); if (DEBUG) { Utils.log(">> " + opId); @@ -924,6 +938,7 @@ public class RemoteComposeBuffer { operation.read(buffer, operations); } + @NonNull RemoteComposeBuffer copy() { ArrayList operations = new ArrayList<>(); inflateFromBuffer(operations); @@ -935,33 +950,38 @@ public class RemoteComposeBuffer { Theme.apply(mBuffer, theme); } + @NonNull static String version() { return "v1.0"; } - public static RemoteComposeBuffer fromFile(String path, RemoteComposeState remoteComposeState) - throws IOException { + @NonNull + public static RemoteComposeBuffer fromFile( + @NonNull String path, RemoteComposeState remoteComposeState) throws IOException { RemoteComposeBuffer buffer = new RemoteComposeBuffer(remoteComposeState); read(new File(path), buffer); return buffer; } - public RemoteComposeBuffer fromFile(File file, RemoteComposeState remoteComposeState) + @NonNull + public RemoteComposeBuffer fromFile(@NonNull File file, RemoteComposeState remoteComposeState) throws IOException { RemoteComposeBuffer buffer = new RemoteComposeBuffer(remoteComposeState); read(file, buffer); return buffer; } + @NonNull public static RemoteComposeBuffer fromInputStream( - InputStream inputStream, RemoteComposeState remoteComposeState) { + @NonNull InputStream inputStream, RemoteComposeState remoteComposeState) { RemoteComposeBuffer buffer = new RemoteComposeBuffer(remoteComposeState); read(inputStream, buffer); return buffer; } + @NonNull RemoteComposeBuffer copyFromOperations( - ArrayList operations, RemoteComposeBuffer buffer) { + @NonNull ArrayList operations, @NonNull RemoteComposeBuffer buffer) { for (Operation operation : operations) { operation.write(buffer.mBuffer); @@ -975,7 +995,7 @@ public class RemoteComposeBuffer { * @param buffer a RemoteComposeBuffer * @param file a target file */ - public void write(RemoteComposeBuffer buffer, File file) { + public void write(@NonNull RemoteComposeBuffer buffer, @NonNull File file) { try { FileOutputStream fd = new FileOutputStream(file); fd.write(buffer.mBuffer.getBuffer(), 0, buffer.mBuffer.getSize()); @@ -986,12 +1006,12 @@ public class RemoteComposeBuffer { } } - static void read(File file, RemoteComposeBuffer buffer) throws IOException { + static void read(@NonNull File file, @NonNull RemoteComposeBuffer buffer) throws IOException { FileInputStream fd = new FileInputStream(file); read(fd, buffer); } - public static void read(InputStream fd, RemoteComposeBuffer buffer) { + public static void read(@NonNull InputStream fd, @NonNull RemoteComposeBuffer buffer) { try { byte[] bytes = readAllBytes(fd); buffer.reset(bytes.length); @@ -1002,7 +1022,7 @@ public class RemoteComposeBuffer { } } - private static byte[] readAllBytes(InputStream is) throws IOException { + private static byte[] readAllBytes(@NonNull InputStream is) throws IOException { byte[] buff = new byte[32 * 1024]; // moderate size buff to start int red = 0; while (true) { @@ -1176,12 +1196,51 @@ public class RemoteComposeBuffer { * @param value A RPN style float operation i.e. "4, 3, ADD" outputs 7 * @return NaN id of the result of the calculation */ - public float addAnimatedFloat(float... value) { + public float addAnimatedFloat(@NonNull float... value) { int id = mRemoteComposeState.cacheData(value); FloatExpression.apply(mBuffer, id, value, null); return Utils.asNan(id); } + /** + * 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) { + int id = mRemoteComposeState.nextId(); + TouchExpression.apply( + mBuffer, + id, + value, + min, + max, + velocityId, + touchEffects, + exp, + touchMode, + touchSpec, + easingSpec); + return Utils.asNan(id); + } + /** * Add a float that is a computation based on variables. see packAnimation * @@ -1189,7 +1248,7 @@ public class RemoteComposeBuffer { * @param animation Array of floats that represents animation * @return NaN id of the result of the calculation */ - public float addAnimatedFloat(float[] value, float[] animation) { + public float addAnimatedFloat(@NonNull float[] value, float[] animation) { int id = mRemoteComposeState.cacheData(value); FloatExpression.apply(mBuffer, id, value, animation); return Utils.asNan(id); @@ -1228,7 +1287,7 @@ public class RemoteComposeBuffer { * @param values * @return the id of the array, encoded as a float NaN */ - public float addFloatArray(float[] values) { + public float addFloatArray(@NonNull float[] values) { int id = mRemoteComposeState.cacheData(values, NanMap.TYPE_ARRAY); DataListFloat.apply(mBuffer, id, values); return Utils.asNan(id); @@ -1240,7 +1299,7 @@ public class RemoteComposeBuffer { * @param values array of floats to be individually stored * @return id of the list */ - public float addFloatList(float[] values) { + public float addFloatList(@NonNull float[] values) { int[] listId = new int[values.length]; for (int i = 0; i < listId.length; i++) { listId[i] = mRemoteComposeState.cacheFloat(values[i]); @@ -1255,7 +1314,7 @@ public class RemoteComposeBuffer { * @param listId array id to be stored * @return id of the list */ - public float addList(int[] listId) { + public float addList(@NonNull int[] listId) { int id = mRemoteComposeState.cacheData(listId, NanMap.TYPE_ARRAY); DataListIds.apply(mBuffer, id, listId); return Utils.asNan(id); @@ -1268,7 +1327,7 @@ public class RemoteComposeBuffer { * @param values * @return the id of the map, encoded as a float NaN */ - public float addFloatMap(String[] keys, float[] values) { + public float addFloatMap(@NonNull String[] keys, @NonNull float[] values) { int[] listId = new int[values.length]; byte[] type = new byte[values.length]; for (int i = 0; i < listId.length; i++) { @@ -1286,7 +1345,7 @@ public class RemoteComposeBuffer { * @param listId * @return the id of the map, encoded as a float NaN */ - public int addMap(String[] keys, byte[] types, int[] listId) { + public int addMap(@NonNull String[] keys, byte[] types, int[] listId) { int id = mRemoteComposeState.cacheData(listId, NanMap.TYPE_ARRAY); DataMapIds.apply(mBuffer, id, keys, types, listId); return id; @@ -1331,7 +1390,7 @@ public class RemoteComposeBuffer { * @param value array of values to calculate maximum 32 * @return the id as an integer */ - public int addIntegerExpression(int mask, int[] value) { + public int addIntegerExpression(int mask, @NonNull int[] value) { int id = mRemoteComposeState.cacheData(value); IntegerExpression.apply(mBuffer, id, mask, value); return id; @@ -1474,7 +1533,7 @@ public class RemoteComposeBuffer { * @param id of the color * @param name Name of the color */ - public void setColorName(int id, String name) { + public void setColorName(int id, @NonNull String name) { NamedVariable.apply(mBuffer, id, NamedVariable.COLOR_TYPE, name); } @@ -1484,7 +1543,7 @@ public class RemoteComposeBuffer { * @param id of the string * @param name name of the string */ - public void setStringName(int id, String name) { + public void setStringName(int id, @NonNull String name) { NamedVariable.apply(mBuffer, id, NamedVariable.STRING_TYPE, name); } @@ -1575,6 +1634,72 @@ public class RemoteComposeBuffer { PaddingModifierOperation.apply(mBuffer, left, top, right, bottom); } + /** + * Add an offset modifier + * + * @param x x offset + * @param y y offset + */ + public void addModifierOffset(float x, float y) { + OffsetModifierOperation.apply(mBuffer, x, y); + } + + /** + * Add a zIndex modifier + * + * @param value z-Index value + */ + public void addModifierZIndex(float value) { + ZIndexModifierOperation.apply(mBuffer, value); + } + + /** + * Add a graphics layer + * + * @param scaleX + * @param scaleY + * @param rotationX + * @param rotationY + * @param rotationZ + * @param shadowElevation + * @param transformOriginX + * @param transformOriginY + */ + public void addModifierGraphicsLayer( + float scaleX, + float scaleY, + float rotationX, + float rotationY, + float rotationZ, + float shadowElevation, + float transformOriginX, + float transformOriginY, + float alpha, + float cameraDistance, + int blendMode, + int spotShadowColorId, + int ambientShadowColorId, + int colorFilterId, + int renderEffectId) { + GraphicsLayerModifierOperation.apply( + mBuffer, + scaleX, + scaleY, + rotationX, + rotationY, + rotationZ, + shadowElevation, + transformOriginX, + transformOriginY, + alpha, + cameraDistance, + blendMode, + spotShadowColorId, + ambientShadowColorId, + colorFilterId, + renderEffectId); + } + /** * Sets the clip based on rounded clip rect * @@ -1721,7 +1846,8 @@ public class RemoteComposeBuffer { float fontSize, int fontStyle, float fontWeight, - String fontFamily) { + @Nullable String fontFamily, + int textAlign) { mLastComponentId = getComponentId(componentId); int fontFamilyId = -1; if (fontFamily != null) { @@ -1736,6 +1862,11 @@ public class RemoteComposeBuffer { fontSize, fontStyle, fontWeight, - fontFamilyId); + fontFamilyId, + textAlign); + } + + public int createID(int type) { + return mRemoteComposeState.nextId(type); } } 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 51445f2ff31d329508eaf854d93117ac5d7590ab..3039328149099e029bb75840f6ae198e9aea5ca0 100644 --- a/core/java/com/android/internal/widget/remotecompose/core/RemoteComposeState.java +++ b/core/java/com/android/internal/widget/remotecompose/core/RemoteComposeState.java @@ -15,6 +15,9 @@ */ package com.android.internal.widget.remotecompose.core; +import android.annotation.NonNull; +import android.annotation.Nullable; + import com.android.internal.widget.remotecompose.core.operations.utilities.ArrayAccess; import com.android.internal.widget.remotecompose.core.operations.utilities.CollectionsAccess; import com.android.internal.widget.remotecompose.core.operations.utilities.DataMap; @@ -50,10 +53,11 @@ public class RemoteComposeState implements CollectionsAccess { private final boolean[] mDataOverride = new boolean[MAX_DATA]; private final boolean[] mIntegerOverride = new boolean[MAX_DATA]; + private final boolean[] mFloatOverride = new boolean[MAX_DATA]; private int mNextId = START_ID; - private int[] mIdMaps = new int[] {START_ID, NanMap.START_VAR, NanMap.START_ARRAY}; - private RemoteContext mRemoteContext = null; + @NonNull private int[] mIdMaps = new int[] {START_ID, NanMap.START_VAR, NanMap.START_ARRAY}; + @Nullable private RemoteContext mRemoteContext = null; /** * Get Object based on id. The system will cache things like bitmaps Paths etc. They can be @@ -62,6 +66,7 @@ public class RemoteComposeState implements CollectionsAccess { * @param id * @return */ + @Nullable public Object getFromId(int id) { return mIntDataMap.get(id); } @@ -158,10 +163,28 @@ public class RemoteComposeState implements CollectionsAccess { /** Insert an float item in the cache */ public void updateFloat(int id, float value) { + if (!mFloatOverride[id]) { + float previous = mFloatMap.get(id); + if (previous != value) { + mFloatMap.put(id, value); + mIntegerMap.put(id, (int) value); + updateListeners(id); + } + } + } + + /** + * Adds a float Override. + * + * @param id + * @param value the new value + */ + public void overrideFloat(int id, float value) { float previous = mFloatMap.get(id); if (previous != value) { mFloatMap.put(id, value); mIntegerMap.put(id, (int) value); + mFloatOverride[id] = true; updateListeners(id); } } @@ -293,6 +316,16 @@ public class RemoteComposeState implements CollectionsAccess { updateListeners(id); } + /** + * Clear the float override + * + * @param id the float id to clear + */ + public void clearFloatOverride(int id) { + mFloatOverride[id] = false; + updateListeners(id); + } + /** * Method to determine if a cached value has been written to the documents WireBuffer based on * its id. @@ -322,7 +355,8 @@ public class RemoteComposeState implements CollectionsAccess { } /** - * Get the next available id + * Get the next available id 0 is normal (float,int,String,color) 1 is VARIABLES 2 is + * collections * * @return */ @@ -342,8 +376,8 @@ public class RemoteComposeState implements CollectionsAccess { mNextId = id; } - IntMap> mVarListeners = new IntMap<>(); - ArrayList mAllVarListeners = new ArrayList<>(); + @NonNull IntMap> mVarListeners = new IntMap<>(); + @NonNull ArrayList mAllVarListeners = new ArrayList<>(); private void add(int id, VariableSupport variableSupport) { ArrayList v = mVarListeners.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 1066e7d9f6176b15b24d143b82d97019d35f511d..23cc5b89d916b466ec849e9531ac38a27b3f0891 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,8 @@ */ package com.android.internal.widget.remotecompose.core; +import android.annotation.Nullable; + 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.Theme; @@ -40,10 +42,12 @@ public abstract class RemoteContext { protected CoreDocument mDocument; public RemoteComposeState mRemoteComposeState; long mStart = System.nanoTime(); // todo This should be set at a hi level - protected PaintContext mPaintContext = null; + @Nullable protected PaintContext mPaintContext = null; + protected float mDensity = 2.75f; + ContextMode mMode = ContextMode.UNSET; - boolean mDebug = false; + int mDebug = 0; private int mTheme = Theme.UNSPECIFIED; @@ -56,6 +60,14 @@ public abstract class RemoteContext { public Component lastComponent; public long currentTime = 0L; + public float getDensity() { + return mDensity; + } + + public void setDensity(float density) { + mDensity = density; + } + public boolean isAnimationEnabled() { return mAnimate; } @@ -173,12 +185,22 @@ public abstract class RemoteContext { public abstract void runAction(int id, String metadata); - public abstract void runNamedAction(int textId); + // 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 Object getObject(int mId); + public void addTouchListener(TouchListener touchExpression) {} + + /** + * Vibrate the device + * + * @param type 0 = none, 1-21 ,see HapticFeedbackConstants + */ + public abstract void hapticEffect(int type); + /** * The context can be used in a few different mode, allowing operations to skip being executed: * - UNSET : all operations will get executed - DATA : only operations dealing with DATA (eg @@ -206,6 +228,7 @@ public abstract class RemoteContext { this.mMode = mode; } + @Nullable public PaintContext getPaintContext() { return mPaintContext; } @@ -219,10 +242,14 @@ public abstract class RemoteContext { } public boolean isDebug() { - return mDebug; + return mDebug == 1; } - public void setDebug(boolean debug) { + public boolean isVisualDebug() { + return mDebug == 2; + } + + public void setDebug(int debug) { this.mDebug = debug; } @@ -313,6 +340,14 @@ public abstract class RemoteContext { */ public abstract void loadFloat(int id, float value); + /** + * Override an existing float value + * + * @param id + * @param value + */ + public abstract void overrideFloat(int id, float value); + /** * Load a integer * @@ -321,8 +356,20 @@ public abstract class RemoteContext { */ public abstract void loadInteger(int id, int value); + /** + * Override an existing int value + * + * @param id + * @param value + */ public abstract void overrideInteger(int id, int value); + /** + * Override an existing text value + * + * @param id + * @param valueId + */ public abstract void overrideText(int id, int valueId); /** @@ -400,6 +447,25 @@ public abstract class RemoteContext { public static final int ID_OFFSET_TO_UTC = 10; public static final int ID_WEEK_DAY = 11; public static final int ID_DAY_OF_MONTH = 12; + public static final int ID_TOUCH_POS_X = 13; + public static final int ID_TOUCH_POS_Y = 14; + + public static final int ID_TOUCH_VEL_X = 15; + public static final int ID_TOUCH_VEL_Y = 16; + + public static final int ID_ACCELERATION_X = 17; + public static final int ID_ACCELERATION_Y = 18; + public static final int ID_ACCELERATION_Z = 19; + + public static final int ID_GYRO_ROT_X = 20; + public static final int ID_GYRO_ROT_Y = 21; + public static final int ID_GYRO_ROT_Z = 22; + + public static final int ID_MAGNETIC_X = 23; + public static final int ID_MAGNETIC_Y = 24; + public static final int ID_MAGNETIC_Z = 25; + + public static final int ID_LIGHT = 26; /** CONTINUOUS_SEC is seconds from midnight looping every hour 0-3600 */ public static final float FLOAT_CONTINUOUS_SEC = Utils.asNan(ID_CONTINUOUS_SEC); @@ -426,9 +492,52 @@ public abstract class RemoteContext { public static final float FLOAT_WINDOW_HEIGHT = Utils.asNan(ID_WINDOW_HEIGHT); public static final float FLOAT_COMPONENT_WIDTH = Utils.asNan(ID_COMPONENT_WIDTH); public static final float FLOAT_COMPONENT_HEIGHT = Utils.asNan(ID_COMPONENT_HEIGHT); - // ID_OFFSET_TO_UTC is the offset from UTC in sec (typically / 3600f) + + /** ID_OFFSET_TO_UTC is the offset from UTC in sec (typically / 3600f) */ public static final float FLOAT_OFFSET_TO_UTC = Utils.asNan(ID_OFFSET_TO_UTC); + /** TOUCH_POS_X is the x position of the touch */ + public static final float FLOAT_TOUCH_POS_X = Utils.asNan(ID_TOUCH_POS_X); + + /** TOUCH_POS_Y is the y position of the touch */ + public static final float FLOAT_TOUCH_POS_Y = Utils.asNan(ID_TOUCH_POS_Y); + + /** TOUCH_VEL_X is the x velocity of the touch */ + public static final float FLOAT_TOUCH_VEL_X = Utils.asNan(ID_TOUCH_VEL_X); + + /** TOUCH_VEL_Y is the x velocity of the touch */ + public static final float FLOAT_TOUCH_VEL_Y = Utils.asNan(ID_TOUCH_VEL_Y); + + /** X acceleration sensor value in M/s^2 */ + public static final float FLOAT_ACCELERATION_X = Utils.asNan(ID_ACCELERATION_X); + + /** Y acceleration sensor value in M/s^2 */ + public static final float FLOAT_ACCELERATION_Y = Utils.asNan(ID_ACCELERATION_Y); + + /** Z acceleration sensor value in M/s^2 */ + public static final float FLOAT_ACCELERATION_Z = Utils.asNan(ID_ACCELERATION_Z); + + /** X Gyroscope rotation rate sensor value in radians/second */ + public static final float FLOAT_GYRO_ROT_X = Utils.asNan(ID_GYRO_ROT_X); + + /** Y Gyroscope rotation rate sensor value in radians/second */ + public static final float FLOAT_GYRO_ROT_Y = Utils.asNan(ID_GYRO_ROT_Y); + + /** Z Gyroscope rotation rate sensor value in radians/second */ + public static final float FLOAT_GYRO_ROT_Z = Utils.asNan(ID_GYRO_ROT_Z); + + /** Ambient magnetic field in X. sensor value in micro-Tesla (uT) */ + public static final float FLOAT_MAGNETIC_X = Utils.asNan(ID_MAGNETIC_X); + + /** Ambient magnetic field in Y. sensor value in micro-Tesla (uT) */ + public static final float FLOAT_MAGNETIC_Y = Utils.asNan(ID_MAGNETIC_Y); + + /** Ambient magnetic field in Z. sensor value in micro-Tesla (uT) */ + public static final float FLOAT_MAGNETIC_Z = Utils.asNan(ID_MAGNETIC_Z); + + /** Ambient light level in SI lux */ + public static final float FLOAT_LIGHT = Utils.asNan(ID_LIGHT); + /////////////////////////////////////////////////////////////////////////////////////////////// // Click handling /////////////////////////////////////////////////////////////////////////////////////////////// diff --git a/core/java/com/android/internal/widget/remotecompose/core/TimeVariables.java b/core/java/com/android/internal/widget/remotecompose/core/TimeVariables.java index fa0cf3f455c4864b334c84f59243a066548793a7..14aed2f0c17396041b67cf51b784722301d9c8ec 100644 --- a/core/java/com/android/internal/widget/remotecompose/core/TimeVariables.java +++ b/core/java/com/android/internal/widget/remotecompose/core/TimeVariables.java @@ -15,6 +15,8 @@ */ package com.android.internal.widget.remotecompose.core; +import android.annotation.NonNull; + import java.time.LocalDateTime; import java.time.OffsetDateTime; import java.time.ZoneId; @@ -27,7 +29,7 @@ public class TimeVariables { * * @param context */ - public void updateTime(RemoteContext context) { + public void updateTime(@NonNull RemoteContext context) { LocalDateTime dateTime = LocalDateTime.now(ZoneId.systemDefault()); // TODO, pass in a timezone explicitly? // This define the time in the format diff --git a/core/java/com/android/internal/widget/remotecompose/core/TouchListener.java b/core/java/com/android/internal/widget/remotecompose/core/TouchListener.java new file mode 100644 index 0000000000000000000000000000000000000000..3dda678c2a3a0331c04192e128ed757884284b3c --- /dev/null +++ b/core/java/com/android/internal/widget/remotecompose/core/TouchListener.java @@ -0,0 +1,24 @@ +/* + * 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; + +public interface TouchListener { + void touchDown(RemoteContext context, float x, float y); + + void touchUp(RemoteContext context, float x, float y, float dx, float dy); + + void touchDrag(RemoteContext context, float x, float y); +} 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 c71b4901ca78d28a17b6ba8f5e353f30e401e668..738e42baae0b7da7f54ecd0d15feb058ebcee459 100644 --- a/core/java/com/android/internal/widget/remotecompose/core/WireBuffer.java +++ b/core/java/com/android/internal/widget/remotecompose/core/WireBuffer.java @@ -15,6 +15,8 @@ */ package com.android.internal.widget.remotecompose.core; +import android.annotation.NonNull; + import java.util.Arrays; /** The base communication buffer capable of encoding and decoding various types */ @@ -184,11 +186,13 @@ public class WireBuffer { return b; } + @NonNull public String readUTF8() { byte[] stringBuffer = readBuffer(); return new String(stringBuffer); } + @NonNull public String readUTF8(int maxSize) { byte[] stringBuffer = readBuffer(maxSize); return new String(stringBuffer); @@ -250,7 +254,7 @@ public class WireBuffer { writeLong(Double.doubleToRawLongBits(value)); } - public void writeBuffer(byte[] b) { + public void writeBuffer(@NonNull byte[] b) { resize(b.length + 4); writeInt(b.length); for (int i = 0; i < b.length; i++) { @@ -259,7 +263,7 @@ public class WireBuffer { mSize += b.length; } - public void writeUTF8(String content) { + public void writeUTF8(@NonNull String content) { byte[] buffer = content.getBytes(); writeBuffer(buffer); } 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 c33ae244b92305ef231d8fa0fdae115f5b641117..5edecaa01f823e5b615ec88149a79ae001e0cb18 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 @@ -15,6 +15,8 @@ */ package com.android.internal.widget.remotecompose.core.documentation; +import android.annotation.NonNull; + import java.util.ArrayList; public class DocumentedOperation { @@ -40,12 +42,13 @@ public class DocumentedOperation { boolean mWIP; String mTextExamples; - ArrayList mExamples = new ArrayList<>(); - ArrayList mFields = new ArrayList<>(); - String mVarSize = ""; + @NonNull ArrayList mExamples = new ArrayList<>(); + @NonNull ArrayList mFields = new ArrayList<>(); + @NonNull String mVarSize = ""; int mExamplesWidth = 100; int mExamplesHeight = 100; + @NonNull public static String getType(int type) { switch (type) { case INT: @@ -85,6 +88,7 @@ public class DocumentedOperation { this(category, id, name, false); } + @NonNull public ArrayList getFields() { return mFields; } @@ -105,6 +109,7 @@ public class DocumentedOperation { return mWIP; } + @NonNull public String getVarSize() { return mVarSize; } @@ -129,6 +134,7 @@ public class DocumentedOperation { return mTextExamples; } + @NonNull public ArrayList getExamples() { return mExamples; } @@ -141,16 +147,19 @@ public class DocumentedOperation { return mExamplesHeight; } + @NonNull public DocumentedOperation field(int type, String name, String description) { mFields.add(new OperationField(type, name, description)); return this; } + @NonNull public DocumentedOperation field(int type, String name, String varSize, String description) { mFields.add(new OperationField(type, name, varSize, description)); return this; } + @NonNull public DocumentedOperation possibleValues(String name, int value) { if (!mFields.isEmpty()) { mFields.get(mFields.size() - 1).possibleValue(name, "" + value); @@ -158,21 +167,25 @@ public class DocumentedOperation { return this; } + @NonNull public DocumentedOperation description(String description) { mDescription = description; return this; } + @NonNull public DocumentedOperation examples(String examples) { mTextExamples = examples; return this; } + @NonNull public DocumentedOperation exampleImage(String name, String imagePath) { mExamples.add(new StringPair(name, imagePath)); return this; } + @NonNull public DocumentedOperation examplesDimension(int width, int height) { mExamplesWidth = width; mExamplesHeight = height; 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 c7704839140522943200128887dbc162e17d8b8e..cbb5ca9821c35db5b6b564d689a4b8d5fc694fc7 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 @@ -15,15 +15,18 @@ */ package com.android.internal.widget.remotecompose.core.documentation; +import android.annotation.NonNull; +import android.annotation.Nullable; + import java.util.ArrayList; public class OperationField { int mType; String mName; String mDescription; - String mVarSize = null; + @Nullable String mVarSize = null; - ArrayList mPossibleValues = new ArrayList<>(); + @NonNull ArrayList mPossibleValues = new ArrayList<>(); public OperationField(int type, String name, String description) { mType = type; @@ -50,6 +53,7 @@ public class OperationField { return mDescription; } + @NonNull public ArrayList getPossibleValues() { return mPossibleValues; } @@ -62,6 +66,7 @@ public class OperationField { return !mPossibleValues.isEmpty(); } + @Nullable public String getVarSize() { return mVarSize; } 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 20ba8c313b47b4bb7c66a268d5d290e53b34e50d..8da0e184cbe787c557c79631b6bfed3d64bf41d6 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 @@ -18,6 +18,8 @@ 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 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; @@ -58,15 +60,17 @@ public class BitmapData implements Operation, SerializableToString { } @Override - public void write(WireBuffer buffer) { + public void write(@NonNull WireBuffer buffer) { apply(buffer, mImageId, mImageWidth, mImageHeight, mBitmap); } + @NonNull @Override public String toString() { return "BITMAP DATA " + mImageId; } + @NonNull public static String name() { return CLASS_NAME; } @@ -75,7 +79,12 @@ public class BitmapData implements Operation, SerializableToString { return OP_CODE; } - public static void apply(WireBuffer buffer, int imageId, int width, int height, byte[] bitmap) { + public static void apply( + @NonNull WireBuffer buffer, + int imageId, + int width, + int height, + @NonNull byte[] bitmap) { buffer.start(OP_CODE); buffer.writeInt(imageId); buffer.writeInt(width); @@ -83,7 +92,7 @@ public class BitmapData implements Operation, SerializableToString { buffer.writeBuffer(bitmap); } - public static void read(WireBuffer buffer, List operations) { + public static void read(@NonNull WireBuffer buffer, @NonNull List operations) { int imageId = buffer.readInt(); int width = buffer.readInt(); int height = buffer.readInt(); @@ -97,7 +106,7 @@ public class BitmapData implements Operation, SerializableToString { operations.add(new BitmapData(imageId, width, height, bitmap)); } - public static void documentation(DocumentationBuilder doc) { + public static void documentation(@NonNull DocumentationBuilder doc) { doc.operation("Data Operations", OP_CODE, CLASS_NAME) .description("Bitmap data") .field(DocumentedOperation.INT, "id", "id of bitmap data") @@ -107,17 +116,18 @@ public class BitmapData implements Operation, SerializableToString { } @Override - public void apply(RemoteContext context) { + public void apply(@NonNull RemoteContext context) { context.loadBitmap(mImageId, mImageWidth, mImageHeight, mBitmap); } + @NonNull @Override public String deepToString(String indent) { return indent + toString(); } @Override - public void serializeToString(int indent, StringSerializer serializer) { + public void serializeToString(int indent, @NonNull StringSerializer serializer) { serializer.append( indent, CLASS_NAME + " id " + mImageId + " (" + mImageWidth + "x" + mImageHeight + ")"); 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 8b9e5a8d7625d142247b6055e64cc2765e3e8317..83d0ac7a1eb2b9f1d2e174b6b05b36249846bce4 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 @@ -15,6 +15,8 @@ */ package com.android.internal.widget.remotecompose.core.operations; +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.RemoteComposeOperation; @@ -67,10 +69,11 @@ public class ClickArea implements RemoteComposeOperation { } @Override - public void write(WireBuffer buffer) { + public void write(@NonNull WireBuffer buffer) { apply(buffer, mId, mContentDescription, mLeft, mTop, mRight, mBottom, mMetadata); } + @NonNull @Override public String toString() { return "CLICK_AREA <" @@ -97,18 +100,20 @@ public class ClickArea implements RemoteComposeOperation { } @Override - public void apply(RemoteContext context) { + public void apply(@NonNull RemoteContext context) { if (context.getMode() != RemoteContext.ContextMode.DATA) { return; } context.addClickArea(mId, mContentDescription, mLeft, mTop, mRight, mBottom, mMetadata); } + @NonNull @Override public String deepToString(String indent) { return indent + toString(); } + @NonNull public static String name() { return CLASS_NAME; } @@ -118,7 +123,7 @@ public class ClickArea implements RemoteComposeOperation { } public static void apply( - WireBuffer buffer, + @NonNull WireBuffer buffer, int id, int contentDescription, float left, @@ -136,7 +141,7 @@ public class ClickArea implements RemoteComposeOperation { buffer.writeInt(metadata); } - public static void read(WireBuffer buffer, List operations) { + public static void read(@NonNull WireBuffer buffer, @NonNull List operations) { int id = buffer.readInt(); int contentDescription = buffer.readInt(); float left = buffer.readFloat(); @@ -149,7 +154,7 @@ public class ClickArea implements RemoteComposeOperation { operations.add(clickArea); } - public static void documentation(DocumentationBuilder doc) { + public static void documentation(@NonNull DocumentationBuilder doc) { doc.operation("Canvas Operations", OP_CODE, CLASS_NAME) .description("Define a region you can click on") .field(DocumentedOperation.FLOAT, "left", "The left side of the region") diff --git a/core/java/com/android/internal/widget/remotecompose/core/operations/ClipPath.java b/core/java/com/android/internal/widget/remotecompose/core/operations/ClipPath.java index 96b600acc971f349da4e1c173ba6e28d8db2a1a9..db93829586bbda7e478a9bf5e60c39925bad7f80 100644 --- a/core/java/com/android/internal/widget/remotecompose/core/operations/ClipPath.java +++ b/core/java/com/android/internal/widget/remotecompose/core/operations/ClipPath.java @@ -15,6 +15,8 @@ */ package com.android.internal.widget.remotecompose.core.operations; +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,16 +59,17 @@ public class ClipPath extends PaintOperation { public static final int UNDEFINED = PATH_CLIP_UNDEFINED; @Override - public void write(WireBuffer buffer) { + public void write(@NonNull WireBuffer buffer) { apply(buffer, mId); } + @NonNull @Override public String toString() { return "ClipPath " + mId + ";"; } - public static void read(WireBuffer buffer, List operations) { + public static void read(@NonNull WireBuffer buffer, @NonNull List operations) { int pack = buffer.readInt(); int id = pack & 0xFFFFF; int regionOp = pack >> 24; @@ -74,6 +77,7 @@ public class ClipPath extends PaintOperation { operations.add(op); } + @NonNull public static String name() { return CLASS_NAME; } @@ -82,19 +86,19 @@ public class ClipPath extends PaintOperation { return OP_CODE; } - public static void apply(WireBuffer buffer, int id) { + public static void apply(@NonNull WireBuffer buffer, int id) { buffer.start(OP_CODE); buffer.writeInt(id); } - public static void documentation(DocumentationBuilder doc) { + public static void documentation(@NonNull DocumentationBuilder doc) { doc.operation("Canvas Operations", OP_CODE, CLASS_NAME) .description("Intersect the current clip with the path") .field(DocumentedOperation.INT, "id", "id of the path"); } @Override - public void paint(PaintContext context) { + public void paint(@NonNull PaintContext context) { context.clipPath(mId, mRegionOp); } } diff --git a/core/java/com/android/internal/widget/remotecompose/core/operations/ClipRect.java b/core/java/com/android/internal/widget/remotecompose/core/operations/ClipRect.java index b101bfb2d151d45f884556e2af4300437f4c6bc7..df54fb1ed834d5235583ff19a9769ff77e9670ef 100644 --- a/core/java/com/android/internal/widget/remotecompose/core/operations/ClipRect.java +++ b/core/java/com/android/internal/widget/remotecompose/core/operations/ClipRect.java @@ -15,6 +15,8 @@ */ package com.android.internal.widget.remotecompose.core.operations; +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; @@ -29,7 +31,7 @@ public class ClipRect extends DrawBase4 { public static final int OP_CODE = Operations.CLIP_RECT; public static final String CLASS_NAME = "ClipRect"; - public static void read(WireBuffer buffer, List operations) { + public static void read(@NonNull WireBuffer buffer, @NonNull List operations) { Maker m = ClipRect::new; read(m, buffer, operations); } @@ -38,16 +40,17 @@ public class ClipRect extends DrawBase4 { return OP_CODE; } + @NonNull public static String name() { return CLASS_NAME; } @Override - protected void write(WireBuffer buffer, float v1, float v2, float v3, float v4) { + protected void write(@NonNull WireBuffer buffer, float v1, float v2, float v3, float v4) { apply(buffer, v1, v2, v3, v4); } - public static void documentation(DocumentationBuilder doc) { + public static void documentation(@NonNull DocumentationBuilder doc) { doc.operation("Expressions Operations", OP_CODE, CLASS_NAME) .description("Intersect the current clip with rectangle") .field( @@ -74,7 +77,7 @@ public class ClipRect extends DrawBase4 { } @Override - public void paint(PaintContext context) { + public void paint(@NonNull PaintContext context) { context.clipRect(mX1, mY1, mX2, mY2); } @@ -87,7 +90,7 @@ public class ClipRect extends DrawBase4 { * @param x2 end x of the DrawOval * @param y2 end y of the DrawOval */ - public static void apply(WireBuffer buffer, float x1, float y1, float x2, float y2) { + public static void apply(@NonNull WireBuffer buffer, float x1, float y1, float x2, float y2) { write(buffer, OP_CODE, x1, y1, x2, y2); } } 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 19d80daf0c8f35478c0628737fab051208ab36d0..929c9a603079996b7ebba4f602c6d492c25f0dbe 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 @@ -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; @@ -39,15 +41,17 @@ public class ColorConstant implements Operation { } @Override - public void write(WireBuffer buffer) { + public void write(@NonNull WireBuffer buffer) { apply(buffer, mColorId, mColor); } + @NonNull @Override public String toString() { return "ColorConstant[" + mColorId + "] = " + Utils.colorInt(mColor) + ""; } + @NonNull public static String name() { return CLASS_NAME; } @@ -63,19 +67,19 @@ public class ColorConstant implements Operation { * @param colorId * @param color */ - public static void apply(WireBuffer buffer, int colorId, int color) { + public static void apply(@NonNull WireBuffer buffer, int colorId, int color) { buffer.start(OP_CODE); buffer.writeInt(colorId); buffer.writeInt(color); } - public static void read(WireBuffer buffer, List operations) { + public static void read(@NonNull WireBuffer buffer, @NonNull List operations) { int colorId = buffer.readInt(); int color = buffer.readInt(); operations.add(new ColorConstant(colorId, color)); } - public static void documentation(DocumentationBuilder doc) { + public static void documentation(@NonNull DocumentationBuilder doc) { doc.operation("Expressions Operations", OP_CODE, CLASS_NAME) .description("Define a Color") .field(DocumentedOperation.INT, "id", "Id of the color") @@ -83,10 +87,11 @@ public class ColorConstant implements Operation { } @Override - public void apply(RemoteContext context) { + public void apply(@NonNull RemoteContext context) { context.loadColor(mColorId, mColor); } + @NonNull @Override public String deepToString(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 b6041eaeacdc473ad7229c99517a0ec384ac064a..3d840c5b82039a2208fd8da7e58e2622430548da 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 @@ -18,6 +18,8 @@ package com.android.internal.widget.remotecompose.core.operations; 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.RemoteContext; @@ -94,7 +96,7 @@ public class ColorExpression implements Operation, VariableSupport { } @Override - public void updateVariables(RemoteContext context) { + public void updateVariables(@NonNull RemoteContext context) { if (mMode == 4) { if (Float.isNaN(mHue)) { mOutHue = context.getFloat(Utils.idFromNan(mHue)); @@ -118,7 +120,7 @@ public class ColorExpression implements Operation, VariableSupport { } @Override - public void registerListening(RemoteContext context) { + public void registerListening(@NonNull RemoteContext context) { if (mMode == 4) { if (Float.isNaN(mHue)) { context.listensTo(Utils.idFromNan(mHue), this); @@ -143,7 +145,7 @@ public class ColorExpression implements Operation, VariableSupport { } @Override - public void apply(RemoteContext context) { + public void apply(@NonNull RemoteContext context) { if (mMode == 4) { context.loadColor( mId, (mAlpha << 24) | (0xFFFFFF & Utils.hsvToRgb(mOutHue, mOutSat, mOutValue))); @@ -164,11 +166,12 @@ public class ColorExpression implements Operation, VariableSupport { } @Override - public void write(WireBuffer buffer) { + public void write(@NonNull WireBuffer buffer) { int mode = mMode | (mAlpha << 16); apply(buffer, mId, mode, mColor1, mColor2, mTween); } + @NonNull @Override public String toString() { if (mMode == 4) { @@ -196,6 +199,7 @@ public class ColorExpression implements Operation, VariableSupport { + ")"; } + @NonNull public static String name() { return CLASS_NAME; } @@ -215,7 +219,7 @@ public class ColorExpression implements Operation, VariableSupport { * @param tween */ public static void apply( - WireBuffer buffer, int id, int mode, int color1, int color2, float tween) { + @NonNull WireBuffer buffer, int id, int mode, int color1, int color2, float tween) { buffer.start(OP_CODE); buffer.writeInt(id); buffer.writeInt(mode); @@ -224,7 +228,7 @@ public class ColorExpression implements Operation, VariableSupport { buffer.writeFloat(tween); } - public static void read(WireBuffer buffer, List operations) { + public static void read(@NonNull WireBuffer buffer, @NonNull List operations) { int id = buffer.readInt(); int mode = buffer.readInt(); int color1 = buffer.readInt(); @@ -234,7 +238,7 @@ public class ColorExpression implements Operation, VariableSupport { operations.add(new ColorExpression(id, mode, color1, color2, tween)); } - public static void documentation(DocumentationBuilder doc) { + public static void documentation(@NonNull DocumentationBuilder doc) { doc.operation("Expressions Operations", OP_CODE, CLASS_NAME) .description("A Color defined by an expression") .field(DocumentedOperation.INT, "id", "Id of the color") @@ -249,6 +253,7 @@ public class ColorExpression implements Operation, VariableSupport { .field(FLOAT, "tween", "32 bit ARGB color"); } + @NonNull @Override public String deepToString(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 992972076839c90d30af50ad5773f705583b2232..142c97b24d2e531dc9a4a5488c05970271b46c4d 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 @@ -17,6 +17,9 @@ 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; import com.android.internal.widget.remotecompose.core.RemoteContext; @@ -43,10 +46,12 @@ public class ComponentValue implements Operation, SerializableToString { return OP_CODE; } + @NonNull public static String name() { return CLASS_NAME; } + @NonNull @Override public String toString() { return CLASS_NAME + "(" + mType + ", " + mComponentID + ", " + mValueId + ")"; @@ -65,7 +70,7 @@ public class ComponentValue implements Operation, SerializableToString { } @Override - public void write(WireBuffer buffer) { + public void write(@NonNull WireBuffer buffer) { apply(buffer, mType, mComponentID, mValueId); } @@ -74,7 +79,7 @@ public class ComponentValue implements Operation, SerializableToString { // Nothing } - public static void read(WireBuffer buffer, List operations) { + public static void read(@NonNull WireBuffer buffer, @NonNull List operations) { int type = buffer.readInt(); int componentId = buffer.readInt(); int valueId = buffer.readInt(); @@ -82,7 +87,7 @@ public class ComponentValue implements Operation, SerializableToString { operations.add(op); } - public static void documentation(DocumentationBuilder doc) { + public static void documentation(@NonNull DocumentationBuilder doc) { doc.operation("Expressions Operations", OP_CODE, CLASS_NAME) .description("Encode a component-related value (eg its width, height etc.)") .field( @@ -111,20 +116,21 @@ public class ComponentValue implements Operation, SerializableToString { * @param componentId component id to reference * @param valueId remote float used to represent the component value */ - public static void apply(WireBuffer buffer, int type, int componentId, int valueId) { + public static void apply(@NonNull WireBuffer buffer, int type, int componentId, int valueId) { buffer.start(OP_CODE); buffer.writeInt(type); buffer.writeInt(componentId); buffer.writeInt(valueId); } + @Nullable @Override public String deepToString(String indent) { return null; } @Override - public void serializeToString(int indent, StringSerializer serializer) { + public void serializeToString(int indent, @NonNull StringSerializer serializer) { String type = "WIDTH"; if (mType == HEIGHT) { type = "HEIGHT"; 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 00758694c25454fd4b3000b375098c7fe85548bc..ba02b91b36eda72c0aab9a0e7e6dd6eddd75be5e 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 @@ -18,6 +18,8 @@ package com.android.internal.widget.remotecompose.core.operations; import static com.android.internal.widget.remotecompose.core.documentation.DocumentedOperation.FLOAT_ARRAY; 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; @@ -48,7 +50,7 @@ public class DataListFloat implements VariableSupport, ArrayAccess, Operation { } @Override - public void registerListening(RemoteContext context) { + public void registerListening(@NonNull RemoteContext context) { context.addCollection(mId, this); for (float value : mValues) { if (Utils.isVariable(value)) { @@ -58,16 +60,17 @@ public class DataListFloat implements VariableSupport, ArrayAccess, Operation { } @Override - public void write(WireBuffer buffer) { + public void write(@NonNull WireBuffer buffer) { apply(buffer, mId, mValues); } + @NonNull @Override public String toString() { return "DataListFloat[" + Utils.idString(mId) + "] " + Arrays.toString(mValues); } - public static void apply(WireBuffer buffer, int id, float[] values) { + public static void apply(@NonNull WireBuffer buffer, int id, @NonNull float[] values) { buffer.start(OP_CODE); buffer.writeInt(id); buffer.writeInt(values.length); @@ -76,7 +79,7 @@ public class DataListFloat implements VariableSupport, ArrayAccess, Operation { } } - public static void read(WireBuffer buffer, List operations) { + public static void read(@NonNull WireBuffer buffer, @NonNull List operations) { int id = buffer.readInt(); int len = buffer.readInt(); if (len > MAX_FLOAT_ARRAY) { @@ -90,7 +93,7 @@ public class DataListFloat implements VariableSupport, ArrayAccess, Operation { operations.add(data); } - public static void documentation(DocumentationBuilder doc) { + public static void documentation(@NonNull DocumentationBuilder doc) { doc.operation("Data Operations", OP_CODE, CLASS_NAME) .description("a list of Floats") .field(DocumentedOperation.INT, "id", "id the array (2xxxxx)") @@ -98,13 +101,14 @@ public class DataListFloat implements VariableSupport, ArrayAccess, Operation { .field(FLOAT_ARRAY, "values", "length", "array of floats"); } + @NonNull @Override public String deepToString(String indent) { return indent + toString(); } @Override - public void apply(RemoteContext context) { + public void apply(@NonNull RemoteContext context) { context.addCollection(mId, this); } 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 c43dab4bbee04645a8afc94edf6a17ce3362b22f..b9820f856a92bf93a926f5f31cde04bb973a94cf 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 @@ -18,6 +18,8 @@ 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 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; @@ -49,16 +51,17 @@ public class DataListIds implements VariableSupport, ArrayAccess, Operation { public void registerListening(RemoteContext context) {} @Override - public void write(WireBuffer buffer) { + public void write(@NonNull WireBuffer buffer) { apply(buffer, mId, mIds); } + @NonNull @Override public String toString() { return "map[" + Utils.idString(mId) + "] \"" + Arrays.toString(mIds) + "\""; } - public static void apply(WireBuffer buffer, int id, int[] ids) { + public static void apply(@NonNull WireBuffer buffer, int id, @NonNull int[] ids) { buffer.start(OP_CODE); buffer.writeInt(id); buffer.writeInt(ids.length); @@ -67,7 +70,7 @@ public class DataListIds implements VariableSupport, ArrayAccess, Operation { } } - public static void read(WireBuffer buffer, List operations) { + public static void read(@NonNull WireBuffer buffer, @NonNull List operations) { int id = buffer.readInt(); int len = buffer.readInt(); if (len > MAX_LIST) { @@ -81,7 +84,7 @@ public class DataListIds implements VariableSupport, ArrayAccess, Operation { operations.add(data); } - public static void documentation(DocumentationBuilder doc) { + public static void documentation(@NonNull DocumentationBuilder doc) { doc.operation("Data Operations", OP_CODE, CLASS_NAME) .description("a list of id's") .field(DocumentedOperation.INT, "id", "id the array") @@ -89,13 +92,14 @@ public class DataListIds implements VariableSupport, ArrayAccess, Operation { .field(INT_ARRAY, "ids[n]", "length", "ids of other variables"); } + @NonNull @Override public String deepToString(String indent) { return indent + toString(); } @Override - public void apply(RemoteContext context) { + public void apply(@NonNull RemoteContext context) { context.addCollection(mId, this); } 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 75db29d2781ec41469032fbbee7d35492c0b3db2..fb559bbf18635754f494a3ac01d276bf587a4629 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 @@ -18,6 +18,8 @@ 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.UTF8; +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; @@ -64,10 +66,11 @@ public class DataMapIds implements Operation { } @Override - public void write(WireBuffer buffer) { + public void write(@NonNull WireBuffer buffer) { apply(buffer, mId, mDataMap.mNames, mDataMap.mTypes, mDataMap.mIds); } + @NonNull @Override public String toString() { StringBuilder builder = new StringBuilder("DataMapIds[" + Utils.idString(mId) + "] "); @@ -84,7 +87,8 @@ public class DataMapIds implements Operation { return builder.toString(); } - public static void apply(WireBuffer buffer, int id, String[] names, byte[] type, int[] ids) { + public static void apply( + @NonNull WireBuffer buffer, int id, @NonNull String[] names, byte[] type, int[] ids) { buffer.start(OP_CODE); buffer.writeInt(id); buffer.writeInt(names.length); @@ -95,7 +99,7 @@ public class DataMapIds implements Operation { } } - public static void read(WireBuffer buffer, List operations) { + public static void read(@NonNull WireBuffer buffer, @NonNull List operations) { int id = buffer.readInt(); int len = buffer.readInt(); if (len > MAX_MAP) { @@ -113,7 +117,7 @@ public class DataMapIds implements Operation { operations.add(data); } - public static void documentation(DocumentationBuilder doc) { + public static void documentation(@NonNull DocumentationBuilder doc) { doc.operation("Data Operations", OP_CODE, CLASS_NAME) .description("Encode a collection of name id pairs") .field(INT, "id", "id the array") @@ -122,13 +126,14 @@ public class DataMapIds implements Operation { .field(UTF8, "id[0]", "length", "path encoded as floats"); } + @NonNull @Override public String deepToString(String indent) { return indent + toString(); } @Override - public void apply(RemoteContext context) { + public void apply(@NonNull RemoteContext context) { context.putDataMap(mId, mDataMap); } } diff --git a/core/java/com/android/internal/widget/remotecompose/core/operations/DrawArc.java b/core/java/com/android/internal/widget/remotecompose/core/operations/DrawArc.java index e078307f3bd9a003e385583f3fbefdf2c464c162..629f78647079760946d234c08805e31e79a0aa4b 100644 --- a/core/java/com/android/internal/widget/remotecompose/core/operations/DrawArc.java +++ b/core/java/com/android/internal/widget/remotecompose/core/operations/DrawArc.java @@ -15,6 +15,8 @@ */ package com.android.internal.widget.remotecompose.core.operations; +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; @@ -28,7 +30,7 @@ public class DrawArc extends DrawBase6 { public static final int OP_CODE = Operations.DRAW_ARC; private static final String CLASS_NAME = "DrawArc"; - public static void read(WireBuffer buffer, List operations) { + public static void read(@NonNull WireBuffer buffer, @NonNull List operations) { Maker m = DrawArc::new; read(m, buffer, operations); } @@ -49,7 +51,13 @@ public class DrawArc extends DrawBase6 { * @param v6 Sweep angle (in degrees) measured clockwise */ public static void apply( - 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) { buffer.start(OP_CODE); buffer.writeFloat(v1); buffer.writeFloat(v2); @@ -61,11 +69,17 @@ public class DrawArc extends DrawBase6 { @Override protected 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) { apply(buffer, v1, v2, v3, v4, v5, v6); } - public static void documentation(DocumentationBuilder doc) { + public static void documentation(@NonNull DocumentationBuilder doc) { doc.operation("Canvas Operations", OP_CODE, CLASS_NAME) .description( "Draw the specified arc" @@ -90,7 +104,7 @@ public class DrawArc extends DrawBase6 { } @Override - public void paint(PaintContext context) { + public void paint(@NonNull PaintContext context) { context.drawArc(mV1, mV2, mV3, mV4, mV5, mV6); } } 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 c678cc4a36bea01296a446e9680e1166c94ad414..984599e09c1944d0cafe5883efd8e4d5919524bf 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 @@ -17,6 +17,9 @@ package com.android.internal.widget.remotecompose.core.operations; import static com.android.internal.widget.remotecompose.core.operations.Utils.floatToString; +import android.annotation.NonNull; +import android.annotation.Nullable; + import com.android.internal.widget.remotecompose.core.Operation; import com.android.internal.widget.remotecompose.core.PaintOperation; import com.android.internal.widget.remotecompose.core.RemoteContext; @@ -27,7 +30,7 @@ import java.util.List; /** Base class for commands that take 3 float */ public abstract class DrawBase2 extends PaintOperation implements VariableSupport { - protected String mName = "DrawRectBase"; + @NonNull protected String mName = "DrawRectBase"; float mV1; float mV2; float mValue1; @@ -41,13 +44,13 @@ public abstract class DrawBase2 extends PaintOperation implements VariableSuppor } @Override - public void updateVariables(RemoteContext context) { + public void updateVariables(@NonNull RemoteContext context) { mV1 = Float.isNaN(mValue1) ? context.getFloat(Utils.idFromNan(mValue1)) : mValue1; mV2 = Float.isNaN(mValue2) ? context.getFloat(Utils.idFromNan(mValue2)) : mValue2; } @Override - public void registerListening(RemoteContext context) { + public void registerListening(@NonNull RemoteContext context) { if (Float.isNaN(mValue1)) { context.listensTo(Utils.idFromNan(mValue1), this); } @@ -67,12 +70,14 @@ public abstract class DrawBase2 extends PaintOperation implements VariableSuppor DrawBase2 create(float v1, float v2); } + @NonNull @Override public String toString() { return mName + " " + floatToString(mV1) + " " + floatToString(mV2); } - public static void read(Maker maker, WireBuffer buffer, List operations) { + public static void read( + @NonNull Maker maker, @NonNull WireBuffer buffer, @NonNull List operations) { float v1 = buffer.readFloat(); float v2 = buffer.readFloat(); @@ -87,6 +92,7 @@ public abstract class DrawBase2 extends PaintOperation implements VariableSuppor * @param y1 * @return */ + @Nullable public Operation construct(float x1, float y1) { return null; } @@ -99,7 +105,7 @@ public abstract class DrawBase2 extends PaintOperation implements VariableSuppor * @param x1 * @param y1 */ - protected static void write(WireBuffer buffer, int opCode, float x1, float y1) { + protected static void write(@NonNull WireBuffer buffer, int opCode, float x1, float y1) { buffer.start(opCode); buffer.writeFloat(x1); buffer.writeFloat(y1); 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 e1108e906d8d1ba3244928ec229101024c027d39..825da52400324fd9bd3bf06894851396953327f7 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 @@ -17,6 +17,9 @@ package com.android.internal.widget.remotecompose.core.operations; import static com.android.internal.widget.remotecompose.core.operations.Utils.floatToString; +import android.annotation.NonNull; +import android.annotation.Nullable; + import com.android.internal.widget.remotecompose.core.Operation; import com.android.internal.widget.remotecompose.core.PaintOperation; import com.android.internal.widget.remotecompose.core.RemoteContext; @@ -28,7 +31,7 @@ import java.util.List; /** Base class for commands that take 3 float */ public abstract class DrawBase3 extends PaintOperation implements VariableSupport { - protected String mName = "DrawRectBase"; + @NonNull protected String mName = "DrawRectBase"; float mV1; float mV2; float mV3; @@ -47,14 +50,14 @@ public abstract class DrawBase3 extends PaintOperation implements VariableSuppor } @Override - public void updateVariables(RemoteContext context) { + public void updateVariables(@NonNull RemoteContext context) { mV1 = Utils.isVariable(mValue1) ? context.getFloat(Utils.idFromNan(mValue1)) : mValue1; mV2 = Utils.isVariable(mValue2) ? context.getFloat(Utils.idFromNan(mValue2)) : mValue2; mV3 = Utils.isVariable(mValue3) ? context.getFloat(Utils.idFromNan(mValue3)) : mValue3; } @Override - public void registerListening(RemoteContext context) { + public void registerListening(@NonNull RemoteContext context) { if (Utils.isVariable(mValue1)) { context.listensTo(Utils.idFromNan(mValue1), this); } @@ -77,6 +80,7 @@ public abstract class DrawBase3 extends PaintOperation implements VariableSuppor DrawBase3 create(float v1, float v2, float v3); } + @NonNull @Override public String toString() { return mName @@ -88,7 +92,8 @@ public abstract class DrawBase3 extends PaintOperation implements VariableSuppor + floatToString(mV3); } - public static void read(Maker maker, WireBuffer buffer, List operations) { + public static void read( + @NonNull Maker maker, @NonNull WireBuffer buffer, @NonNull List operations) { float v1 = buffer.readFloat(); float v2 = buffer.readFloat(); float v3 = buffer.readFloat(); @@ -104,6 +109,7 @@ public abstract class DrawBase3 extends PaintOperation implements VariableSuppor * @param x2 * @return */ + @Nullable public Operation construct(float x1, float y1, float x2) { return null; } 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 09f0df985b5ce63418972fae5181ca74442e1dc7..a23bcb9dca78392c75e488f11b1e022e945162cf 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 @@ -17,6 +17,9 @@ package com.android.internal.widget.remotecompose.core.operations; import static com.android.internal.widget.remotecompose.core.operations.Utils.floatToString; +import android.annotation.NonNull; +import android.annotation.Nullable; + import com.android.internal.widget.remotecompose.core.Operation; import com.android.internal.widget.remotecompose.core.PaintOperation; import com.android.internal.widget.remotecompose.core.RemoteContext; @@ -27,7 +30,7 @@ import java.util.List; /** Base class for draw commands that take 4 floats */ public abstract class DrawBase4 extends PaintOperation implements VariableSupport { - protected String mName = "DrawRectBase"; + @NonNull protected String mName = "DrawRectBase"; protected float mX1; protected float mY1; protected float mX2; @@ -50,7 +53,7 @@ public abstract class DrawBase4 extends PaintOperation implements VariableSuppor } @Override - public void updateVariables(RemoteContext context) { + public void updateVariables(@NonNull RemoteContext context) { mX1 = Float.isNaN(mX1Value) ? context.getFloat(Utils.idFromNan(mX1Value)) : mX1Value; mY1 = Float.isNaN(mY1Value) ? context.getFloat(Utils.idFromNan(mY1Value)) : mY1Value; mX2 = Float.isNaN(mX2Value) ? context.getFloat(Utils.idFromNan(mX2Value)) : mX2Value; @@ -58,7 +61,7 @@ public abstract class DrawBase4 extends PaintOperation implements VariableSuppor } @Override - public void registerListening(RemoteContext context) { + public void registerListening(@NonNull RemoteContext context) { if (Float.isNaN(mX1Value)) { context.listensTo(Utils.idFromNan(mX1Value), this); } @@ -84,6 +87,7 @@ public abstract class DrawBase4 extends PaintOperation implements VariableSuppor DrawBase4 create(float v1, float v2, float v3, float v4); } + @NonNull @Override public String toString() { return mName @@ -97,7 +101,8 @@ public abstract class DrawBase4 extends PaintOperation implements VariableSuppor + floatToString(mY2Value, mY2); } - public static void read(Maker maker, WireBuffer buffer, List operations) { + public static void read( + @NonNull Maker maker, @NonNull WireBuffer buffer, @NonNull List operations) { float v1 = buffer.readFloat(); float v2 = buffer.readFloat(); float v3 = buffer.readFloat(); @@ -116,6 +121,7 @@ public abstract class DrawBase4 extends PaintOperation implements VariableSuppor * @param y2 * @return */ + @Nullable public Operation construct(float x1, float y1, float x2, float y2) { return null; } @@ -131,7 +137,7 @@ public abstract class DrawBase4 extends PaintOperation implements VariableSuppor * @param y2 */ protected static void write( - WireBuffer buffer, int opCode, float x1, float y1, float x2, float y2) { + @NonNull WireBuffer buffer, int opCode, float x1, float y1, float x2, float y2) { buffer.start(opCode); buffer.writeFloat(x1); buffer.writeFloat(y1); 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 e071d5f2096f589226e0b78dee53fc92bdca6e55..68c9f8cdc462514e87f0338191ecb471328365f3 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 @@ -15,6 +15,9 @@ */ package com.android.internal.widget.remotecompose.core.operations; +import android.annotation.NonNull; +import android.annotation.Nullable; + import com.android.internal.widget.remotecompose.core.Operation; import com.android.internal.widget.remotecompose.core.PaintOperation; import com.android.internal.widget.remotecompose.core.RemoteContext; @@ -25,7 +28,7 @@ import java.util.List; /** Base class for draw commands the take 6 floats */ public abstract class DrawBase6 extends PaintOperation implements VariableSupport { - protected String mName = "DrawRectBase"; + @NonNull protected String mName = "DrawRectBase"; float mV1; float mV2; float mV3; @@ -56,7 +59,7 @@ public abstract class DrawBase6 extends PaintOperation implements VariableSuppor } @Override - public void updateVariables(RemoteContext context) { + public void updateVariables(@NonNull RemoteContext context) { mV1 = Float.isNaN(mValue1) ? context.getFloat(Utils.idFromNan(mValue1)) : mValue1; mV2 = Float.isNaN(mValue2) ? context.getFloat(Utils.idFromNan(mValue2)) : mValue2; mV3 = Float.isNaN(mValue3) ? context.getFloat(Utils.idFromNan(mValue3)) : mValue3; @@ -66,7 +69,7 @@ public abstract class DrawBase6 extends PaintOperation implements VariableSuppor } @Override - public void registerListening(RemoteContext context) { + public void registerListening(@NonNull RemoteContext context) { if (Float.isNaN(mValue1)) { context.listensTo(Utils.idFromNan(mValue1), this); } @@ -95,6 +98,7 @@ public abstract class DrawBase6 extends PaintOperation implements VariableSuppor protected abstract void write( WireBuffer buffer, float v1, float v2, float v3, float v4, float v5, float v6); + @NonNull @Override public String toString() { return mName @@ -112,7 +116,8 @@ public abstract class DrawBase6 extends PaintOperation implements VariableSuppor DrawBase6 create(float v1, float v2, float v3, float v4, float v5, float v6); } - public static void read(Maker build, WireBuffer buffer, List operations) { + public static void read( + @NonNull Maker build, @NonNull WireBuffer buffer, @NonNull List operations) { float sv1 = buffer.readFloat(); float sv2 = buffer.readFloat(); float sv3 = buffer.readFloat(); @@ -135,10 +140,12 @@ public abstract class DrawBase6 extends PaintOperation implements VariableSuppor * @param v6 * @return */ + @Nullable public Operation construct(float v1, float v2, float v3, float v4, float v5, float v6) { return null; } + @NonNull public static String name() { return "DrawBase6"; } diff --git a/core/java/com/android/internal/widget/remotecompose/core/operations/DrawBitmap.java b/core/java/com/android/internal/widget/remotecompose/core/operations/DrawBitmap.java index 0b43fd24556a76bb99a004fd1d31571b0b5fb422..9c23c95599533e99ee8681c69e655c796b33700a 100644 --- a/core/java/com/android/internal/widget/remotecompose/core/operations/DrawBitmap.java +++ b/core/java/com/android/internal/widget/remotecompose/core/operations/DrawBitmap.java @@ -18,6 +18,8 @@ package com.android.internal.widget.remotecompose.core.operations; 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; @@ -54,7 +56,7 @@ public class DrawBitmap extends PaintOperation implements VariableSupport { } @Override - public void updateVariables(RemoteContext context) { + public void updateVariables(@NonNull RemoteContext context) { mOutputLeft = Float.isNaN(mLeft) ? context.getFloat(Utils.idFromNan(mLeft)) : mLeft; mOutputTop = Float.isNaN(mTop) ? context.getFloat(Utils.idFromNan(mTop)) : mTop; mOutputRight = Float.isNaN(mRight) ? context.getFloat(Utils.idFromNan(mRight)) : mRight; @@ -62,7 +64,7 @@ public class DrawBitmap extends PaintOperation implements VariableSupport { } @Override - public void registerListening(RemoteContext context) { + public void registerListening(@NonNull RemoteContext context) { if (Float.isNaN(mLeft)) { context.listensTo(Utils.idFromNan(mLeft), this); } @@ -78,10 +80,11 @@ public class DrawBitmap extends PaintOperation implements VariableSupport { } @Override - public void write(WireBuffer buffer) { + public void write(@NonNull WireBuffer buffer) { apply(buffer, mId, mLeft, mTop, mRight, mBottom, mDescriptionId); } + @NonNull @Override public String toString() { return "DrawBitmap (desc=" @@ -97,7 +100,7 @@ public class DrawBitmap extends PaintOperation implements VariableSupport { + ";"; } - public static void read(WireBuffer buffer, List operations) { + public static void read(@NonNull WireBuffer buffer, @NonNull List operations) { int id = buffer.readInt(); float sLeft = buffer.readFloat(); float srcTop = buffer.readFloat(); @@ -109,6 +112,7 @@ public class DrawBitmap extends PaintOperation implements VariableSupport { operations.add(op); } + @NonNull public static String name() { return CLASS_NAME; } @@ -118,7 +122,7 @@ public class DrawBitmap extends PaintOperation implements VariableSupport { } public static void apply( - WireBuffer buffer, + @NonNull WireBuffer buffer, int id, float left, float top, @@ -134,7 +138,7 @@ public class DrawBitmap extends PaintOperation implements VariableSupport { buffer.writeInt(descriptionId); } - public static void documentation(DocumentationBuilder doc) { + public static void documentation(@NonNull DocumentationBuilder doc) { doc.operation("Draw Operations", OP_CODE, CLASS_NAME) .description("Draw a bitmap") .field(INT, "id", "id of float") @@ -146,7 +150,7 @@ public class DrawBitmap extends PaintOperation implements VariableSupport { } @Override - public void paint(PaintContext context) { + public void paint(@NonNull PaintContext context) { context.drawBitmap(mId, mOutputLeft, mOutputTop, mOutputRight, mOutputBottom); } } diff --git a/core/java/com/android/internal/widget/remotecompose/core/operations/DrawBitmapInt.java b/core/java/com/android/internal/widget/remotecompose/core/operations/DrawBitmapInt.java index fc7482759369512272133b4f4762dc88ae8e641d..da9fe247bced4a62b6017e4d777fa0c51a48fad8 100644 --- a/core/java/com/android/internal/widget/remotecompose/core/operations/DrawBitmapInt.java +++ b/core/java/com/android/internal/widget/remotecompose/core/operations/DrawBitmapInt.java @@ -15,6 +15,8 @@ */ package com.android.internal.widget.remotecompose.core.operations; +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; @@ -64,7 +66,7 @@ public class DrawBitmapInt extends PaintOperation { } @Override - public void write(WireBuffer buffer) { + public void write(@NonNull WireBuffer buffer) { apply( buffer, mImageId, @@ -79,6 +81,7 @@ public class DrawBitmapInt extends PaintOperation { mContentDescId); } + @NonNull @Override public String toString() { return "DRAW_BITMAP_INT " @@ -103,6 +106,7 @@ public class DrawBitmapInt extends PaintOperation { + ";"; } + @NonNull public static String name() { return CLASS_NAME; } @@ -112,7 +116,7 @@ public class DrawBitmapInt extends PaintOperation { } public static void apply( - WireBuffer buffer, + @NonNull WireBuffer buffer, int imageId, int srcLeft, int srcTop, @@ -136,7 +140,7 @@ public class DrawBitmapInt extends PaintOperation { buffer.writeInt(cdId); } - public static void read(WireBuffer buffer, List operations) { + public static void read(@NonNull WireBuffer buffer, @NonNull List operations) { int imageId = buffer.readInt(); int sLeft = buffer.readInt(); int srcTop = buffer.readInt(); @@ -155,7 +159,7 @@ public class DrawBitmapInt extends PaintOperation { operations.add(op); } - public static void documentation(DocumentationBuilder doc) { + public static void documentation(@NonNull DocumentationBuilder doc) { doc.operation("Draw Operations", OP_CODE, CLASS_NAME) .description("Draw a bitmap using integer coordinates") .field(DocumentedOperation.INT, "id", "id of bitmap") @@ -171,7 +175,7 @@ public class DrawBitmapInt extends PaintOperation { } @Override - public void paint(PaintContext context) { + public void paint(@NonNull PaintContext context) { context.drawBitmap( mImageId, mSrcLeft, 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 22742c63dd2d3014406721616c11765cbfba7e46..e20bcd2d79b56e38f30df0a9fc4cd5280b52193c 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 @@ -15,6 +15,8 @@ */ package com.android.internal.widget.remotecompose.core.operations; +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; @@ -45,7 +47,7 @@ public class DrawBitmapScaled extends PaintOperation implements VariableSupport float mScaleFactor, mOutScaleFactor; int mScaleType; - ImageScaling mScaling = new ImageScaling(); + @NonNull ImageScaling mScaling = new ImageScaling(); public static final int SCALE_NONE = ImageScaling.SCALE_NONE; public static final int SCALE_INSIDE = ImageScaling.SCALE_INSIDE; public static final int SCALE_FILL_WIDTH = ImageScaling.SCALE_FILL_WIDTH; @@ -83,7 +85,7 @@ public class DrawBitmapScaled extends PaintOperation implements VariableSupport } @Override - public void updateVariables(RemoteContext context) { + public void updateVariables(@NonNull RemoteContext context) { mOutSrcLeft = Float.isNaN(mSrcLeft) ? context.getFloat(Utils.idFromNan(mSrcLeft)) : mSrcLeft; mOutSrcTop = Float.isNaN(mSrcTop) ? context.getFloat(Utils.idFromNan(mSrcTop)) : mSrcTop; @@ -109,7 +111,7 @@ public class DrawBitmapScaled extends PaintOperation implements VariableSupport } @Override - public void registerListening(RemoteContext context) { + public void registerListening(@NonNull RemoteContext context) { register(context, mSrcLeft); register(context, mSrcTop); register(context, mSrcRight); @@ -121,12 +123,13 @@ public class DrawBitmapScaled extends PaintOperation implements VariableSupport register(context, mScaleFactor); } - private void register(RemoteContext context, float value) { + private void register(@NonNull RemoteContext context, float value) { if (Float.isNaN(value)) { context.listensTo(Utils.idFromNan(value), this); } } + @NonNull static String str(float v) { String s = " " + (int) v; return s.substring(s.length() - 3); @@ -140,7 +143,7 @@ public class DrawBitmapScaled extends PaintOperation implements VariableSupport } @Override - public void write(WireBuffer buffer) { + public void write(@NonNull WireBuffer buffer) { apply( buffer, mImageId, @@ -157,6 +160,7 @@ public class DrawBitmapScaled extends PaintOperation implements VariableSupport mContentDescId); } + @NonNull @Override public String toString() { return "DrawBitmapScaled " @@ -185,6 +189,7 @@ public class DrawBitmapScaled extends PaintOperation implements VariableSupport + Utils.floatToString(mScaleFactor, mOutScaleFactor); } + @NonNull public static String name() { return CLASS_NAME; } @@ -194,7 +199,7 @@ public class DrawBitmapScaled extends PaintOperation implements VariableSupport } public static void apply( - WireBuffer buffer, + @NonNull WireBuffer buffer, int imageId, float srcLeft, float srcTop, @@ -225,7 +230,7 @@ public class DrawBitmapScaled extends PaintOperation implements VariableSupport buffer.writeInt(cdId); } - public static void read(WireBuffer buffer, List operations) { + public static void read(@NonNull WireBuffer buffer, @NonNull List operations) { int imageId = buffer.readInt(); float sLeft = buffer.readFloat(); @@ -258,7 +263,7 @@ public class DrawBitmapScaled extends PaintOperation implements VariableSupport operations.add(op); } - public static void documentation(DocumentationBuilder doc) { + public static void documentation(@NonNull DocumentationBuilder doc) { doc.operation("Draw Operations", OP_CODE, CLASS_NAME) .description("Draw a bitmap using integer coordinates") .field(DocumentedOperation.INT, "id", "id of bitmap") @@ -289,7 +294,7 @@ public class DrawBitmapScaled extends PaintOperation implements VariableSupport // } @Override - public void paint(PaintContext context) { + public void paint(@NonNull PaintContext context) { mScaling.setup( mOutSrcLeft, mOutSrcTop, diff --git a/core/java/com/android/internal/widget/remotecompose/core/operations/DrawCircle.java b/core/java/com/android/internal/widget/remotecompose/core/operations/DrawCircle.java index 04f095af29dc75d3a1640539afdda8ea98c87a73..11bd49a4a6514fa04e02f4591dac02dea6552437 100644 --- a/core/java/com/android/internal/widget/remotecompose/core/operations/DrawCircle.java +++ b/core/java/com/android/internal/widget/remotecompose/core/operations/DrawCircle.java @@ -15,6 +15,8 @@ */ package com.android.internal.widget.remotecompose.core.operations; +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; @@ -28,7 +30,7 @@ public class DrawCircle extends DrawBase3 { private static final int OP_CODE = Operations.DRAW_CIRCLE; private static final String CLASS_NAME = "DrawCircle"; - public static void read(WireBuffer buffer, List operations) { + public static void read(@NonNull WireBuffer buffer, @NonNull List operations) { Maker m = DrawCircle::new; read(m, buffer, operations); } @@ -37,11 +39,12 @@ public class DrawCircle extends DrawBase3 { return OP_CODE; } + @NonNull public static String name() { return CLASS_NAME; } - public static void documentation(DocumentationBuilder doc) { + public static void documentation(@NonNull DocumentationBuilder doc) { doc.operation("Canvas Operations", OP_CODE, CLASS_NAME) .description("Draw a Circle") .field( @@ -56,7 +59,7 @@ public class DrawCircle extends DrawBase3 { } @Override - protected void write(WireBuffer buffer, float v1, float v2, float v3) { + protected void write(@NonNull WireBuffer buffer, float v1, float v2, float v3) { apply(buffer, v1, v2, v3); } @@ -66,7 +69,7 @@ public class DrawCircle extends DrawBase3 { } @Override - public void paint(PaintContext context) { + public void paint(@NonNull PaintContext context) { context.drawCircle(mV1, mV2, mV3); } @@ -78,7 +81,7 @@ public class DrawCircle extends DrawBase3 { * @param y1 * @param x2 */ - public static void apply(WireBuffer buffer, float x1, float y1, float x2) { + public static void apply(@NonNull WireBuffer buffer, float x1, float y1, float x2) { buffer.start(OP_CODE); buffer.writeFloat(x1); buffer.writeFloat(y1); diff --git a/core/java/com/android/internal/widget/remotecompose/core/operations/DrawLine.java b/core/java/com/android/internal/widget/remotecompose/core/operations/DrawLine.java index dacbb0361761ffcf8015f51fba31dfcafcdc3b14..7310a9defba64bcb2884055a0272ac5c012b22f1 100644 --- a/core/java/com/android/internal/widget/remotecompose/core/operations/DrawLine.java +++ b/core/java/com/android/internal/widget/remotecompose/core/operations/DrawLine.java @@ -15,6 +15,8 @@ */ package com.android.internal.widget.remotecompose.core.operations; +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; @@ -30,7 +32,7 @@ public class DrawLine extends DrawBase4 implements SerializableToString { private static final int OP_CODE = Operations.DRAW_LINE; private static final String CLASS_NAME = "DrawLine"; - public static void read(WireBuffer buffer, List operations) { + public static void read(@NonNull WireBuffer buffer, @NonNull List operations) { Maker m = DrawLine::new; read(m, buffer, operations); } @@ -39,11 +41,12 @@ public class DrawLine extends DrawBase4 implements SerializableToString { return OP_CODE; } + @NonNull public static String name() { return CLASS_NAME; } - public static void documentation(DocumentationBuilder doc) { + public static void documentation(@NonNull DocumentationBuilder doc) { doc.operation("Canvas Operations", OP_CODE, CLASS_NAME) .description("Draw a line segment") .field( @@ -65,7 +68,7 @@ public class DrawLine extends DrawBase4 implements SerializableToString { } @Override - protected void write(WireBuffer buffer, float v1, float v2, float v3, float v4) { + protected void write(@NonNull WireBuffer buffer, float v1, float v2, float v3, float v4) { apply(buffer, v1, v2, v3, v4); } @@ -75,7 +78,7 @@ public class DrawLine extends DrawBase4 implements SerializableToString { } @Override - public void paint(PaintContext context) { + public void paint(@NonNull PaintContext context) { context.drawLine(mX1, mY1, mX2, mY2); } @@ -88,12 +91,12 @@ public class DrawLine extends DrawBase4 implements SerializableToString { * @param x2 end x of the line * @param y2 end y of the line */ - public static void apply(WireBuffer buffer, float x1, float y1, float x2, float y2) { + public static void apply(@NonNull WireBuffer buffer, float x1, float y1, float x2, float y2) { write(buffer, OP_CODE, x1, y1, x2, y2); } @Override - public void serializeToString(int indent, StringSerializer serializer) { + public void serializeToString(int indent, @NonNull StringSerializer serializer) { String x1 = "" + mX1; if (Float.isNaN(mX1Value)) { x1 = "[" + Utils.idFromNan(mX1Value) + " = " + mX1 + "]"; diff --git a/core/java/com/android/internal/widget/remotecompose/core/operations/DrawOval.java b/core/java/com/android/internal/widget/remotecompose/core/operations/DrawOval.java index 5d498e81c9d2d29c0de35e55d25dfd793ae5af60..aa5116e950c591f46e456f257b98e6df382ae8fb 100644 --- a/core/java/com/android/internal/widget/remotecompose/core/operations/DrawOval.java +++ b/core/java/com/android/internal/widget/remotecompose/core/operations/DrawOval.java @@ -15,6 +15,8 @@ */ package com.android.internal.widget.remotecompose.core.operations; +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; @@ -28,7 +30,7 @@ public class DrawOval extends DrawBase4 { private static final int OP_CODE = Operations.DRAW_OVAL; private static final String CLASS_NAME = "DrawOval"; - public static void read(WireBuffer buffer, List operations) { + public static void read(@NonNull WireBuffer buffer, @NonNull List operations) { Maker m = DrawOval::new; read(m, buffer, operations); } @@ -37,11 +39,12 @@ public class DrawOval extends DrawBase4 { return OP_CODE; } + @NonNull public static String name() { return CLASS_NAME; } - public static void documentation(DocumentationBuilder doc) { + public static void documentation(@NonNull DocumentationBuilder doc) { doc.operation("Canvas Operations", OP_CODE, CLASS_NAME) .description("Draw the specified oval") .field(DocumentedOperation.FLOAT, "left", "The left side of the oval") @@ -51,12 +54,12 @@ public class DrawOval extends DrawBase4 { } @Override - protected void write(WireBuffer buffer, float v1, float v2, float v3, float v4) { + protected void write(@NonNull WireBuffer buffer, float v1, float v2, float v3, float v4) { apply(buffer, v1, v2, v3, v4); } @Override - public void write(WireBuffer buffer) { + public void write(@NonNull WireBuffer buffer) { apply(buffer, mX1, mY1, mX2, mY2); } @@ -66,7 +69,7 @@ public class DrawOval extends DrawBase4 { } @Override - public void paint(PaintContext context) { + public void paint(@NonNull PaintContext context) { context.drawOval(mX1, mY1, mX2, mY2); } @@ -79,7 +82,7 @@ public class DrawOval extends DrawBase4 { * @param x2 end x of the DrawOval * @param y2 end y of the DrawOval */ - public static void apply(WireBuffer buffer, float x1, float y1, float x2, float y2) { + public static void apply(@NonNull WireBuffer buffer, float x1, float y1, float x2, float y2) { write(buffer, OP_CODE, x1, y1, x2, y2); } } diff --git a/core/java/com/android/internal/widget/remotecompose/core/operations/DrawPath.java b/core/java/com/android/internal/widget/remotecompose/core/operations/DrawPath.java index ccbf3d9e30914367fa433368272f872adac3c433..d35094b0b3511a5a8f90c019c946d48abf6f6071 100644 --- a/core/java/com/android/internal/widget/remotecompose/core/operations/DrawPath.java +++ b/core/java/com/android/internal/widget/remotecompose/core/operations/DrawPath.java @@ -15,6 +15,8 @@ */ package com.android.internal.widget.remotecompose.core.operations; +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; @@ -38,21 +40,23 @@ public class DrawPath extends PaintOperation { } @Override - public void write(WireBuffer buffer) { + public void write(@NonNull WireBuffer buffer) { apply(buffer, mId); } + @NonNull @Override public String toString() { return "DrawPath " + "[" + mId + "]" + ", " + mStart + ", " + mEnd; } - public static void read(WireBuffer buffer, List operations) { + public static void read(@NonNull WireBuffer buffer, @NonNull List operations) { int id = buffer.readInt(); DrawPath op = new DrawPath(id); operations.add(op); } + @NonNull public static String name() { return CLASS_NAME; } @@ -61,19 +65,19 @@ public class DrawPath extends PaintOperation { return Operations.DRAW_PATH; } - public static void apply(WireBuffer buffer, int id) { + public static void apply(@NonNull WireBuffer buffer, int id) { buffer.start(Operations.DRAW_PATH); buffer.writeInt(id); } - public static void documentation(DocumentationBuilder doc) { + public static void documentation(@NonNull DocumentationBuilder doc) { doc.operation("Draw Operations", OP_CODE, CLASS_NAME) .description("Draw a bitmap using integer coordinates") .field(DocumentedOperation.INT, "id", "id of path"); } @Override - public void paint(PaintContext context) { + public void paint(@NonNull PaintContext context) { context.drawPath(mId, mStart, mEnd); } } diff --git a/core/java/com/android/internal/widget/remotecompose/core/operations/DrawRect.java b/core/java/com/android/internal/widget/remotecompose/core/operations/DrawRect.java index 644011b8a21449c6ac9f6052dde7d2804cee60b0..db7633cbe3355f6f974e2211106932bf94b55958 100644 --- a/core/java/com/android/internal/widget/remotecompose/core/operations/DrawRect.java +++ b/core/java/com/android/internal/widget/remotecompose/core/operations/DrawRect.java @@ -15,6 +15,8 @@ */ package com.android.internal.widget.remotecompose.core.operations; +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; @@ -29,7 +31,7 @@ public class DrawRect extends DrawBase4 { private static final int OP_CODE = Operations.DRAW_RECT; private static final String CLASS_NAME = "DrawRect"; - public static void read(WireBuffer buffer, List operations) { + public static void read(@NonNull WireBuffer buffer, @NonNull List operations) { Maker m = DrawRect::new; read(m, buffer, operations); } @@ -38,11 +40,12 @@ public class DrawRect extends DrawBase4 { return OP_CODE; } + @NonNull public static String name() { return CLASS_NAME; } - public static void documentation(DocumentationBuilder doc) { + public static void documentation(@NonNull DocumentationBuilder doc) { doc.operation("Canvas Operations", OP_CODE, CLASS_NAME) .description("Draw the specified rectangle") .field(DocumentedOperation.FLOAT, "left", "The left side of the rectangle") @@ -52,7 +55,7 @@ public class DrawRect extends DrawBase4 { } @Override - protected void write(WireBuffer buffer, float v1, float v2, float v3, float v4) { + protected void write(@NonNull WireBuffer buffer, float v1, float v2, float v3, float v4) { apply(buffer, v1, v2, v3, v4); } @@ -62,7 +65,7 @@ public class DrawRect extends DrawBase4 { } @Override - public void paint(PaintContext context) { + public void paint(@NonNull PaintContext context) { context.drawRect(mX1, mY1, mX2, mY2); } @@ -75,7 +78,7 @@ public class DrawRect extends DrawBase4 { * @param x2 right x of the rect * @param y2 bottom y of the rect */ - public static void apply(WireBuffer buffer, float x1, float y1, float x2, float y2) { + public static void apply(@NonNull WireBuffer buffer, float x1, float y1, float x2, float y2) { write(buffer, OP_CODE, x1, y1, x2, y2); } } diff --git a/core/java/com/android/internal/widget/remotecompose/core/operations/DrawRoundRect.java b/core/java/com/android/internal/widget/remotecompose/core/operations/DrawRoundRect.java index 64a3b283505b8739a5275ca620f58fa70d66a38c..c306e2b5f0411c53ada979b6a70800639d0554e8 100644 --- a/core/java/com/android/internal/widget/remotecompose/core/operations/DrawRoundRect.java +++ b/core/java/com/android/internal/widget/remotecompose/core/operations/DrawRoundRect.java @@ -15,6 +15,8 @@ */ package com.android.internal.widget.remotecompose.core.operations; +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; @@ -29,7 +31,7 @@ public class DrawRoundRect extends DrawBase6 { private static final int OP_CODE = Operations.DRAW_ROUND_RECT; private static final String CLASS_NAME = "DrawRoundRect"; - public static void read(WireBuffer buffer, List operations) { + public static void read(@NonNull WireBuffer buffer, @NonNull List operations) { Maker m = DrawRoundRect::new; read(m, buffer, operations); } @@ -50,7 +52,13 @@ public class DrawRoundRect extends DrawBase6 { * @param v6 The y-radius of the oval used to round the corners */ public static void apply( - 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) { buffer.start(OP_CODE); buffer.writeFloat(v1); buffer.writeFloat(v2); @@ -62,11 +70,17 @@ public class DrawRoundRect extends DrawBase6 { @Override protected 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) { apply(buffer, v1, v2, v3, v4, v5, v6); } - public static void documentation(DocumentationBuilder doc) { + public static void documentation(@NonNull DocumentationBuilder doc) { doc.operation("Canvas Operations", OP_CODE, CLASS_NAME) .description("Draw the specified round-rect") .field(DocumentedOperation.FLOAT, "left", "The left side of the rect") @@ -89,7 +103,7 @@ public class DrawRoundRect extends DrawBase6 { } @Override - public void paint(PaintContext context) { + public void paint(@NonNull PaintContext context) { context.drawRoundRect(mV1, mV2, mV3, mV4, mV5, mV6); } } diff --git a/core/java/com/android/internal/widget/remotecompose/core/operations/DrawSector.java b/core/java/com/android/internal/widget/remotecompose/core/operations/DrawSector.java index 3cb191647c33f7b9b324c57df026326c8c85cb01..3b60df7d529e2cd12e6d302f37a97c2bf4dcdc67 100644 --- a/core/java/com/android/internal/widget/remotecompose/core/operations/DrawSector.java +++ b/core/java/com/android/internal/widget/remotecompose/core/operations/DrawSector.java @@ -15,6 +15,8 @@ */ package com.android.internal.widget.remotecompose.core.operations; +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; @@ -28,7 +30,7 @@ public class DrawSector extends DrawBase6 { public static final int OP_CODE = Operations.DRAW_SECTOR; private static final String CLASS_NAME = "DrawSector"; - public static void read(WireBuffer buffer, List operations) { + public static void read(@NonNull WireBuffer buffer, @NonNull List operations) { Maker m = DrawSector::new; read(m, buffer, operations); } @@ -49,7 +51,13 @@ public class DrawSector extends DrawBase6 { * @param v6 Sweep angle (in degrees) measured clockwise */ public static void apply( - 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) { buffer.start(OP_CODE); buffer.writeFloat(v1); buffer.writeFloat(v2); @@ -61,11 +69,17 @@ public class DrawSector extends DrawBase6 { @Override protected 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) { apply(buffer, v1, v2, v3, v4, v5, v6); } - public static void documentation(DocumentationBuilder doc) { + public static void documentation(@NonNull DocumentationBuilder doc) { doc.operation("Canvas Operations", OP_CODE, CLASS_NAME) .description( "Draw the specified sector (pie shape)" @@ -90,7 +104,7 @@ public class DrawSector extends DrawBase6 { } @Override - public void paint(PaintContext context) { + public void paint(@NonNull PaintContext context) { context.drawSector(mV1, mV2, mV3, mV4, mV5, mV6); } } diff --git a/core/java/com/android/internal/widget/remotecompose/core/operations/DrawText.java b/core/java/com/android/internal/widget/remotecompose/core/operations/DrawText.java index bcb7852e661524789a5d3f19557336732053799a..9c587aba3f7bcc6ac9761556a398b0c8239fb65d 100644 --- a/core/java/com/android/internal/widget/remotecompose/core/operations/DrawText.java +++ b/core/java/com/android/internal/widget/remotecompose/core/operations/DrawText.java @@ -17,6 +17,8 @@ package com.android.internal.widget.remotecompose.core.operations; import static com.android.internal.widget.remotecompose.core.operations.Utils.floatToString; +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; @@ -64,13 +66,13 @@ public class DrawText extends PaintOperation implements VariableSupport { } @Override - public void updateVariables(RemoteContext context) { + public void updateVariables(@NonNull RemoteContext context) { mOutX = Float.isNaN(mX) ? context.getFloat(Utils.idFromNan(mX)) : mX; mOutY = Float.isNaN(mY) ? context.getFloat(Utils.idFromNan(mY)) : mY; } @Override - public void registerListening(RemoteContext context) { + public void registerListening(@NonNull RemoteContext context) { if (Float.isNaN(mX)) { context.listensTo(Utils.idFromNan(mX), this); } @@ -80,10 +82,11 @@ public class DrawText extends PaintOperation implements VariableSupport { } @Override - public void write(WireBuffer buffer) { + public void write(@NonNull WireBuffer buffer) { apply(buffer, mTextID, mStart, mEnd, mContextStart, mContextEnd, mX, mY, mRtl); } + @NonNull @Override public String toString() { return "DrawTextRun [" @@ -98,7 +101,7 @@ public class DrawText extends PaintOperation implements VariableSupport { + floatToString(mY, mOutY); } - public static void read(WireBuffer buffer, List operations) { + public static void read(@NonNull WireBuffer buffer, @NonNull List operations) { int text = buffer.readInt(); int start = buffer.readInt(); int end = buffer.readInt(); @@ -112,6 +115,7 @@ public class DrawText extends PaintOperation implements VariableSupport { operations.add(op); } + @NonNull public static String name() { return CLASS_NAME; } @@ -134,7 +138,7 @@ public class DrawText extends PaintOperation implements VariableSupport { * @param rtl is it Right to Left text */ public static void apply( - WireBuffer buffer, + @NonNull WireBuffer buffer, int textID, int start, int end, @@ -154,7 +158,7 @@ public class DrawText extends PaintOperation implements VariableSupport { buffer.writeBoolean(rtl); } - public static void documentation(DocumentationBuilder doc) { + public static void documentation(@NonNull DocumentationBuilder doc) { doc.operation("Draw Operations", id(), CLASS_NAME) .description("Draw a run of text, all in a single direction") .field(DocumentedOperation.INT, "textId", "id of bitmap") @@ -177,7 +181,7 @@ public class DrawText extends PaintOperation implements VariableSupport { } @Override - public void paint(PaintContext context) { + public void paint(@NonNull PaintContext context) { context.drawTextRun(mTextID, mStart, mEnd, mContextStart, mContextEnd, mOutX, mOutY, mRtl); } } diff --git a/core/java/com/android/internal/widget/remotecompose/core/operations/DrawTextAnchored.java b/core/java/com/android/internal/widget/remotecompose/core/operations/DrawTextAnchored.java index 95a87667dfabf57c31471831d2fe6ad08b0c90f4..8b7018191f4de0cf000b31fe6df736f792bdf986 100644 --- a/core/java/com/android/internal/widget/remotecompose/core/operations/DrawTextAnchored.java +++ b/core/java/com/android/internal/widget/remotecompose/core/operations/DrawTextAnchored.java @@ -15,6 +15,8 @@ */ package com.android.internal.widget.remotecompose.core.operations; +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,7 +59,7 @@ public class DrawTextAnchored extends PaintOperation implements VariableSupport } @Override - public void updateVariables(RemoteContext context) { + public void updateVariables(@NonNull RemoteContext context) { mOutX = Float.isNaN(mX) ? context.getFloat(Utils.idFromNan(mX)) : mX; mOutY = Float.isNaN(mY) ? context.getFloat(Utils.idFromNan(mY)) : mY; mOutPanX = Float.isNaN(mPanX) ? context.getFloat(Utils.idFromNan(mPanX)) : mPanX; @@ -65,7 +67,7 @@ public class DrawTextAnchored extends PaintOperation implements VariableSupport } @Override - public void registerListening(RemoteContext context) { + public void registerListening(@NonNull RemoteContext context) { if (Float.isNaN(mX)) { context.listensTo(Utils.idFromNan(mX), this); } @@ -81,10 +83,11 @@ public class DrawTextAnchored extends PaintOperation implements VariableSupport } @Override - public void write(WireBuffer buffer) { + public void write(@NonNull WireBuffer buffer) { apply(buffer, mTextID, mX, mY, mPanX, mPanY, mFlags); } + @NonNull @Override public String toString() { return "DrawTextAnchored [" @@ -108,7 +111,7 @@ public class DrawTextAnchored extends PaintOperation implements VariableSupport return Float.toString(v); } - public static void read(WireBuffer buffer, List operations) { + public static void read(@NonNull WireBuffer buffer, @NonNull List operations) { int textID = buffer.readInt(); float x = buffer.readFloat(); float y = buffer.readFloat(); @@ -121,6 +124,7 @@ public class DrawTextAnchored extends PaintOperation implements VariableSupport operations.add(op); } + @NonNull public static String name() { return CLASS_NAME; } @@ -141,7 +145,13 @@ public class DrawTextAnchored extends PaintOperation implements VariableSupport * @param flags Change the behaviour */ public static void apply( - WireBuffer buffer, int textID, float x, float y, float panX, float panY, int flags) { + @NonNull WireBuffer buffer, + int textID, + float x, + float y, + float panX, + float panY, + int flags) { buffer.start(OP_CODE); buffer.writeInt(textID); buffer.writeFloat(x); @@ -151,7 +161,7 @@ public class DrawTextAnchored extends PaintOperation implements VariableSupport buffer.writeInt(flags); } - public static void documentation(DocumentationBuilder doc) { + public static void documentation(@NonNull DocumentationBuilder doc) { doc.operation("Draw Operations", OP_CODE, CLASS_NAME) .description("Draw text centered about an anchor point") .field(DocumentedOperation.INT, "textId", "id of bitmap") @@ -168,7 +178,7 @@ public class DrawTextAnchored extends PaintOperation implements VariableSupport .field(DocumentedOperation.INT, "flags", "Change the behaviour"); } - float[] mBounds = new float[4]; + @NonNull float[] mBounds = new float[4]; private float getHorizontalOffset() { // TODO scale TextSize / BaseTextSize; @@ -188,7 +198,7 @@ public class DrawTextAnchored extends PaintOperation implements VariableSupport } @Override - public void paint(PaintContext context) { + public void paint(@NonNull PaintContext context) { int flags = ((mFlags & ANCHOR_MONOSPACE_MEASURE) != 0) ? PaintContext.TEXT_MEASURE_MONOSPACE_WIDTH diff --git a/core/java/com/android/internal/widget/remotecompose/core/operations/DrawTextOnPath.java b/core/java/com/android/internal/widget/remotecompose/core/operations/DrawTextOnPath.java index aefd6f397ebf920f508b84c9d39ce510941840b5..e90122bb95accf781f28aa272511cdb5c5bc14f6 100644 --- a/core/java/com/android/internal/widget/remotecompose/core/operations/DrawTextOnPath.java +++ b/core/java/com/android/internal/widget/remotecompose/core/operations/DrawTextOnPath.java @@ -15,6 +15,8 @@ */ package com.android.internal.widget.remotecompose.core.operations; +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; @@ -46,7 +48,7 @@ public class DrawTextOnPath extends PaintOperation implements VariableSupport { } @Override - public void updateVariables(RemoteContext context) { + public void updateVariables(@NonNull RemoteContext context) { mOutHOffset = Float.isNaN(mHOffset) ? context.getFloat(Utils.idFromNan(mHOffset)) : mHOffset; mOutVOffset = @@ -54,7 +56,7 @@ public class DrawTextOnPath extends PaintOperation implements VariableSupport { } @Override - public void registerListening(RemoteContext context) { + public void registerListening(@NonNull RemoteContext context) { if (Float.isNaN(mHOffset)) { context.listensTo(Utils.idFromNan(mHOffset), this); } @@ -64,10 +66,11 @@ public class DrawTextOnPath extends PaintOperation implements VariableSupport { } @Override - public void write(WireBuffer buffer) { + public void write(@NonNull WireBuffer buffer) { apply(buffer, mTextId, mPathId, mHOffset, mVOffset); } + @NonNull @Override public String toString() { return "DrawTextOnPath [" @@ -80,7 +83,7 @@ public class DrawTextOnPath extends PaintOperation implements VariableSupport { + Utils.floatToString(mVOffset, mOutVOffset); } - public static void read(WireBuffer buffer, List operations) { + public static void read(@NonNull WireBuffer buffer, @NonNull List operations) { int textId = buffer.readInt(); int pathId = buffer.readInt(); float vOffset = buffer.readFloat(); @@ -89,6 +92,7 @@ public class DrawTextOnPath extends PaintOperation implements VariableSupport { operations.add(op); } + @NonNull public static String name() { return "DrawTextOnPath"; } @@ -98,7 +102,7 @@ public class DrawTextOnPath extends PaintOperation implements VariableSupport { } public static void apply( - WireBuffer buffer, int textId, int pathId, float hOffset, float vOffset) { + @NonNull WireBuffer buffer, int textId, int pathId, float hOffset, float vOffset) { buffer.start(OP_CODE); buffer.writeInt(textId); buffer.writeInt(pathId); @@ -106,7 +110,7 @@ public class DrawTextOnPath extends PaintOperation implements VariableSupport { buffer.writeFloat(hOffset); } - public static void documentation(DocumentationBuilder doc) { + public static void documentation(@NonNull DocumentationBuilder doc) { doc.operation("Draw Operations", OP_CODE, CLASS_NAME) .description("Draw text along path object") .field(DocumentedOperation.INT, "textId", "id of the text") @@ -116,7 +120,7 @@ public class DrawTextOnPath extends PaintOperation implements VariableSupport { } @Override - public void paint(PaintContext context) { + public void paint(@NonNull PaintContext context) { context.drawTextOnPath(mTextId, mPathId, mOutHOffset, mOutVOffset); } } diff --git a/core/java/com/android/internal/widget/remotecompose/core/operations/DrawTweenPath.java b/core/java/com/android/internal/widget/remotecompose/core/operations/DrawTweenPath.java index b6d45d95f2c036c2dfb76c0082965dc9d3a523eb..0aaaf42ba838b7b5ba52879ceb4b234d02cd29af 100644 --- a/core/java/com/android/internal/widget/remotecompose/core/operations/DrawTweenPath.java +++ b/core/java/com/android/internal/widget/remotecompose/core/operations/DrawTweenPath.java @@ -17,6 +17,8 @@ package com.android.internal.widget.remotecompose.core.operations; import static com.android.internal.widget.remotecompose.core.operations.Utils.floatToString; +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; @@ -50,14 +52,14 @@ public class DrawTweenPath extends PaintOperation implements VariableSupport { } @Override - public void updateVariables(RemoteContext context) { + public void updateVariables(@NonNull RemoteContext context) { mOutTween = Float.isNaN(mTween) ? context.getFloat(Utils.idFromNan(mTween)) : mTween; mOutStart = Float.isNaN(mStart) ? context.getFloat(Utils.idFromNan(mStart)) : mStart; mOutStop = Float.isNaN(mStop) ? context.getFloat(Utils.idFromNan(mStop)) : mStop; } @Override - public void registerListening(RemoteContext context) { + public void registerListening(@NonNull RemoteContext context) { if (Float.isNaN(mTween)) { context.listensTo(Utils.idFromNan(mTween), this); } @@ -70,10 +72,11 @@ public class DrawTweenPath extends PaintOperation implements VariableSupport { } @Override - public void write(WireBuffer buffer) { + public void write(@NonNull WireBuffer buffer) { apply(buffer, mPath1Id, mPath2Id, mTween, mStart, mStop); } + @NonNull @Override public String toString() { return "DrawTweenPath " @@ -89,7 +92,7 @@ public class DrawTweenPath extends PaintOperation implements VariableSupport { + floatToString(mStop, mOutStop); } - public static void read(WireBuffer buffer, List operations) { + public static void read(@NonNull WireBuffer buffer, @NonNull List operations) { int path1Id = buffer.readInt(); int path2Id = buffer.readInt(); float tween = buffer.readFloat(); @@ -99,6 +102,7 @@ public class DrawTweenPath extends PaintOperation implements VariableSupport { operations.add(op); } + @NonNull public static String name() { return "DrawTweenPath"; } @@ -108,7 +112,12 @@ public class DrawTweenPath extends PaintOperation implements VariableSupport { } public static void apply( - WireBuffer buffer, int path1Id, int path2Id, float tween, float start, float stop) { + @NonNull WireBuffer buffer, + int path1Id, + int path2Id, + float tween, + float start, + float stop) { buffer.start(OP_CODE); buffer.writeInt(path1Id); buffer.writeInt(path2Id); @@ -117,7 +126,7 @@ public class DrawTweenPath extends PaintOperation implements VariableSupport { buffer.writeFloat(stop); } - public static void documentation(DocumentationBuilder doc) { + public static void documentation(@NonNull DocumentationBuilder doc) { doc.operation("Draw Operations", OP_CODE, CLASS_NAME) .description("Draw text along path object") .field(DocumentedOperation.INT, "pathId1", "id of path 1") @@ -128,7 +137,7 @@ public class DrawTweenPath extends PaintOperation implements VariableSupport { } @Override - public void paint(PaintContext context) { + public void paint(@NonNull PaintContext context) { context.drawTweenPath(mPath1Id, mPath2Id, mOutTween, mOutStart, mOutStop); } } 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 765e150e81afcb567d9ee759d47985a564f1d51c..89390acb8c507fdbf505e01b4442633dac9545b0 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 @@ -17,6 +17,8 @@ package com.android.internal.widget.remotecompose.core.operations; 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.RemoteContext; @@ -39,15 +41,17 @@ public class FloatConstant implements com.android.internal.widget.remotecompose. } @Override - public void write(WireBuffer buffer) { + public void write(@NonNull WireBuffer buffer) { apply(buffer, mTextId, mValue); } + @NonNull @Override public String toString() { return "FloatConstant[" + mTextId + "] = " + mValue; } + @NonNull public static String name() { return CLASS_NAME; } @@ -63,20 +67,20 @@ public class FloatConstant implements com.android.internal.widget.remotecompose. * @param id the id * @param value the value of the float */ - public static void apply(WireBuffer buffer, int id, float value) { + public static void apply(@NonNull WireBuffer buffer, int id, float value) { buffer.start(OP_CODE); buffer.writeInt(id); buffer.writeFloat(value); } - public static void read(WireBuffer buffer, List operations) { + public static void read(@NonNull WireBuffer buffer, @NonNull List operations) { int textId = buffer.readInt(); float value = buffer.readFloat(); operations.add(new FloatConstant(textId, value)); } - 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(DocumentedOperation.INT, "id", "id of float") @@ -84,10 +88,11 @@ public class FloatConstant implements com.android.internal.widget.remotecompose. } @Override - public void apply(RemoteContext context) { + public void apply(@NonNull RemoteContext context) { context.loadFloat(mTextId, mValue); } + @NonNull @Override public String deepToString(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 d71793364a33532358e7bff3949c020d440ef208..e1c6c257786060de998ac37588d91298aa966d45 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 @@ -20,6 +20,9 @@ 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 android.annotation.Nullable; + import com.android.internal.widget.remotecompose.core.Operation; import com.android.internal.widget.remotecompose.core.Operations; import com.android.internal.widget.remotecompose.core.RemoteContext; @@ -48,7 +51,7 @@ public class FloatExpression implements Operation, VariableSupport { public float[] mPreCalcValue; private float mLastChange = Float.NaN; private float mLastCalculatedValue = Float.NaN; - AnimatedFloatExpression mExp = new AnimatedFloatExpression(); + @NonNull AnimatedFloatExpression mExp = new AnimatedFloatExpression(); public static final int MAX_EXPRESSION_SIZE = 32; public FloatExpression(int id, float[] value, float[] animation) { @@ -61,7 +64,7 @@ public class FloatExpression implements Operation, VariableSupport { } @Override - public void updateVariables(RemoteContext context) { + public void updateVariables(@NonNull RemoteContext context) { if (mPreCalcValue == null || mPreCalcValue.length != mSrcValue.length) { mPreCalcValue = new float[mSrcValue.length]; } @@ -107,7 +110,7 @@ public class FloatExpression implements Operation, VariableSupport { } @Override - public void registerListening(RemoteContext context) { + public void registerListening(@NonNull RemoteContext context) { for (float v : mSrcValue) { if (Float.isNaN(v) && !AnimatedFloatExpression.isMathOperator(v) @@ -118,7 +121,7 @@ public class FloatExpression implements Operation, VariableSupport { } @Override - public void apply(RemoteContext context) { + public void apply(@NonNull RemoteContext context) { updateVariables(context); float t = context.getAnimationTime(); if (Float.isNaN(mLastChange)) { @@ -135,10 +138,11 @@ public class FloatExpression implements Operation, VariableSupport { } @Override - public void write(WireBuffer buffer) { + public void write(@NonNull WireBuffer buffer) { apply(buffer, mId, mSrcValue, mSrcAnimation); } + @NonNull @Override public String toString() { String[] labels = new String[mSrcValue.length]; @@ -161,6 +165,7 @@ public class FloatExpression implements Operation, VariableSupport { + ")"; } + @NonNull public static String name() { return CLASS_NAME; } @@ -177,7 +182,11 @@ public class FloatExpression implements Operation, VariableSupport { * @param value the float expression array * @param animation the animation expression array */ - public static void apply(WireBuffer buffer, int id, float[] value, float[] animation) { + public static void apply( + @NonNull WireBuffer buffer, + int id, + @NonNull float[] value, + @Nullable float[] animation) { buffer.start(OP_CODE); buffer.writeInt(id); @@ -197,7 +206,7 @@ public class FloatExpression implements Operation, VariableSupport { } } - public static void read(WireBuffer buffer, List operations) { + public static void read(@NonNull WireBuffer buffer, @NonNull List operations) { int id = buffer.readInt(); int len = buffer.readInt(); int valueLen = len & 0xFFFF; @@ -222,7 +231,7 @@ public class FloatExpression implements Operation, VariableSupport { operations.add(new FloatExpression(id, values, animation)); } - public static void documentation(DocumentationBuilder doc) { + public static void documentation(@NonNull DocumentationBuilder doc) { doc.operation("Expressions Operations", OP_CODE, CLASS_NAME) .description("A Float expression") .field(DocumentedOperation.INT, "id", "The id of the Color") @@ -245,6 +254,7 @@ public class FloatExpression implements Operation, VariableSupport { .field(FLOAT, "wrapValue", "> [Wrap value] "); } + @NonNull @Override public String deepToString(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 4f8516f5235d88bf5421c26345033ee5c33cab71..1979bc5f4331eb086fdcc041a4acadf95b4d2f48 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 @@ -18,6 +18,8 @@ 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.LONG; +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.RemoteComposeOperation; @@ -80,10 +82,11 @@ public class Header implements RemoteComposeOperation { } @Override - public void write(WireBuffer buffer) { + public void write(@NonNull WireBuffer buffer) { apply(buffer, mWidth, mHeight, mDensity, mCapabilities); } + @NonNull @Override public String toString() { return "HEADER v" @@ -102,15 +105,17 @@ public class Header implements RemoteComposeOperation { } @Override - public void apply(RemoteContext context) { + public void apply(@NonNull RemoteContext context) { context.header(mMajorVersion, mMinorVersion, mPatchVersion, mWidth, mHeight, mCapabilities); } + @NonNull @Override public String deepToString(String indent) { return toString(); } + @NonNull public static String name() { return CLASS_NAME; } @@ -120,7 +125,7 @@ public class Header implements RemoteComposeOperation { } public static void apply( - WireBuffer buffer, int width, int height, float density, long capabilities) { + @NonNull WireBuffer buffer, int width, int height, float density, long capabilities) { buffer.start(OP_CODE); buffer.writeInt(MAJOR_VERSION); // major version number of the protocol buffer.writeInt(MINOR_VERSION); // minor version number of the protocol @@ -131,7 +136,7 @@ public class Header implements RemoteComposeOperation { buffer.writeLong(capabilities); } - public static void read(WireBuffer buffer, List operations) { + public static void read(@NonNull WireBuffer buffer, @NonNull List operations) { int majorVersion = buffer.readInt(); int minorVersion = buffer.readInt(); int patchVersion = buffer.readInt(); @@ -152,7 +157,7 @@ public class Header implements RemoteComposeOperation { operations.add(header); } - public static void documentation(DocumentationBuilder doc) { + public static void documentation(@NonNull DocumentationBuilder doc) { doc.operation("Protocol Operations", OP_CODE, CLASS_NAME) .description( "Document metadata, containing the version," 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 c9a850875011c0f184d20b9e36e2bd55772ebfc1..6375f001c81823b868f5fd2259f56b9477ad0fea 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 @@ -18,6 +18,8 @@ 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 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; @@ -45,7 +47,7 @@ public class IntegerExpression implements Operation, VariableSupport { public int[] mPreCalcValue; private float mLastChange = Float.NaN; public static final int MAX_SIZE = 320; - IntegerExpressionEvaluator mExp = new IntegerExpressionEvaluator(); + @NonNull IntegerExpressionEvaluator mExp = new IntegerExpressionEvaluator(); public IntegerExpression(int id, int mask, int[] value) { this.mId = id; @@ -54,7 +56,7 @@ public class IntegerExpression implements Operation, VariableSupport { } @Override - public void updateVariables(RemoteContext context) { + public void updateVariables(@NonNull RemoteContext context) { if (mPreCalcValue == null || mPreCalcValue.length != mSrcValue.length) { mPreCalcValue = new int[mSrcValue.length]; } @@ -70,7 +72,7 @@ public class IntegerExpression implements Operation, VariableSupport { } @Override - public void registerListening(RemoteContext context) { + public void registerListening(@NonNull RemoteContext context) { for (int i = 0; i < mSrcValue.length; i++) { if (isId(mMask, i, mSrcValue[i])) { context.listensTo(mSrcValue[i], this); @@ -79,7 +81,7 @@ public class IntegerExpression implements Operation, VariableSupport { } @Override - public void apply(RemoteContext context) { + public void apply(@NonNull RemoteContext context) { updateVariables(context); float t = context.getAnimationTime(); if (Float.isNaN(mLastChange)) { @@ -95,7 +97,7 @@ public class IntegerExpression implements Operation, VariableSupport { * @param context current context * @return the resulting value */ - public int evaluate(RemoteContext context) { + public int evaluate(@NonNull RemoteContext context) { updateVariables(context); float t = context.getAnimationTime(); if (Float.isNaN(mLastChange)) { @@ -105,10 +107,11 @@ public class IntegerExpression implements Operation, VariableSupport { } @Override - public void write(WireBuffer buffer) { + public void write(@NonNull WireBuffer buffer) { apply(buffer, mId, mMask, mSrcValue); } + @NonNull @Override public String toString() { StringBuilder s = new StringBuilder(); @@ -132,6 +135,7 @@ public class IntegerExpression implements Operation, VariableSupport { return "IntegerExpression[" + mId + "] = (" + s + ")"; } + @NonNull public static String name() { return CLASS_NAME; } @@ -148,7 +152,7 @@ public class IntegerExpression implements Operation, VariableSupport { * @param mask the mask bits of ints & operators or variables * @param value array of integers to be evaluated */ - public static void apply(WireBuffer buffer, int id, int mask, int[] value) { + public static void apply(@NonNull WireBuffer buffer, int id, int mask, @NonNull int[] value) { buffer.start(OP_CODE); buffer.writeInt(id); buffer.writeInt(mask); @@ -158,7 +162,7 @@ public class IntegerExpression implements Operation, VariableSupport { } } - public static void read(WireBuffer buffer, List operations) { + public static void read(@NonNull WireBuffer buffer, @NonNull List operations) { int id = buffer.readInt(); int mask = buffer.readInt(); int len = buffer.readInt(); @@ -173,7 +177,7 @@ public class IntegerExpression implements Operation, VariableSupport { operations.add(new IntegerExpression(id, mask, values)); } - public static void documentation(DocumentationBuilder doc) { + public static void documentation(@NonNull DocumentationBuilder doc) { doc.operation("Data Operations", OP_CODE, CLASS_NAME) .description("Expression that computes an integer") .field(DocumentedOperation.INT, "id", "id of integer") @@ -182,6 +186,7 @@ public class IntegerExpression implements Operation, VariableSupport { .field(INT_ARRAY, "values", "length", "Array of ints"); } + @NonNull @Override public String deepToString(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 04f8a503adff236a773c94762bf5803f2dfdd290..6a620e58570ae33ef77e46ac7f2a7b2384cac41b 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 @@ -15,6 +15,8 @@ */ package com.android.internal.widget.remotecompose.core.operations; +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; @@ -31,20 +33,22 @@ public class MatrixRestore extends PaintOperation { public MatrixRestore() {} @Override - public void write(WireBuffer buffer) { + public void write(@NonNull WireBuffer buffer) { apply(buffer); } - public static void read(WireBuffer buffer, List operations) { + public static void read(WireBuffer buffer, @NonNull List operations) { MatrixRestore op = new MatrixRestore(); operations.add(op); } + @NonNull @Override public String toString() { return "MatrixRestore"; } + @NonNull public static String name() { return CLASS_NAME; } @@ -53,17 +57,17 @@ public class MatrixRestore extends PaintOperation { return OP_CODE; } - public static void apply(WireBuffer buffer) { + public static void apply(@NonNull WireBuffer buffer) { buffer.start(OP_CODE); } - public static void documentation(DocumentationBuilder doc) { + public static void documentation(@NonNull DocumentationBuilder doc) { doc.operation("Canvas Operations", OP_CODE, CLASS_NAME) .description("Restore the matrix and clip"); } @Override - public void paint(PaintContext context) { + public void paint(@NonNull PaintContext context) { context.matrixRestore(); } } diff --git a/core/java/com/android/internal/widget/remotecompose/core/operations/MatrixRotate.java b/core/java/com/android/internal/widget/remotecompose/core/operations/MatrixRotate.java index df10f329630a7784152f8e456ee5ae50245dd3af..438a2aad648a4c8db971097d85947a86f2409c24 100644 --- a/core/java/com/android/internal/widget/remotecompose/core/operations/MatrixRotate.java +++ b/core/java/com/android/internal/widget/remotecompose/core/operations/MatrixRotate.java @@ -15,6 +15,8 @@ */ package com.android.internal.widget.remotecompose.core.operations; +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; @@ -28,9 +30,10 @@ public class MatrixRotate extends DrawBase3 { public static final int OP_CODE = Operations.MATRIX_ROTATE; private static final String CLASS_NAME = "MatrixRotate"; - public static void read(WireBuffer buffer, List operations) { + public static void read(@NonNull WireBuffer buffer, @NonNull List operations) { Maker m = new Maker() { + @NonNull @Override public DrawBase3 create(float v1, float v2, float v3) { return new MatrixRotate(v1, v2, v3); @@ -43,11 +46,12 @@ public class MatrixRotate extends DrawBase3 { return OP_CODE; } + @NonNull public static String name() { return CLASS_NAME; } - public static void documentation(DocumentationBuilder doc) { + public static void documentation(@NonNull DocumentationBuilder doc) { doc.operation("Canvas Operations", OP_CODE, CLASS_NAME) .description("apply rotation to matrix") .field(DocumentedOperation.FLOAT, "rotate", "Angle to rotate") @@ -56,7 +60,7 @@ public class MatrixRotate extends DrawBase3 { } @Override - protected void write(WireBuffer buffer, float v1, float v2, float v3) { + protected void write(@NonNull WireBuffer buffer, float v1, float v2, float v3) { apply(buffer, v1, v2, v3); } @@ -66,7 +70,7 @@ public class MatrixRotate extends DrawBase3 { } @Override - public void paint(PaintContext context) { + public void paint(@NonNull PaintContext context) { context.matrixRotate(mV1, mV2, mV3); } @@ -78,7 +82,7 @@ public class MatrixRotate extends DrawBase3 { * @param y1 X Pivot point * @param x2 Y Pivot point */ - public static void apply(WireBuffer buffer, float x1, float y1, float x2) { + public static void apply(@NonNull WireBuffer buffer, float x1, float y1, float x2) { buffer.start(OP_CODE); buffer.writeFloat(x1); buffer.writeFloat(y1); 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 67612c7fd2f4444930897fa8bd9de3de6fd6f95f..1880b19be1a79ded053c4c1eae324fd1ba002b67 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 @@ -15,6 +15,8 @@ */ package com.android.internal.widget.remotecompose.core.operations; +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; @@ -29,20 +31,22 @@ public class MatrixSave extends PaintOperation { private static final String CLASS_NAME = "MatrixSave"; @Override - public void write(WireBuffer buffer) { + public void write(@NonNull WireBuffer buffer) { apply(buffer); } + @NonNull @Override public String toString() { return "MatrixSave;"; } - public static void read(WireBuffer buffer, List operations) { + public static void read(WireBuffer buffer, @NonNull List operations) { MatrixSave op = new MatrixSave(); operations.add(op); } + @NonNull public static String name() { return CLASS_NAME; } @@ -51,17 +55,17 @@ public class MatrixSave extends PaintOperation { return OP_CODE; } - public static void apply(WireBuffer buffer) { + public static void apply(@NonNull WireBuffer buffer) { buffer.start(Operations.MATRIX_SAVE); } - public static void documentation(DocumentationBuilder doc) { + public static void documentation(@NonNull DocumentationBuilder doc) { doc.operation("Canvas Operations", OP_CODE, CLASS_NAME) .description("Save the matrix and clip to a stack"); } @Override - public void paint(PaintContext context) { + public void paint(@NonNull PaintContext context) { context.matrixSave(); } } diff --git a/core/java/com/android/internal/widget/remotecompose/core/operations/MatrixScale.java b/core/java/com/android/internal/widget/remotecompose/core/operations/MatrixScale.java index 26c898acb67b6c4658727eb0d7cd5c6c4488d4c8..6304584999778536c455c1aca76d2004b3cf82ca 100644 --- a/core/java/com/android/internal/widget/remotecompose/core/operations/MatrixScale.java +++ b/core/java/com/android/internal/widget/remotecompose/core/operations/MatrixScale.java @@ -15,6 +15,8 @@ */ package com.android.internal.widget.remotecompose.core.operations; +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; @@ -28,7 +30,7 @@ public class MatrixScale extends DrawBase4 { public static final int OP_CODE = Operations.MATRIX_SCALE; public static final String CLASS_NAME = "MatrixScale"; - public static void read(WireBuffer buffer, List operations) { + public static void read(@NonNull WireBuffer buffer, @NonNull List operations) { Maker m = MatrixScale::new; read(m, buffer, operations); } @@ -37,16 +39,17 @@ public class MatrixScale extends DrawBase4 { return OP_CODE; } + @NonNull public static String name() { return CLASS_NAME; } @Override - protected void write(WireBuffer buffer, float v1, float v2, float v3, float v4) { + protected void write(@NonNull WireBuffer buffer, float v1, float v2, float v3, float v4) { apply(buffer, v1, v2, v3, v4); } - public static void documentation(DocumentationBuilder doc) { + public static void documentation(@NonNull DocumentationBuilder doc) { doc.operation("Canvas Operations", OP_CODE, CLASS_NAME) .description("Draw the specified Oval") .field(DocumentedOperation.FLOAT, "scaleX", "The amount to scale in X") @@ -61,7 +64,7 @@ public class MatrixScale extends DrawBase4 { } @Override - public void paint(PaintContext context) { + public void paint(@NonNull PaintContext context) { context.matrixScale(mX1, mY1, mX2, mY2); } @@ -74,7 +77,7 @@ public class MatrixScale extends DrawBase4 { * @param x2 end x of the DrawOval * @param y2 end y of the DrawOval */ - public static void apply(WireBuffer buffer, float x1, float y1, float x2, float y2) { + public static void apply(@NonNull WireBuffer buffer, float x1, float y1, float x2, float y2) { write(buffer, OP_CODE, x1, y1, x2, y2); } } diff --git a/core/java/com/android/internal/widget/remotecompose/core/operations/MatrixSkew.java b/core/java/com/android/internal/widget/remotecompose/core/operations/MatrixSkew.java index d64117871eaad46092f0eaeb4e19ce47caf7a9de..675cf0de47438964ab9d83f4c769e893d74bb20b 100644 --- a/core/java/com/android/internal/widget/remotecompose/core/operations/MatrixSkew.java +++ b/core/java/com/android/internal/widget/remotecompose/core/operations/MatrixSkew.java @@ -17,6 +17,8 @@ package com.android.internal.widget.remotecompose.core.operations; 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; @@ -29,7 +31,7 @@ public class MatrixSkew extends DrawBase2 { public static final int OP_CODE = Operations.MATRIX_SKEW; public static final String CLASS_NAME = "MatrixSkew"; - public static void read(WireBuffer buffer, List operations) { + public static void read(@NonNull WireBuffer buffer, @NonNull List operations) { Maker m = MatrixSkew::new; read(m, buffer, operations); } @@ -38,16 +40,17 @@ public class MatrixSkew extends DrawBase2 { return OP_CODE; } + @NonNull public static String name() { return CLASS_NAME; } @Override - protected void write(WireBuffer buffer, float v1, float v2) { + protected void write(@NonNull WireBuffer buffer, float v1, float v2) { apply(buffer, v1, v2); } - public static void documentation(DocumentationBuilder doc) { + public static void documentation(@NonNull DocumentationBuilder doc) { doc.operation("Canvas Operations", OP_CODE, CLASS_NAME) .description("Current matrix with the specified skew.") .field(FLOAT, "skewX", "The amount to skew in X") @@ -60,7 +63,7 @@ public class MatrixSkew extends DrawBase2 { } @Override - public void paint(PaintContext context) { + public void paint(@NonNull PaintContext context) { context.matrixSkew(mV1, mV2); } @@ -71,7 +74,7 @@ public class MatrixSkew extends DrawBase2 { * @param x1 start x of DrawOval * @param y1 start y of the DrawOval */ - public static void apply(WireBuffer buffer, float x1, float y1) { + public static void apply(@NonNull WireBuffer buffer, float x1, float y1) { write(buffer, OP_CODE, x1, y1); } } diff --git a/core/java/com/android/internal/widget/remotecompose/core/operations/MatrixTranslate.java b/core/java/com/android/internal/widget/remotecompose/core/operations/MatrixTranslate.java index e008292f110783b3ae66589c8f31d22f08900c95..b0a7d352dfe3904b66af8844606754add5af26d8 100644 --- a/core/java/com/android/internal/widget/remotecompose/core/operations/MatrixTranslate.java +++ b/core/java/com/android/internal/widget/remotecompose/core/operations/MatrixTranslate.java @@ -15,6 +15,8 @@ */ package com.android.internal.widget.remotecompose.core.operations; +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; @@ -28,7 +30,7 @@ public class MatrixTranslate extends DrawBase2 { public static final int OP_CODE = Operations.MATRIX_TRANSLATE; public static final String CLASS_NAME = "MatrixTranslate"; - public static void read(WireBuffer buffer, List operations) { + public static void read(@NonNull WireBuffer buffer, @NonNull List operations) { Maker m = MatrixTranslate::new; read(m, buffer, operations); } @@ -37,16 +39,17 @@ public class MatrixTranslate extends DrawBase2 { return OP_CODE; } + @NonNull public static String name() { return CLASS_NAME; } @Override - protected void write(WireBuffer buffer, float v1, float v2) { + protected void write(@NonNull WireBuffer buffer, float v1, float v2) { apply(buffer, v1, v2); } - public static void documentation(DocumentationBuilder doc) { + public static void documentation(@NonNull DocumentationBuilder doc) { doc.operation("Canvas Operations", OP_CODE, "MatrixTranslate") .description("Preconcat the current matrix with the specified translation") .field(DocumentedOperation.FLOAT, "dx", "The distance to translate in X") @@ -59,7 +62,7 @@ public class MatrixTranslate extends DrawBase2 { } @Override - public void paint(PaintContext context) { + public void paint(@NonNull PaintContext context) { context.matrixTranslate(mV1, mV2); } @@ -70,7 +73,7 @@ public class MatrixTranslate extends DrawBase2 { * @param x1 start x of DrawOval * @param y1 start y of the DrawOval */ - public static void apply(WireBuffer buffer, float x1, float y1) { + public static void apply(@NonNull WireBuffer buffer, float x1, float y1) { write(buffer, OP_CODE, x1, y1); } } 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 fa6e2712a0bb3c522a3e6b194ddab7a5c49cb5d7..6310521e40108ed1f4c20f08344d30b7238bc37f 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 @@ -18,6 +18,8 @@ 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.UTF8; +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; @@ -47,10 +49,11 @@ public class NamedVariable implements Operation { } @Override - public void write(WireBuffer buffer) { + public void write(@NonNull WireBuffer buffer) { apply(buffer, mVarId, mVarType, mVarName); } + @NonNull @Override public String toString() { return "VariableName[" @@ -61,6 +64,7 @@ public class NamedVariable implements Operation { + mVarType; } + @NonNull public static String name() { return CLASS_NAME; } @@ -77,21 +81,22 @@ public class NamedVariable implements Operation { * @param varType The type of variable * @param text String */ - public static void apply(WireBuffer buffer, int varId, int varType, String text) { + public static void apply( + @NonNull WireBuffer buffer, int varId, int varType, @NonNull String text) { buffer.start(Operations.NAMED_VARIABLE); buffer.writeInt(varId); buffer.writeInt(varType); buffer.writeUTF8(text); } - public static void read(WireBuffer buffer, List operations) { + public static void read(@NonNull WireBuffer buffer, @NonNull List operations) { int varId = buffer.readInt(); int varType = buffer.readInt(); String text = buffer.readUTF8(MAX_STRING_SIZE); operations.add(new NamedVariable(varId, varType, text)); } - public static void documentation(DocumentationBuilder doc) { + public static void documentation(@NonNull DocumentationBuilder doc) { doc.operation("Data Operations", OP_CODE, CLASS_NAME) .description("Add a string name for an ID") .field(DocumentedOperation.INT, "varId", "id to label") @@ -100,10 +105,11 @@ public class NamedVariable implements Operation { } @Override - public void apply(RemoteContext context) { + public void apply(@NonNull RemoteContext context) { context.loadVariableName(mVarName, mVarId, mVarType); } + @NonNull @Override public String deepToString(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 095a0106b3d7d1a17ed39f1e14235adbb9de7400..527d5610788c4927562e3601fccb3d8ad284fb95 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 @@ -18,6 +18,8 @@ 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 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; @@ -33,31 +35,33 @@ import java.util.List; public class PaintData extends PaintOperation implements VariableSupport { private static final int OP_CODE = Operations.PAINT_VALUES; private static final String CLASS_NAME = "PaintData"; - public PaintBundle mPaintData = new PaintBundle(); + @NonNull public PaintBundle mPaintData = new PaintBundle(); public static final int MAX_STRING_SIZE = 4000; public PaintData() {} @Override - public void updateVariables(RemoteContext context) { + public void updateVariables(@NonNull RemoteContext context) { mPaintData.updateVariables(context); } @Override - public void registerListening(RemoteContext context) { + public void registerListening(@NonNull RemoteContext context) { mPaintData.registerVars(context, this); } @Override - public void write(WireBuffer buffer) { + public void write(@NonNull WireBuffer buffer) { apply(buffer, mPaintData); } + @NonNull @Override public String toString() { return "PaintData " + "\"" + mPaintData + "\""; } + @NonNull public static String name() { return CLASS_NAME; } @@ -66,31 +70,32 @@ public class PaintData extends PaintOperation implements VariableSupport { return OP_CODE; } - public static void apply(WireBuffer buffer, PaintBundle paintBundle) { + public static void apply(@NonNull WireBuffer buffer, @NonNull PaintBundle paintBundle) { buffer.start(Operations.PAINT_VALUES); paintBundle.writeBundle(buffer); } - public static void read(WireBuffer buffer, List operations) { + public static void read(@NonNull WireBuffer buffer, @NonNull List operations) { PaintData data = new PaintData(); data.mPaintData.readBundle(buffer); operations.add(data); } - public static void documentation(DocumentationBuilder doc) { + public static void documentation(@NonNull DocumentationBuilder doc) { doc.operation("Data Operations", OP_CODE, CLASS_NAME) .description("Encode a Paint ") .field(INT, "length", "id string") .field(INT_ARRAY, "paint", "length", "path encoded as floats"); } + @NonNull @Override public String deepToString(String indent) { return indent + toString(); } @Override - public void paint(PaintContext context) { + public void paint(@NonNull PaintContext context) { context.applyPaint(mPaintData); } } 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 13d5a49a584b17e26a594012cd9c3d2bde250d4f..06a1fec361964634868e38146454474161afeecd 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 @@ -18,6 +18,9 @@ package com.android.internal.widget.remotecompose.core.operations; import static com.android.internal.widget.remotecompose.core.documentation.DocumentedOperation.FLOAT_ARRAY; 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; import com.android.internal.widget.remotecompose.core.RemoteContext; @@ -43,7 +46,7 @@ public class PathData implements Operation, VariableSupport { } @Override - public void updateVariables(RemoteContext context) { + public void updateVariables(@NonNull RemoteContext context) { for (int i = 0; i < mFloatPath.length; i++) { float v = mFloatPath[i]; if (Utils.isVariable(v)) { @@ -55,7 +58,7 @@ public class PathData implements Operation, VariableSupport { } @Override - public void registerListening(RemoteContext context) { + public void registerListening(@NonNull RemoteContext context) { for (float v : mFloatPath) { if (Float.isNaN(v)) { context.listensTo(Utils.idFromNan(v), this); @@ -64,15 +67,17 @@ public class PathData implements Operation, VariableSupport { } @Override - public void write(WireBuffer buffer) { + public void write(@NonNull WireBuffer buffer) { apply(buffer, mInstanceId, mOutputPath); } + @NonNull @Override public String deepToString(String indent) { return pathString(mFloatPath); } + @NonNull @Override public String toString() { return "PathData[" + mInstanceId + "] = " + "\"" + deepToString(" ") + "\""; @@ -102,6 +107,7 @@ public class PathData implements Operation, VariableSupport { public static final float CLOSE_NAN = Utils.asNan(CLOSE); public static final float DONE_NAN = Utils.asNan(DONE); + @NonNull public static String name() { return CLASS_NAME; } @@ -110,7 +116,7 @@ public class PathData implements Operation, VariableSupport { return OP_CODE; } - public static void apply(WireBuffer buffer, int id, float[] data) { + public static void apply(@NonNull WireBuffer buffer, int id, @NonNull float[] data) { buffer.start(Operations.DATA_PATH); buffer.writeInt(id); buffer.writeInt(data.length); @@ -119,7 +125,7 @@ public class PathData implements Operation, VariableSupport { } } - public static void read(WireBuffer buffer, List operations) { + public static void read(@NonNull WireBuffer buffer, @NonNull List operations) { int imageId = buffer.readInt(); int len = buffer.readInt(); float[] data = new float[len]; @@ -129,7 +135,7 @@ public class PathData implements Operation, VariableSupport { operations.add(new PathData(imageId, data)); } - public static void documentation(DocumentationBuilder doc) { + public static void documentation(@NonNull DocumentationBuilder doc) { doc.operation("Data Operations", OP_CODE, CLASS_NAME) .description("Encode a Path ") .field(DocumentedOperation.INT, "id", "id string") @@ -137,7 +143,8 @@ public class PathData implements Operation, VariableSupport { .field(FLOAT_ARRAY, "pathData", "length", "path encoded as floats"); } - public static String pathString(float[] path) { + @NonNull + public static String pathString(@Nullable float[] path) { if (path == null) { return "null"; } @@ -186,7 +193,7 @@ public class PathData implements Operation, VariableSupport { } @Override - public void apply(RemoteContext context) { + public void apply(@NonNull RemoteContext context) { context.loadPathData(mInstanceId, mOutputPath); } } 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 4a8f5324b74e3e1abcfca89846728178cbd8cea5..6ff9ad73e35f27e9694e814e10b8ac3f37b0468a 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 @@ -15,6 +15,8 @@ */ package com.android.internal.widget.remotecompose.core.operations; +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.RemoteComposeOperation; @@ -172,10 +174,11 @@ public class RootContentBehavior implements RemoteComposeOperation { } @Override - public void write(WireBuffer buffer) { + public void write(@NonNull WireBuffer buffer) { apply(buffer, mScroll, mAlignment, mSizing, mMode); } + @NonNull @Override public String toString() { return "ROOT_CONTENT_BEHAVIOR scroll: " @@ -187,15 +190,17 @@ public class RootContentBehavior implements RemoteComposeOperation { } @Override - public void apply(RemoteContext context) { + public void apply(@NonNull RemoteContext context) { context.setRootContentBehavior(mScroll, mAlignment, mSizing, mMode); } + @NonNull @Override public String deepToString(String indent) { return toString(); } + @NonNull public static String name() { return CLASS_NAME; } @@ -204,7 +209,8 @@ public class RootContentBehavior implements RemoteComposeOperation { return OP_CODE; } - public static void apply(WireBuffer buffer, int scroll, int alignment, int sizing, int mode) { + public static void apply( + @NonNull WireBuffer buffer, int scroll, int alignment, int sizing, int mode) { buffer.start(OP_CODE); buffer.writeInt(scroll); buffer.writeInt(alignment); @@ -212,7 +218,7 @@ public class RootContentBehavior implements RemoteComposeOperation { buffer.writeInt(mode); } - public static void read(WireBuffer buffer, List operations) { + public static void read(@NonNull WireBuffer buffer, @NonNull List operations) { int scroll = buffer.readInt(); int alignment = buffer.readInt(); int sizing = buffer.readInt(); @@ -222,7 +228,7 @@ public class RootContentBehavior implements RemoteComposeOperation { operations.add(rootContentBehavior); } - public static void documentation(DocumentationBuilder doc) { + public static void documentation(@NonNull DocumentationBuilder doc) { doc.operation("Protocol Operations", OP_CODE, CLASS_NAME) .description("Describes the behaviour of the root") .field(DocumentedOperation.INT, "scroll", "scroll") 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 bff902926fd315b2f10558e10a5ce7916c65d8ac..c2d62a7b3ac446127885fca84fa9752b77e8c1c0 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 @@ -15,6 +15,8 @@ */ package com.android.internal.widget.remotecompose.core.operations; +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.RemoteComposeOperation; @@ -41,25 +43,28 @@ public class RootContentDescription implements RemoteComposeOperation { } @Override - public void write(WireBuffer buffer) { + public void write(@NonNull WireBuffer buffer) { apply(buffer, mContentDescription); } + @NonNull @Override public String toString() { return "RootContentDescription " + mContentDescription; } @Override - public void apply(RemoteContext context) { + public void apply(@NonNull RemoteContext context) { context.setDocumentContentDescription(mContentDescription); } + @NonNull @Override public String deepToString(String indent) { return toString(); } + @NonNull public static String name() { return CLASS_NAME; } @@ -68,18 +73,18 @@ public class RootContentDescription implements RemoteComposeOperation { return OP_CODE; } - public static void apply(WireBuffer buffer, int contentDescription) { + public static void apply(@NonNull WireBuffer buffer, int contentDescription) { buffer.start(Operations.ROOT_CONTENT_DESCRIPTION); buffer.writeInt(contentDescription); } - public static void read(WireBuffer buffer, List operations) { + public static void read(@NonNull WireBuffer buffer, @NonNull List operations) { int contentDescription = buffer.readInt(); RootContentDescription header = new RootContentDescription(contentDescription); operations.add(header); } - public static void documentation(DocumentationBuilder doc) { + public static void documentation(@NonNull DocumentationBuilder doc) { doc.operation("Protocol Operations", OP_CODE, CLASS_NAME) .description("Content description of root") .field(DocumentedOperation.INT, "id", "id of Int"); 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 7ec7879bf8b2ce6e1ef6540cd395c426ab79fa66..ae61c3aa01c953b476398d27861ad4519d697526 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 @@ -22,6 +22,9 @@ import static com.android.internal.widget.remotecompose.core.documentation.Docum import static com.android.internal.widget.remotecompose.core.documentation.DocumentedOperation.SHORT; 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; import com.android.internal.widget.remotecompose.core.RemoteContext; @@ -43,17 +46,17 @@ public class ShaderData implements Operation, VariableSupport { private static final String CLASS_NAME = "ShaderData"; int mShaderTextId; // the actual text of a shader int mShaderID; // allows shaders to be referenced by number - HashMap mUniformRawFloatMap = null; - HashMap mUniformFloatMap = null; - HashMap mUniformIntMap = null; - HashMap mUniformBitmapMap = null; + @Nullable HashMap mUniformRawFloatMap = null; + @Nullable HashMap mUniformFloatMap = null; + @Nullable HashMap mUniformIntMap = null; + @Nullable HashMap mUniformBitmapMap = null; public ShaderData( int shaderID, int shaderTextId, - HashMap floatMap, - HashMap intMap, - HashMap bitmapMap) { + @Nullable HashMap floatMap, + @Nullable HashMap intMap, + @Nullable HashMap bitmapMap) { mShaderID = shaderID; mShaderTextId = shaderTextId; if (floatMap != null) { @@ -89,6 +92,7 @@ public class ShaderData implements Operation, VariableSupport { * * @return Names of all uniform floats or empty array */ + @NonNull public String[] getUniformFloatNames() { if (mUniformFloatMap == null) return new String[0]; return mUniformFloatMap.keySet().toArray(new String[0]); @@ -109,6 +113,7 @@ public class ShaderData implements Operation, VariableSupport { * * @return Name of all integer uniforms */ + @NonNull public String[] getUniformIntegerNames() { if (mUniformIntMap == null) return new String[0]; return mUniformIntMap.keySet().toArray(new String[0]); @@ -129,6 +134,7 @@ public class ShaderData implements Operation, VariableSupport { * * @return Name of all bitmap uniforms */ + @NonNull public String[] getUniformBitmapNames() { if (mUniformBitmapMap == null) return new String[0]; return mUniformBitmapMap.keySet().toArray(new String[0]); @@ -145,7 +151,7 @@ public class ShaderData implements Operation, VariableSupport { } @Override - public void write(WireBuffer buffer) { + public void write(@NonNull WireBuffer buffer) { apply( buffer, mShaderID, @@ -155,13 +161,14 @@ public class ShaderData implements Operation, VariableSupport { mUniformBitmapMap); } + @NonNull @Override public String toString() { return "SHADER DATA " + mShaderID; } @Override - public void updateVariables(RemoteContext context) { + public void updateVariables(@NonNull RemoteContext context) { for (String name : mUniformRawFloatMap.keySet()) { float[] value = mUniformRawFloatMap.get(name); float[] out = null; @@ -178,7 +185,7 @@ public class ShaderData implements Operation, VariableSupport { } @Override - public void registerListening(RemoteContext context) { + public void registerListening(@NonNull RemoteContext context) { for (String name : mUniformRawFloatMap.keySet()) { float[] value = mUniformRawFloatMap.get(name); for (float v : value) { @@ -189,6 +196,7 @@ public class ShaderData implements Operation, VariableSupport { } } + @NonNull public static String name() { return CLASS_NAME; } @@ -208,12 +216,12 @@ public class ShaderData implements Operation, VariableSupport { * @param bitmapMap the map of bitmap uniforms */ public static void apply( - WireBuffer buffer, + @NonNull WireBuffer buffer, int shaderID, int shaderTextId, - HashMap floatMap, - HashMap intMap, - HashMap bitmapMap) { + @Nullable HashMap floatMap, + @Nullable HashMap intMap, + @Nullable HashMap bitmapMap) { buffer.start(OP_CODE); buffer.writeInt(shaderID); @@ -256,7 +264,7 @@ public class ShaderData implements Operation, VariableSupport { } } - public static void read(WireBuffer buffer, List operations) { + public static void read(@NonNull WireBuffer buffer, @NonNull List operations) { int shaderID = buffer.readInt(); int shaderTextId = buffer.readInt(); HashMap floatMap = null; @@ -308,7 +316,7 @@ public class ShaderData implements Operation, VariableSupport { operations.add(new ShaderData(shaderID, shaderTextId, floatMap, intMap, bitmapMap)); } - public static void documentation(DocumentationBuilder doc) { + public static void documentation(@NonNull DocumentationBuilder doc) { doc.operation("Data Operations", OP_CODE, CLASS_NAME) .description("Shader") .field(DocumentedOperation.INT, "shaderID", "id of shader") @@ -326,10 +334,11 @@ public class ShaderData implements Operation, VariableSupport { } @Override - public void apply(RemoteContext context) { + public void apply(@NonNull RemoteContext context) { context.loadShader(mShaderID, this); } + @NonNull @Override public String deepToString(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 638324950f882975ce05c431f5351c73a40bdade..dbaef7ef7ae14c906eb4eec9d74ca3ffbf8bf851 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 @@ -17,6 +17,8 @@ package com.android.internal.widget.remotecompose.core.operations; import static com.android.internal.widget.remotecompose.core.documentation.DocumentedOperation.UTF8; +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; @@ -42,15 +44,17 @@ public class TextData implements Operation, SerializableToString { } @Override - public void write(WireBuffer buffer) { + public void write(@NonNull WireBuffer buffer) { apply(buffer, mTextId, mText); } + @NonNull @Override public String toString() { return "TextData[" + mTextId + "] = \"" + Utils.trimString(mText, 10) + "\""; } + @NonNull public static String name() { return CLASS_NAME; } @@ -59,20 +63,20 @@ public class TextData implements Operation, SerializableToString { return OP_CODE; } - public static void apply(WireBuffer buffer, int textId, String text) { + public static void apply(@NonNull WireBuffer buffer, int textId, @NonNull String text) { buffer.start(OP_CODE); buffer.writeInt(textId); buffer.writeUTF8(text); } - public static void read(WireBuffer buffer, List operations) { + public static void read(@NonNull WireBuffer buffer, @NonNull List operations) { int textId = buffer.readInt(); String text = buffer.readUTF8(MAX_STRING_SIZE); operations.add(new TextData(textId, text)); } - public static void documentation(DocumentationBuilder doc) { + public static void documentation(@NonNull DocumentationBuilder doc) { doc.operation("Data Operations", OP_CODE, CLASS_NAME) .description("Encode a string ") .field(DocumentedOperation.INT, "id", "id string") @@ -80,20 +84,22 @@ public class TextData implements Operation, SerializableToString { } @Override - public void apply(RemoteContext context) { + public void apply(@NonNull RemoteContext context) { context.loadText(mTextId, mText); } + @NonNull @Override public String deepToString(String indent) { return indent + toString(); } @Override - public void serializeToString(int indent, StringSerializer serializer) { + public void serializeToString(int indent, @NonNull StringSerializer serializer) { serializer.append(indent, getSerializedName() + "<" + mTextId + "> = \"" + mText + "\""); } + @NonNull private String getSerializedName() { return "DATA_TEXT"; } 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 0d966d10384a75b1889bb41abb005991472b54c3..fb5087f3fee333a3ea022a1aa957f0f8e1ddf9ee 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 @@ -18,6 +18,8 @@ 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.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; @@ -87,10 +89,11 @@ public class TextFromFloat implements Operation, VariableSupport { } @Override - public void write(WireBuffer buffer) { + public void write(@NonNull WireBuffer buffer) { apply(buffer, mTextId, mValue, mDigitsBefore, mDigitsAfter, mFlags); } + @NonNull @Override public String toString() { return "TextFromFloat[" @@ -106,19 +109,20 @@ public class TextFromFloat implements Operation, VariableSupport { } @Override - public void updateVariables(RemoteContext context) { + public void updateVariables(@NonNull RemoteContext context) { if (Float.isNaN(mValue)) { mOutValue = context.getFloat(Utils.idFromNan(mValue)); } } @Override - public void registerListening(RemoteContext context) { + public void registerListening(@NonNull RemoteContext context) { if (Float.isNaN(mValue)) { context.listensTo(Utils.idFromNan(mValue), this); } } + @NonNull public static String name() { return CLASS_NAME; } @@ -138,7 +142,7 @@ public class TextFromFloat implements Operation, VariableSupport { * @param flags flags that control if and how to fill the empty spots */ public static void apply( - WireBuffer buffer, + @NonNull WireBuffer buffer, int textId, float value, short digitsBefore, @@ -151,7 +155,7 @@ public class TextFromFloat implements Operation, VariableSupport { buffer.writeInt(flags); } - public static void read(WireBuffer buffer, List operations) { + public static void read(@NonNull WireBuffer buffer, @NonNull List operations) { int textId = buffer.readInt(); float value = buffer.readFloat(); int tmp = buffer.readInt(); @@ -162,7 +166,7 @@ public class TextFromFloat implements Operation, VariableSupport { operations.add(new TextFromFloat(textId, value, pre, post, flags)); } - public static void documentation(DocumentationBuilder doc) { + public static void documentation(@NonNull DocumentationBuilder doc) { doc.operation("Expressions Operations", OP_CODE, CLASS_NAME) .description("Draw text along path object") .field(DocumentedOperation.INT, "textId", "id of the text generated") @@ -173,12 +177,13 @@ public class TextFromFloat implements Operation, VariableSupport { } @Override - public void apply(RemoteContext context) { + public void apply(@NonNull RemoteContext context) { float v = mOutValue; String s = StringUtils.floatToString(v, mDigitsBefore, mDigitsAfter, mPre, mAfter); context.loadText(mTextId, s); } + @NonNull @Override public String deepToString(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 b04d698fa36c7d518c217bdf9f48931aff098f28..2129edde2f59d64dbce821fa08305e2ca29cc3ee 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 @@ -18,6 +18,8 @@ package com.android.internal.widget.remotecompose.core.operations; 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.RemoteContext; @@ -48,10 +50,11 @@ public class TextLookup implements Operation, VariableSupport { } @Override - public void write(WireBuffer buffer) { + public void write(@NonNull WireBuffer buffer) { apply(buffer, mTextId, mDataSetId, mIndex); } + @NonNull @Override public String toString() { return "TextLookup[" @@ -63,19 +66,20 @@ public class TextLookup implements Operation, VariableSupport { } @Override - public void updateVariables(RemoteContext context) { + public void updateVariables(@NonNull RemoteContext context) { if (Float.isNaN(mIndex)) { mOutIndex = context.getFloat(Utils.idFromNan(mIndex)); } } @Override - public void registerListening(RemoteContext context) { + public void registerListening(@NonNull RemoteContext context) { if (Float.isNaN(mIndex)) { context.listensTo(Utils.idFromNan(mIndex), this); } } + @NonNull public static String name() { return CLASS_NAME; } @@ -92,21 +96,21 @@ public class TextLookup implements Operation, VariableSupport { * @param dataSet float pointer to the array/list to turn int a string * @param index index of element to return */ - public static void apply(WireBuffer buffer, int textId, int dataSet, float index) { + public static void apply(@NonNull WireBuffer buffer, int textId, int dataSet, float index) { buffer.start(OP_CODE); buffer.writeInt(textId); buffer.writeInt(dataSet); buffer.writeFloat(index); } - public static void read(WireBuffer buffer, List operations) { + public static void read(@NonNull WireBuffer buffer, @NonNull List operations) { int textId = buffer.readInt(); int dataSetId = buffer.readInt(); float index = buffer.readFloat(); operations.add(new TextLookup(textId, dataSetId, index)); } - public static void documentation(DocumentationBuilder doc) { + public static void documentation(@NonNull DocumentationBuilder doc) { doc.operation("Expressions Operations", OP_CODE, CLASS_NAME) .description("Look an array and turn into a text object") .field(INT, "textId", "id of the text generated") @@ -115,11 +119,12 @@ public class TextLookup implements Operation, VariableSupport { } @Override - public void apply(RemoteContext context) { + public void apply(@NonNull RemoteContext context) { int id = context.getCollectionsAccess().getId(mDataSetId, (int) mOutIndex); context.loadText(mTextId, context.getText(id)); } + @NonNull @Override public String deepToString(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 171bea2492731a707e34ec75e643eedac8dc8d2e..ea550cbe010c7dd9d2bdb5d5d29c6c303ec7dfdf 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 @@ -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; @@ -45,10 +47,11 @@ public class TextLookupInt implements Operation, VariableSupport { } @Override - public void write(WireBuffer buffer) { + public void write(@NonNull WireBuffer buffer) { apply(buffer, mTextId, mDataSetId, mIndex); } + @NonNull @Override public String toString() { return "TextLookupInt[" @@ -60,15 +63,16 @@ public class TextLookupInt implements Operation, VariableSupport { } @Override - public void updateVariables(RemoteContext context) { + public void updateVariables(@NonNull RemoteContext context) { mOutIndex = context.getInteger(mIndex); } @Override - public void registerListening(RemoteContext context) { + public void registerListening(@NonNull RemoteContext context) { context.listensTo(mIndex, this); } + @NonNull public static String name() { return CLASS_NAME; } @@ -85,21 +89,21 @@ public class TextLookupInt implements Operation, VariableSupport { * @param dataSet float pointer to the array/list to turn int a string * @param indexId index of element to return */ - public static void apply(WireBuffer buffer, int textId, int dataSet, int indexId) { + public static void apply(@NonNull WireBuffer buffer, int textId, int dataSet, int indexId) { buffer.start(OP_CODE); buffer.writeInt(textId); buffer.writeInt(dataSet); buffer.writeInt(indexId); } - public static void read(WireBuffer buffer, List operations) { + public static void read(@NonNull WireBuffer buffer, @NonNull List operations) { int textId = buffer.readInt(); int dataSetId = buffer.readInt(); int indexId = buffer.readInt(); operations.add(new TextLookupInt(textId, dataSetId, indexId)); } - public static void documentation(DocumentationBuilder doc) { + public static void documentation(@NonNull DocumentationBuilder doc) { doc.operation("Expressions Operations", OP_CODE, CLASS_NAME) .description("Look up an array and turn into a text object") .field(DocumentedOperation.INT, "textId", "id of the text generated") @@ -108,11 +112,12 @@ public class TextLookupInt implements Operation, VariableSupport { } @Override - public void apply(RemoteContext context) { + public void apply(@NonNull RemoteContext context) { int id = context.getCollectionsAccess().getId(mDataSetId, (int) mOutIndex); context.loadText(mTextId, context.getText(id)); } + @NonNull @Override public String deepToString(String indent) { return indent + toString(); 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 78cc674a22e9b555ddb7f6400c5c922e5b2b41c4..fa18b4ddb2a2eb42e255bf9d1c15612eb7855c54 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 @@ -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; @@ -41,15 +43,17 @@ public class TextMerge implements Operation { } @Override - public void write(WireBuffer buffer) { + public void write(@NonNull WireBuffer buffer) { apply(buffer, mTextId, mSrcId1, mSrcId2); } + @NonNull @Override public String toString() { return "TextMerge[" + mTextId + "] = [" + mSrcId1 + " ] + [ " + mSrcId2 + "]"; } + @NonNull public static String name() { return CLASS_NAME; } @@ -66,14 +70,14 @@ public class TextMerge implements Operation { * @param srcId1 source text 1 * @param srcId2 source text 2 */ - public static void apply(WireBuffer buffer, int textId, int srcId1, int srcId2) { + public static void apply(@NonNull WireBuffer buffer, int textId, int srcId1, int srcId2) { buffer.start(OP_CODE); buffer.writeInt(textId); buffer.writeInt(srcId1); buffer.writeInt(srcId2); } - public static void read(WireBuffer buffer, List operations) { + public static void read(@NonNull WireBuffer buffer, @NonNull List operations) { int textId = buffer.readInt(); int srcId1 = buffer.readInt(); int srcId2 = buffer.readInt(); @@ -81,7 +85,7 @@ public class TextMerge implements Operation { operations.add(new TextMerge(textId, srcId1, srcId2)); } - public static void documentation(DocumentationBuilder doc) { + public static void documentation(@NonNull DocumentationBuilder doc) { doc.operation("Data Operations", OP_CODE, CLASS_NAME) .description("Merge two string into one") .field(DocumentedOperation.INT, "textId", "id of the text") @@ -90,12 +94,13 @@ public class TextMerge implements Operation { } @Override - public void apply(RemoteContext context) { + public void apply(@NonNull RemoteContext context) { String str1 = context.getText(mSrcId1); String str2 = context.getText(mSrcId2); context.loadText(mTextId, str1 + str2); } + @NonNull @Override public String deepToString(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 845f25d0cd67271fdbd457593c7ff53dfe825ec6..1e90ab128e932a0388ff826fabfda6b26adf306c 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 @@ -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.RemoteComposeOperation; @@ -49,25 +51,28 @@ public class Theme implements RemoteComposeOperation { } @Override - public void write(WireBuffer buffer) { + public void write(@NonNull WireBuffer buffer) { apply(buffer, mTheme); } + @NonNull @Override public String toString() { return "SET_THEME " + mTheme; } @Override - public void apply(RemoteContext context) { + public void apply(@NonNull RemoteContext context) { context.setTheme(mTheme); } + @NonNull @Override public String deepToString(String indent) { return indent + toString(); } + @NonNull public static String name() { return CLASS_NAME; } @@ -76,17 +81,17 @@ public class Theme implements RemoteComposeOperation { return OP_CODE; } - public static void apply(WireBuffer buffer, int theme) { + public static void apply(@NonNull WireBuffer buffer, int theme) { buffer.start(OP_CODE); buffer.writeInt(theme); } - public static void read(WireBuffer buffer, List operations) { + public static void read(@NonNull WireBuffer buffer, @NonNull List operations) { int theme = buffer.readInt(); operations.add(new Theme(theme)); } - public static void documentation(DocumentationBuilder doc) { + public static void documentation(@NonNull DocumentationBuilder doc) { doc.operation("Protocol Operations", OP_CODE, CLASS_NAME) .description("Set a theme") .field(INT, "THEME", "theme id") 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 new file mode 100644 index 0000000000000000000000000000000000000000..b25a7f6ea09d97064f3fa5d5333ae5d9ac07e37c --- /dev/null +++ b/core/java/com/android/internal/widget/remotecompose/core/operations/TouchExpression.java @@ -0,0 +1,599 @@ +/* + * Copyright (C) 2023 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.android.internal.widget.remotecompose.core.operations; + +import static com.android.internal.widget.remotecompose.core.documentation.DocumentedOperation.FLOAT; +import static com.android.internal.widget.remotecompose.core.documentation.DocumentedOperation.FLOAT_ARRAY; +import static com.android.internal.widget.remotecompose.core.documentation.DocumentedOperation.INT; +import static com.android.internal.widget.remotecompose.core.documentation.DocumentedOperation.SHORT; + +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.TouchListener; +import com.android.internal.widget.remotecompose.core.VariableSupport; +import com.android.internal.widget.remotecompose.core.WireBuffer; +import com.android.internal.widget.remotecompose.core.documentation.DocumentationBuilder; +import com.android.internal.widget.remotecompose.core.operations.layout.Component; +import com.android.internal.widget.remotecompose.core.operations.utilities.AnimatedFloatExpression; +import com.android.internal.widget.remotecompose.core.operations.utilities.NanMap; +import com.android.internal.widget.remotecompose.core.operations.utilities.touch.VelocityEasing; + +import java.util.Arrays; +import java.util.List; + +/** + * Operation to deal with Touch handling (typically on canvas) This support handling of many typical + * touch behaviours. Including animating to Notched, positions. and tweaking the dynamics of the + * animation. + */ +public class TouchExpression implements Operation, VariableSupport, TouchListener { + private static final int OP_CODE = Operations.TOUCH_EXPRESSION; + private static final String CLASS_NAME = "TouchExpression"; + private float mDefValue; + private float mOutDefValue; + public int mId; + public float[] mSrcExp; + int mMode = 1; // 0 = delta, 1 = absolute + float mMax = 1; + float mMin = 1; + float mOutMax = 1; + float mOutMin = 1; + float mValue = 0; + boolean mUnmodified = true; + public float[] mPreCalcValue; + private float mLastChange = Float.NaN; + private float mLastCalculatedValue = Float.NaN; + AnimatedFloatExpression mExp = new AnimatedFloatExpression(); + public static final int MAX_EXPRESSION_SIZE = 32; + private VelocityEasing mEasyTouch = new VelocityEasing(); + private boolean mEasingToStop = false; + private float mTouchUpTime = 0; + private float mCurrentValue = Float.NaN; + private boolean mTouchDown = false; + float mMaxTime = 1; + float mMaxAcceleration = 5; + float mMaxVelocity = 7; + int mStopMode = 0; + boolean mWrapMode = false; + float[] mNotches; + float[] mStopSpec; + int mTouchEffects; + float mVelocityId; + + public static final int STOP_GENTLY = 0; + public static final int STOP_ENDS = 2; + public static final int STOP_INSTANTLY = 1; + public static final int STOP_NOTCHES_EVEN = 3; + public static final int STOP_NOTCHES_PERCENTS = 4; + public static final int STOP_NOTCHES_ABSOLUTE = 5; + public static final int STOP_ABSOLUTE_POS = 6; + + public TouchExpression( + int id, + float[] exp, + float defValue, + float min, + float max, + int touchEffects, + float velocityId, + int stopMode, + float[] stopSpec, + float[] easingSpec) { + this.mId = id; + this.mSrcExp = exp; + mOutDefValue = mDefValue = defValue; + mMode = STOP_ABSOLUTE_POS == stopMode ? 1 : 0; + mOutMax = mMax = max; + mTouchEffects = touchEffects; + mVelocityId = velocityId; + if (Float.isNaN(min) && Utils.idFromNan(min) == 0) { + mWrapMode = true; + } else { + mOutMin = mMin = min; + } + 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]; + } + } + } + } + + @Override + public void updateVariables(RemoteContext context) { + + if (mPreCalcValue == null || mPreCalcValue.length != mSrcExp.length) { + mPreCalcValue = new float[mSrcExp.length]; + } + if (Float.isNaN(mMax)) { + mOutMax = context.getFloat(Utils.idFromNan(mMax)); + } + if (Float.isNaN(mMin)) { + mOutMin = context.getFloat(Utils.idFromNan(mMin)); + } + if (Float.isNaN(mDefValue)) { + mOutDefValue = context.getFloat(Utils.idFromNan(mDefValue)); + } + + boolean value_changed = false; + for (int i = 0; i < mSrcExp.length; i++) { + float v = mSrcExp[i]; + if (Float.isNaN(v) + && !AnimatedFloatExpression.isMathOperator(v) + && !NanMap.isDataVariable(v)) { + float newValue = context.getFloat(Utils.idFromNan(v)); + + mPreCalcValue[i] = newValue; + + } else { + mPreCalcValue[i] = mSrcExp[i]; + } + } + float v = mLastCalculatedValue; + if (value_changed) { // inputs changed check if output changed + v = mExp.eval(mPreCalcValue, mPreCalcValue.length); + if (v != mLastCalculatedValue) { + mLastChange = context.getAnimationTime(); + mLastCalculatedValue = v; + } else { + value_changed = false; + } + } + } + + @Override + public void registerListening(RemoteContext context) { + if (Float.isNaN(mMax)) { + context.listensTo(Utils.idFromNan(mMax), this); + } + if (Float.isNaN(mMin)) { + context.listensTo(Utils.idFromNan(mMin), this); + } + if (Float.isNaN(mDefValue)) { + context.listensTo(Utils.idFromNan(mDefValue), this); + } + context.addTouchListener(this); + for (float v : mSrcExp) { + if (Float.isNaN(v) + && !AnimatedFloatExpression.isMathOperator(v) + && !NanMap.isDataVariable(v)) { + context.listensTo(Utils.idFromNan(v), this); + } + } + } + + private float wrap(float pos) { + if (!mWrapMode) { + return pos; + } + pos = pos % mOutMax; + if (pos < 0) { + pos += mOutMax; + } + return pos; + } + + private float getStopPosition(float pos, float slope) { + float target = pos + slope / mMaxAcceleration; + if (mWrapMode) { + pos = wrap(pos); + target = pos += +slope / mMaxAcceleration; + } else { + target = Math.max(Math.min(target, mOutMax), mOutMin); + } + float[] positions = new float[mStopSpec.length]; + float min = (mWrapMode) ? 0 : mOutMin; + + switch (mStopMode) { + case STOP_ENDS: + return ((pos + slope) > (mOutMax + min) / 2) ? mOutMax : min; + case STOP_INSTANTLY: + return pos; + case STOP_NOTCHES_EVEN: + int evenSpacing = (int) mStopSpec[0]; + float step = (mOutMax - min) / evenSpacing; + + float notch = min + step * (int) (0.5f + (target - mOutMin) / step); + + notch = Math.max(Math.min(notch, mOutMax), min); + return notch; + case STOP_NOTCHES_PERCENTS: + positions = new float[mStopSpec.length]; + float minPos = min; + float minPosDist = Math.abs(mOutMin - target); + for (int i = 0; i < positions.length; i++) { + float p = mOutMin + mStopSpec[i] * (mOutMax - mOutMin); + float dist = Math.abs(p - target); + if (minPosDist > dist) { + minPosDist = dist; + minPos = p; + } + } + return minPos; + case STOP_NOTCHES_ABSOLUTE: + positions = mStopSpec; + minPos = mOutMin; + minPosDist = Math.abs(mOutMin - target); + for (int i = 0; i < positions.length; i++) { + float dist = Math.abs(positions[i] - target); + if (minPosDist > dist) { + minPosDist = dist; + minPos = positions[i]; + } + } + return minPos; + case STOP_GENTLY: + default: + return target; + } + } + + void haptic(RemoteContext context) { + int touch = ((mTouchEffects) & 0xFF); + if ((mTouchEffects & (1 << 15)) != 0) { + touch = context.getInteger(mTouchEffects & 0x7FFF); + } + + context.hapticEffect(touch); + } + + float mLastValue = 0; + + void crossNotchCheck(RemoteContext context) { + float prev = mLastValue; + float next = mCurrentValue; + mLastValue = next; + + // System.out.println(mStopMode + " " + prev + " -> " + next); + float min = (mWrapMode) ? 0 : mOutMin; + float max = mOutMax; + + switch (mStopMode) { + case STOP_ENDS: + if (((min - prev) * (max - prev) < 0) ^ ((min - next) * (max - next)) < 0) { + haptic(context); + } + break; + case STOP_INSTANTLY: + haptic(context); + break; + case STOP_NOTCHES_EVEN: + int evenSpacing = (int) mStopSpec[0]; + float step = (max - min) / evenSpacing; + if ((int) ((prev - min) / step) != (int) ((next - min) / step)) { + haptic(context); + } + break; + case STOP_NOTCHES_PERCENTS: + for (int i = 0; i < mStopSpec.length; i++) { + float p = mOutMin + mStopSpec[i] * (mOutMax - mOutMin); + if ((prev - p) * (next - p) < 0) { + haptic(context); + } + } + break; + case STOP_NOTCHES_ABSOLUTE: + for (int i = 0; i < mStopSpec.length; i++) { + float p = mStopSpec[i]; + if ((prev - p) * (next - p) < 0) { + haptic(context); + } + } + break; + case STOP_GENTLY: + } + } + + float mScrLeft, mScrRight, mScrTop, mScrBottom; + + @Override + public void apply(RemoteContext context) { + Component comp = context.lastComponent; + if (comp != null) { + float x = comp.getX(); + float y = comp.getY(); + float w = comp.getWidth(); + float h = comp.getHeight(); + comp = comp.getParent(); + while (comp != null) { + x += comp.getX(); + y += comp.getY(); + comp = comp.getParent(); + } + mScrLeft = x; + mScrTop = y; + mScrRight = w + x; + mScrBottom = h + y; + } + updateVariables(context); + if (mUnmodified) { + mCurrentValue = mOutDefValue; + + context.loadFloat(mId, wrap(mCurrentValue)); + return; + } + if (mEasingToStop) { + float time = context.getAnimationTime() - mTouchUpTime; + float value = mEasyTouch.getPos(time); + mCurrentValue = value; + value = wrap(value); + context.loadFloat(mId, value); + if (mEasyTouch.getDuration() < time) { + mEasingToStop = false; + } + crossNotchCheck(context); + return; + } + if (mTouchDown) { + float value = + mExp.eval(context.getCollectionsAccess(), mPreCalcValue, mPreCalcValue.length); + if (mMode == 0) { + value = mValueAtDown + (value - mDownTouchValue); + } + if (mWrapMode) { + value = wrap(value); + } else { + value = Math.min(Math.max(value, mOutMin), mOutMax); + } + mCurrentValue = value; + } + crossNotchCheck(context); + context.loadFloat(mId, wrap(mCurrentValue)); + } + + float mValueAtDown; // The currently "displayed" value at down + float mDownTouchValue; // The calculated value at down + + @Override + public void touchDown(RemoteContext context, float x, float y) { + + if (!(x >= mScrLeft && x <= mScrRight && y >= mScrTop && y <= mScrBottom)) { + Utils.log("NOT IN WINDOW " + x + ", " + y + " " + mScrLeft + ", " + mScrTop); + return; + } + mTouchDown = true; + mUnmodified = false; + if (mMode == 0) { + mValueAtDown = context.getFloat(mId); + mDownTouchValue = + mExp.eval(context.getCollectionsAccess(), mPreCalcValue, mPreCalcValue.length); + } + } + + @Override + public void touchUp(RemoteContext context, float x, float y, float dx, float dy) { + // calculate the slope (using small changes) + if (!mTouchDown) { + return; + } + mTouchDown = false; + float dt = 0.0001f; + if (mStopMode == STOP_INSTANTLY) { + return; + } + float v = mExp.eval(context.getCollectionsAccess(), mPreCalcValue, mPreCalcValue.length); + for (int i = 0; i < mSrcExp.length; i++) { + if (Float.isNaN(mSrcExp[i])) { + int id = Utils.idFromNan(mSrcExp[i]); + if (id == RemoteContext.ID_TOUCH_POS_X) { + mPreCalcValue[i] = x + dx * dt; + } else if (id == RemoteContext.ID_TOUCH_POS_Y) { + mPreCalcValue[i] = y + dy * dt; + } + } + } + float vdt = mExp.eval(context.getCollectionsAccess(), mPreCalcValue, mPreCalcValue.length); + float slope = (vdt - v) / dt; // the rate of change with respect to the dx,dy movement + float value = context.getFloat(mId); + + mTouchUpTime = context.getAnimationTime(); + + float dest = getStopPosition(value, slope); + mEasyTouch.config(value, dest, slope, mMaxTime, mMaxAcceleration, mMaxVelocity, null); + mEasingToStop = true; + } + + @Override + public void touchDrag(RemoteContext context, float x, float y) { + if (!mTouchDown) { + return; + } + apply(context); + context.getDocument().getRootLayoutComponent().needsRepaint(); + } + + @Override + public void write(WireBuffer buffer) { + apply( + buffer, + mId, + mValue, + mMin, + mMax, + mVelocityId, + mTouchEffects, + mSrcExp, + mStopMode, + mNotches, + null); + } + + @Override + public String toString() { + String[] labels = new String[mSrcExp.length]; + for (int i = 0; i < mSrcExp.length; i++) { + if (Float.isNaN(mSrcExp[i])) { + labels[i] = "[" + Utils.idStringFromNan(mSrcExp[i]) + "]"; + } + } + if (mPreCalcValue == null) { + return CLASS_NAME + + "[" + + mId + + "] = (" + + AnimatedFloatExpression.toString(mSrcExp, labels) + + ")"; + } + return CLASS_NAME + + "[" + + mId + + "] = (" + + AnimatedFloatExpression.toString(mPreCalcValue, labels) + + ")"; + } + + // ===================== static ====================== + + public static String name() { + return CLASS_NAME; + } + + public static int id() { + return OP_CODE; + } + + /** + * Writes out the operation to the buffer + * + * @param buffer The buffer to write to + * @param id the id of the resulting float + * @param value the float expression array + */ + public static void apply( + WireBuffer buffer, + int id, + float value, + float min, + float max, + float velocityId, + int touchEffects, + float[] exp, + int touchMode, + float[] touchSpec, + float[] easingSpec) { + buffer.start(OP_CODE); + buffer.writeInt(id); + buffer.writeFloat(value); + buffer.writeFloat(min); + buffer.writeFloat(max); + buffer.writeFloat(velocityId); + buffer.writeInt(touchEffects); + buffer.writeInt(exp.length); + for (float v : exp) { + buffer.writeFloat(v); + } + int len = 0; + if (touchSpec != null) { + len = touchSpec.length; + } + buffer.writeInt((touchMode << 16) | len); + for (int i = 0; i < len; i++) { + buffer.writeFloat(touchSpec[i]); + } + + if (easingSpec != null) { + len = easingSpec.length; + } else { + len = 0; + } + buffer.writeInt(len); + for (int i = 0; i < len; i++) { + buffer.writeFloat(easingSpec[i]); + } + } + + public static void read(WireBuffer buffer, List operations) { + int id = buffer.readInt(); + float startValue = buffer.readFloat(); + float min = buffer.readFloat(); + float max = buffer.readFloat(); + float velocityId = buffer.readFloat(); // TODO future support + int touchEffects = buffer.readInt(); + int len = buffer.readInt(); + int valueLen = len & 0xFFFF; + if (valueLen > MAX_EXPRESSION_SIZE) { + throw new RuntimeException("Float expression to long"); + } + float[] exp = new float[valueLen]; + for (int i = 0; i < exp.length; i++) { + exp[i] = buffer.readFloat(); + } + int stopLogic = buffer.readInt(); + 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(); + } + int easingLen = buffer.readInt(); + + float[] easingData = new float[easingLen]; + for (int i = 0; i < easingData.length; i++) { + easingData[i] = buffer.readFloat(); + } + + operations.add( + new TouchExpression( + id, + exp, + startValue, + min, + max, + touchEffects, + velocityId, + stopMode, + stopsData, + easingData)); + } + + public static void documentation(DocumentationBuilder doc) { + doc.operation("Expressions Operations", OP_CODE, CLASS_NAME) + .description("A Float expression") + .field(INT, "id", "The id of the Color") + .field(SHORT, "expression_length", "expression length") + .field(SHORT, "animation_length", "animation description length") + .field( + FLOAT_ARRAY, + "expression", + "expression_length", + "Sequence of Floats representing and expression") + .field( + FLOAT_ARRAY, + "AnimationSpec", + "animation_length", + "Sequence of Floats representing animation curve") + .field(FLOAT, "duration", "> time in sec") + .field(INT, "bits", "> WRAP|INITALVALUE | TYPE ") + .field(FLOAT_ARRAY, "spec", "> [SPEC PARAMETERS] ") + .field(FLOAT, "initialValue", "> [Initial value] ") + .field(FLOAT, "wrapValue", "> [Wrap value] "); + } + + @Override + public String deepToString(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 8ebb40cab8064e0b3297b63f8924d4ea43a4204e..03f7e0563eeb5cde846612b6ddc2ed6f5043aa84 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 @@ -15,6 +15,8 @@ */ package com.android.internal.widget.remotecompose.core.operations; +import android.annotation.NonNull; + /** Utilities to be used across all core operations */ public class Utils { public static float asNan(int v) { @@ -30,11 +32,13 @@ public class Utils { return v - 0x100000000L; } + @NonNull public static String idStringFromNan(float value) { int b = Float.floatToRawIntBits(value) & 0x3FFFFF; return idString(b); } + @NonNull public static String idString(int b) { return (b > 0xFFFFF) ? "A_" + (b & 0xFFFFF) : "" + b; } @@ -50,7 +54,8 @@ public class Utils { * @param n * @return */ - public static String trimString(String str, int n) { + @NonNull + public static String trimString(@NonNull String str, int n) { if (str.length() > n) { str = str.substring(0, n - 3) + "..."; } @@ -145,6 +150,7 @@ public class Utils { * @param color * @return */ + @NonNull public static String colorInt(int color) { String str = "000000000000" + Integer.toHexString(color); return "0x" + str.substring(str.length() - 8); 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 new file mode 100644 index 0000000000000000000000000000000000000000..e789710bb11385ddb458689a0e4079ef3ef8be0c --- /dev/null +++ b/core/java/com/android/internal/widget/remotecompose/core/operations/layout/AnimatableValue.java @@ -0,0 +1,80 @@ +/* + * 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; + +import com.android.internal.widget.remotecompose.core.PaintContext; +import com.android.internal.widget.remotecompose.core.operations.Utils; +import com.android.internal.widget.remotecompose.core.operations.utilities.easing.FloatAnimation; +import com.android.internal.widget.remotecompose.core.operations.utilities.easing.GeneralEasing; + +public class AnimatableValue { + boolean mIsVariable = false; + int mId = 0; + float mValue = 0f; + + boolean mAnimate = false; + long mAnimateTargetTime = 0; + float mAnimateDuration = 300f; + float mTargetRotationX; + float mStartRotationX; + + int mMotionEasingType = GeneralEasing.CUBIC_STANDARD; + FloatAnimation mMotionEasing; + + public AnimatableValue(float value) { + if (Utils.isVariable(value)) { + mId = Utils.idFromNan(value); + mIsVariable = true; + } else { + mValue = value; + } + } + + public float getValue() { + return mValue; + } + + public float evaluate(PaintContext context) { + if (!mIsVariable) { + return mValue; + } + float value = context.getContext().mRemoteComposeState.getFloat(mId); + + if (value != mValue && !mAnimate) { + // animate + mStartRotationX = mValue; + mTargetRotationX = value; + mAnimate = true; + mAnimateTargetTime = System.currentTimeMillis(); + mMotionEasing = + new FloatAnimation( + mMotionEasingType, mAnimateDuration / 1000f, null, 0f, Float.NaN); + mMotionEasing.setTargetValue(1f); + } + if (mAnimate) { + float elapsed = System.currentTimeMillis() - mAnimateTargetTime; + float p = mMotionEasing.get(elapsed / mAnimateDuration); + mValue = (1 - p) * mStartRotationX + p * mTargetRotationX; + if (p >= 1f) { + mAnimate = false; + } + } else { + mValue = mTargetRotationX; + } + + return mValue; + } +} diff --git a/core/java/com/android/internal/widget/remotecompose/core/operations/layout/CanvasContent.java b/core/java/com/android/internal/widget/remotecompose/core/operations/layout/CanvasContent.java index 9d80d3cc40b03b5b416912e5c697f32e775d2516..988651895bae06c194de8fccc8e1571e78ffb317 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 @@ -17,6 +17,8 @@ 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 com.android.internal.widget.remotecompose.core.Operation; import com.android.internal.widget.remotecompose.core.Operations; import com.android.internal.widget.remotecompose.core.WireBuffer; @@ -38,6 +40,7 @@ public class CanvasContent extends Component implements ComponentStartOperation super(parent, componentId, animationId, x, y, width, height); } + @NonNull public static String name() { return "CanvasContent"; } @@ -46,29 +49,30 @@ public class CanvasContent extends Component implements ComponentStartOperation return Operations.LAYOUT_CANVAS_CONTENT; } + @NonNull @Override protected String getSerializedName() { return "CANVAS_CONTENT"; } - public static void apply(WireBuffer buffer, int componentId) { + public static void apply(@NonNull WireBuffer buffer, int componentId) { buffer.start(Operations.LAYOUT_CANVAS_CONTENT); buffer.writeInt(componentId); } - public static void read(WireBuffer buffer, List operations) { + public static void read(@NonNull WireBuffer buffer, @NonNull List operations) { int componentId = buffer.readInt(); operations.add(new CanvasContent(componentId, 0, 0, 0, 0, null, -1)); } - public static void documentation(DocumentationBuilder doc) { + public static void documentation(@NonNull DocumentationBuilder doc) { doc.operation("Layout Operations", id(), name()) .field(INT, "COMPONENT_ID", "unique id for this component") .description("Container for canvas commands."); } @Override - public void write(WireBuffer buffer) { + public void write(@NonNull WireBuffer buffer) { apply(buffer, mComponentId); } } diff --git a/core/java/com/android/internal/widget/remotecompose/core/operations/layout/ClickHandler.java b/core/java/com/android/internal/widget/remotecompose/core/operations/layout/ClickHandler.java new file mode 100644 index 0000000000000000000000000000000000000000..0ca72fae9eea31df99e5ac2d434f43e20f0d3faf --- /dev/null +++ b/core/java/com/android/internal/widget/remotecompose/core/operations/layout/ClickHandler.java @@ -0,0 +1,35 @@ +/* + * 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; + +import com.android.internal.widget.remotecompose.core.CoreDocument; +import com.android.internal.widget.remotecompose.core.RemoteContext; + +/** Interface to represent operations that can handle click events */ +public interface ClickHandler { + + /** + * callback for a click event + * + * @param context the current context + * @param document the current document + * @param component the component on which the click 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 onClick( + RemoteContext context, CoreDocument document, Component component, float x, float y); +} 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 d5ff07df54cd2fde5d1d2ef7121224ed0ce84dc3..b567538b1c4e174e76b4958f83f78a41d131a211 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 @@ -15,6 +15,9 @@ */ 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; import com.android.internal.widget.remotecompose.core.Operations; @@ -37,7 +40,7 @@ import java.util.List; /** Represents a click modifier + actions */ public class ClickModifierOperation extends PaintOperation - implements ModifierOperation, DecoratorComponent { + implements ModifierOperation, DecoratorComponent, ClickHandler { private static final int OP_CODE = Operations.MODIFIER_CLICK; long mAnimateRippleStart = 0; @@ -48,9 +51,9 @@ public class ClickModifierOperation extends PaintOperation float mWidth = 0; float mHeight = 0; - public float[] locationInWindow = new float[2]; + @NonNull public float[] locationInWindow = new float[2]; - PaintBundle mPaint = new PaintBundle(); + @NonNull PaintBundle mPaint = new PaintBundle(); public void animateRipple(float x, float y) { mAnimateRippleStart = System.currentTimeMillis(); @@ -58,17 +61,19 @@ public class ClickModifierOperation extends PaintOperation mAnimateRippleY = y; } - public ArrayList mList = new ArrayList<>(); + @NonNull public ArrayList mList = new ArrayList<>(); + @NonNull public ArrayList getList() { return mList; } @Override - public void write(WireBuffer buffer) { + public void write(@NonNull WireBuffer buffer) { apply(buffer); } + @NonNull @Override public String toString() { return "ClickModifier"; @@ -83,13 +88,14 @@ public class ClickModifierOperation extends PaintOperation } } + @NonNull @Override - public String deepToString(String indent) { + public String deepToString(@Nullable String indent) { return (indent != null ? indent : "") + toString(); } @Override - public void paint(PaintContext context) { + public void paint(@NonNull PaintContext context) { if (mAnimateRippleStart == 0) { return; } @@ -137,7 +143,7 @@ public class ClickModifierOperation extends PaintOperation } @Override - public void serializeToString(int indent, StringSerializer serializer) { + public void serializeToString(int indent, @NonNull StringSerializer serializer) { serializer.append(indent, "CLICK_MODIFIER"); for (Operation o : mList) { if (o instanceof ActionOperation) { @@ -148,7 +154,11 @@ public class ClickModifierOperation extends PaintOperation @Override public void onClick( - RemoteContext context, CoreDocument document, Component component, float x, float y) { + RemoteContext context, + CoreDocument document, + @NonNull Component component, + float x, + float y) { if (!component.isVisible()) { return; } @@ -163,19 +173,20 @@ public class ClickModifierOperation extends PaintOperation } } + @NonNull public static String name() { return "ClickModifier"; } - public static void apply(WireBuffer buffer) { + public static void apply(@NonNull WireBuffer buffer) { buffer.start(OP_CODE); } - public static void read(WireBuffer buffer, List operations) { + public static void read(WireBuffer buffer, @NonNull List operations) { operations.add(new ClickModifierOperation()); } - public static void documentation(DocumentationBuilder doc) { + public static void documentation(@NonNull DocumentationBuilder doc) { doc.operation("Layout Operations", OP_CODE, name()) .description( "Click modifier. This operation contains" 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 96dffca2042fabb4e4b6ec09e7713dfdfe8c127c..f4f4ee2a3416fc9d3c585622da0699c3220010ec 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 @@ -15,6 +15,9 @@ */ 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; import com.android.internal.widget.remotecompose.core.PaintContext; @@ -31,7 +34,6 @@ import com.android.internal.widget.remotecompose.core.operations.layout.animatio import com.android.internal.widget.remotecompose.core.operations.layout.measure.ComponentMeasure; import com.android.internal.widget.remotecompose.core.operations.layout.measure.Measurable; import com.android.internal.widget.remotecompose.core.operations.layout.measure.MeasurePass; -import com.android.internal.widget.remotecompose.core.operations.layout.modifiers.ComponentModifiers; import com.android.internal.widget.remotecompose.core.operations.paint.PaintBundle; import com.android.internal.widget.remotecompose.core.operations.utilities.StringSerializer; @@ -52,16 +54,23 @@ public class Component extends PaintOperation implements Measurable, Serializabl protected int mAnimationId = -1; public Visibility mVisibility = Visibility.VISIBLE; public Visibility mScheduledVisibility = Visibility.VISIBLE; - public ArrayList mList = new ArrayList<>(); + @NonNull public ArrayList mList = new ArrayList<>(); public PaintOperation mPreTranslate; public boolean mNeedsMeasure = true; public boolean mNeedsRepaint = false; - public AnimateMeasure mAnimateMeasure; - public AnimationSpec mAnimationSpec = new AnimationSpec(); + @Nullable public AnimateMeasure mAnimateMeasure; + @NonNull public AnimationSpec mAnimationSpec = new AnimationSpec(); public boolean mFirstLayout = true; - PaintBundle mPaint = new PaintBundle(); - protected HashSet mComponentValues = new HashSet<>(); + @NonNull PaintBundle mPaint = new PaintBundle(); + @NonNull protected HashSet mComponentValues = new HashSet<>(); + + protected float mZIndex = 0f; + public float getZIndex() { + return mZIndex; + } + + @NonNull public ArrayList getList() { return mList; } @@ -115,7 +124,7 @@ public class Component extends PaintOperation implements Measurable, Serializabl * * @param context the current context */ - private void updateComponentValues(RemoteContext context) { + private void updateComponentValues(@NonNull RemoteContext context) { if (DEBUG) { System.out.println( "UPDATE COMPONENT VALUES (" @@ -172,7 +181,7 @@ public class Component extends PaintOperation implements Measurable, Serializabl this(parent, componentId, -1, x, y, width, height); } - public Component(Component component) { + public Component(@NonNull Component component) { this( component.mParent, component.mComponentId, @@ -212,7 +221,10 @@ public class Component extends PaintOperation implements Measurable, Serializabl * * @param context the current context */ - public void updateVariables(RemoteContext context) { + public void updateVariables(@NonNull RemoteContext context) { + Component prev = context.lastComponent; + context.lastComponent = this; + if (!mComponentValues.isEmpty()) { updateComponentValues(context); } @@ -224,6 +236,7 @@ public class Component extends PaintOperation implements Measurable, Serializabl o.apply(context); } } + context.lastComponent = prev; } public void addComponentValue(ComponentValue v) { @@ -283,14 +296,14 @@ public class Component extends PaintOperation implements Measurable, Serializabl float maxWidth, float minHeight, float maxHeight, - MeasurePass measure) { + @NonNull MeasurePass measure) { ComponentMeasure m = measure.get(this); m.setW(mWidth); m.setH(mHeight); } @Override - public void layout(RemoteContext context, MeasurePass measure) { + public void layout(@NonNull RemoteContext context, @NonNull MeasurePass measure) { ComponentMeasure m = measure.get(this); if (!mFirstLayout && context.isAnimationEnabled() @@ -332,7 +345,7 @@ public class Component extends PaintOperation implements Measurable, Serializabl mFirstLayout = false; } - public float[] locationInWindow = new float[2]; + @NonNull public float[] locationInWindow = new float[2]; public boolean contains(float x, float y) { locationInWindow[0] = 0f; @@ -353,13 +366,57 @@ public class Component extends PaintOperation implements Measurable, Serializabl if (op instanceof Component) { ((Component) op).onClick(context, document, x, y); } - if (op instanceof ComponentModifiers) { - ((ComponentModifiers) op).onClick(context, document, this, x, y); + if (op instanceof ClickHandler) { + ((ClickHandler) op).onClick(context, document, this, x, y); + } + } + } + + public void onTouchDown(RemoteContext context, CoreDocument document, float x, float y) { + if (!contains(x, y)) { + return; + } + for (Operation op : mList) { + if (op instanceof Component) { + ((Component) op).onTouchDown(context, document, x, y); + } + if (op instanceof TouchHandler) { + ((TouchHandler) op).onTouchDown(context, document, this, x, y); + } + } + } + + public void onTouchUp( + RemoteContext context, CoreDocument document, float x, float y, boolean force) { + if (!force && !contains(x, y)) { + return; + } + for (Operation op : mList) { + if (op instanceof Component) { + ((Component) op).onTouchUp(context, document, x, y, force); + } + if (op instanceof TouchHandler) { + ((TouchHandler) op).onTouchUp(context, document, this, x, y); + } + } + } + + public void onTouchCancel( + RemoteContext context, CoreDocument document, float x, float y, boolean force) { + if (!force && !contains(x, y)) { + return; + } + for (Operation op : mList) { + if (op instanceof Component) { + ((Component) op).onTouchCancel(context, document, x, y, force); + } + if (op instanceof TouchHandler) { + ((TouchHandler) op).onTouchCancel(context, document, this, x, y); } } } - public void getLocationInWindow(float[] value) { + public void getLocationInWindow(@NonNull float[] value) { value[0] += mX; value[1] += mY; if (mParent != null) { @@ -372,6 +429,7 @@ public class Component extends PaintOperation implements Measurable, Serializabl } } + @NonNull @Override public String toString() { return "COMPONENT(<" @@ -393,14 +451,14 @@ public class Component extends PaintOperation implements Measurable, Serializabl + ") "; } + @NonNull protected String getSerializedName() { return "COMPONENT"; } @Override - public void serializeToString(int indent, StringSerializer serializer) { - serializer.append( - indent, + public void serializeToString(int indent, @NonNull StringSerializer serializer) { + String content = getSerializedName() + " [" + mComponentId @@ -416,9 +474,9 @@ public class Component extends PaintOperation implements Measurable, Serializabl + ", " + mHeight + "] " - + mVisibility - // + " [" + mNeedsMeasure + ", " + mNeedsRepaint + "]" - ); + + mVisibility; + // + " [" + mNeedsMeasure + ", " + mNeedsRepaint + "]" + serializer.append(indent, content); } @Override @@ -427,6 +485,7 @@ public class Component extends PaintOperation implements Measurable, Serializabl } /** Returns the top-level RootLayoutComponent */ + @NonNull public RootLayoutComponent getRoot() throws Exception { if (this instanceof RootLayoutComponent) { return (RootLayoutComponent) this; @@ -441,6 +500,7 @@ public class Component extends PaintOperation implements Measurable, Serializabl return (RootLayoutComponent) p; } + @NonNull @Override public String deepToString(String indent) { StringBuilder builder = new StringBuilder(); @@ -477,6 +537,7 @@ public class Component extends PaintOperation implements Measurable, Serializabl } } + @NonNull public String content() { StringBuilder builder = new StringBuilder(); for (Operation op : mList) { @@ -487,6 +548,7 @@ public class Component extends PaintOperation implements Measurable, Serializabl return builder.toString(); } + @NonNull public String textContent() { StringBuilder builder = new StringBuilder(); for (Operation ignored : mList) { @@ -499,7 +561,7 @@ public class Component extends PaintOperation implements Measurable, Serializabl return builder.toString(); } - public void debugBox(Component component, PaintContext context) { + public void debugBox(@NonNull Component component, @NonNull PaintContext context) { float width = component.mWidth; float height = component.mHeight; @@ -536,13 +598,15 @@ public class Component extends PaintOperation implements Measurable, Serializabl return 0f; } - public void paintingComponent(PaintContext context) { + public void paintingComponent(@NonNull PaintContext context) { if (mPreTranslate != null) { mPreTranslate.paint(context); } + Component prev = context.getContext().lastComponent; + context.getContext().lastComponent = this; context.save(); context.translate(mX, mY); - if (context.isDebug()) { + if (context.isVisualDebug()) { debugBox(this, context); } for (Operation op : mList) { @@ -554,9 +618,10 @@ public class Component extends PaintOperation implements Measurable, Serializabl } } context.restore(); + context.getContext().lastComponent = prev; } - public boolean applyAnimationAsNeeded(PaintContext context) { + public boolean applyAnimationAsNeeded(@NonNull PaintContext context) { if (context.isAnimationEnabled() && mAnimateMeasure != null) { mAnimateMeasure.apply(context); needsRepaint(); @@ -566,8 +631,8 @@ public class Component extends PaintOperation implements Measurable, Serializabl } @Override - public void paint(PaintContext context) { - if (context.isDebug()) { + public void paint(@NonNull PaintContext context) { + if (context.isVisualDebug()) { context.save(); context.translate(mX, mY); context.savePaint(); @@ -594,7 +659,7 @@ public class Component extends PaintOperation implements Measurable, Serializabl paintingComponent(context); } - public void getComponents(ArrayList components) { + public void getComponents(@NonNull ArrayList components) { for (Operation op : mList) { if (op instanceof Component) { components.add((Component) op); @@ -602,7 +667,7 @@ public class Component extends PaintOperation implements Measurable, Serializabl } } - public void getData(ArrayList data) { + public void getData(@NonNull ArrayList data) { for (Operation op : mList) { if (op instanceof TextData) { data.add((TextData) op); @@ -631,6 +696,7 @@ public class Component extends PaintOperation implements Measurable, Serializabl return mNeedsRepaint; } + @Nullable public Component getComponent(int cid) { if (mComponentId == cid || mAnimationId == cid) { return this; 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 c83ee487a8ea00a022d5736ddb79a1fcb8510741..f370e20677e87a88e5cd523cdeba72b4d131dc4f 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 @@ -15,6 +15,9 @@ */ 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; import com.android.internal.widget.remotecompose.core.RemoteContext; @@ -26,10 +29,11 @@ import java.util.List; public class ComponentEnd implements Operation { @Override - public void write(WireBuffer buffer) { + public void write(@NonNull WireBuffer buffer) { apply(buffer); } + @NonNull @Override public String toString() { return "COMPONENT_END"; @@ -40,11 +44,13 @@ public class ComponentEnd implements Operation { // nothing } + @NonNull @Override - public String deepToString(String indent) { + public String deepToString(@Nullable String indent) { return (indent != null ? indent : "") + toString(); } + @NonNull public static String name() { return "ComponentEnd"; } @@ -53,7 +59,7 @@ public class ComponentEnd implements Operation { return Operations.COMPONENT_END; } - public static void apply(WireBuffer buffer) { + public static void apply(@NonNull WireBuffer buffer) { buffer.start(Operations.COMPONENT_END); } @@ -61,11 +67,11 @@ public class ComponentEnd implements Operation { return 1 + 4 + 4 + 4; } - public static void read(WireBuffer buffer, List operations) { + public static void read(WireBuffer buffer, @NonNull List operations) { operations.add(new ComponentEnd()); } - public static void documentation(DocumentationBuilder doc) { + public static void documentation(@NonNull DocumentationBuilder doc) { doc.operation("Layout Operations", id(), name()) .description( "End tag for components / layouts. This operation marks the end" 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 72cc9b6d26134e29a155a86c5fb852c8da10a337..f250d9ac4a0193691eb5931bc6541333b451be30 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 @@ -18,6 +18,9 @@ package com.android.internal.widget.remotecompose.core.operations.layout; 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 android.annotation.Nullable; + import com.android.internal.widget.remotecompose.core.Operation; import com.android.internal.widget.remotecompose.core.Operations; import com.android.internal.widget.remotecompose.core.RemoteContext; @@ -69,10 +72,11 @@ public class ComponentStart implements ComponentStartOperation { } @Override - public void write(WireBuffer buffer) { + public void write(@NonNull WireBuffer buffer) { apply(buffer, mType, mComponentId, mWidth, mHeight); } + @NonNull @Override public String toString() { return "COMPONENT_START (type " @@ -90,8 +94,9 @@ public class ComponentStart implements ComponentStartOperation { + ")"; } + @NonNull @Override - public String deepToString(String indent) { + public String deepToString(@Nullable String indent) { return (indent != null ? indent : "") + toString(); } @@ -119,6 +124,7 @@ public class ComponentStart implements ComponentStartOperation { public static final int LAYOUT_ROW = 15; public static final int LAYOUT_COLUMN = 16; + @NonNull public static String typeDescription(int type) { switch (type) { case DEFAULT: @@ -152,6 +158,7 @@ public class ComponentStart implements ComponentStartOperation { } } + @NonNull public static String name() { return "ComponentStart"; } @@ -161,7 +168,7 @@ public class ComponentStart implements ComponentStartOperation { } public static void apply( - WireBuffer buffer, int type, int componentId, float width, float height) { + @NonNull WireBuffer buffer, int type, int componentId, float width, float height) { buffer.start(Operations.COMPONENT_START); buffer.writeInt(type); buffer.writeInt(componentId); @@ -173,7 +180,7 @@ public class ComponentStart implements ComponentStartOperation { return 1 + 4 + 4 + 4; } - public static void read(WireBuffer buffer, List operations) { + public static void read(@NonNull WireBuffer buffer, @NonNull List operations) { int type = buffer.readInt(); int componentId = buffer.readInt(); float width = buffer.readFloat(); @@ -181,7 +188,7 @@ public class ComponentStart implements ComponentStartOperation { operations.add(new ComponentStart(type, componentId, width, height)); } - public static void documentation(DocumentationBuilder doc) { + public static void documentation(@NonNull DocumentationBuilder doc) { doc.operation("Layout Operations", id(), name()) .description( "Basic component encapsulating draw commands." + "This is not resizable.") 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 314650fcd59742f171c2e882643f612f1913b944..bb4311996df013a6886322883c420c174f70e905 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,7 +15,6 @@ */ package com.android.internal.widget.remotecompose.core.operations.layout; -import com.android.internal.widget.remotecompose.core.CoreDocument; import com.android.internal.widget.remotecompose.core.RemoteContext; /** @@ -24,7 +23,4 @@ import com.android.internal.widget.remotecompose.core.RemoteContext; */ public interface DecoratorComponent { void layout(RemoteContext context, float width, float height); - - void onClick( - RemoteContext context, CoreDocument document, Component component, float x, float y); } 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 8172502d092f172fa80e9e53a20f7269418904fc..e0923dfb48fb33cab80b576f8f2f363bdd59ed5d 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 @@ -15,6 +15,9 @@ */ 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.PaintContext; import com.android.internal.widget.remotecompose.core.operations.BitmapData; @@ -25,18 +28,22 @@ import com.android.internal.widget.remotecompose.core.operations.TextData; 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; +import com.android.internal.widget.remotecompose.core.operations.layout.modifiers.GraphicsLayerModifierOperation; import com.android.internal.widget.remotecompose.core.operations.layout.modifiers.HeightModifierOperation; import com.android.internal.widget.remotecompose.core.operations.layout.modifiers.ModifierOperation; import com.android.internal.widget.remotecompose.core.operations.layout.modifiers.PaddingModifierOperation; import com.android.internal.widget.remotecompose.core.operations.layout.modifiers.WidthModifierOperation; +import com.android.internal.widget.remotecompose.core.operations.layout.modifiers.ZIndexModifierOperation; import java.util.ArrayList; /** Component with modifiers and children */ public class LayoutComponent extends Component { - protected WidthModifierOperation mWidthModifier = null; - protected HeightModifierOperation mHeightModifier = null; + @Nullable protected WidthModifierOperation mWidthModifier = null; + @Nullable protected HeightModifierOperation mHeightModifier = null; + @Nullable protected ZIndexModifierOperation mZIndexModifier = null; + @Nullable protected GraphicsLayerModifierOperation mGraphicsLayerModifier = null; // Margins protected float mMarginLeft = 0f; @@ -49,8 +56,10 @@ public class LayoutComponent extends Component { protected float mPaddingTop = 0f; protected float mPaddingBottom = 0f; - protected ComponentModifiers mComponentModifiers = new ComponentModifiers(); - protected ArrayList mChildrenComponents = new ArrayList<>(); + @NonNull protected ComponentModifiers mComponentModifiers = new ComponentModifiers(); + @NonNull protected ArrayList mChildrenComponents = new ArrayList<>(); + + protected boolean mChildrenHaveZIndex = false; public LayoutComponent( Component parent, @@ -95,15 +104,25 @@ public class LayoutComponent extends Component { return mPaddingBottom; } + @Nullable public WidthModifierOperation getWidthModifier() { return mWidthModifier; } + @Nullable public HeightModifierOperation getHeightModifier() { return mHeightModifier; } - protected LayoutComponentContent mContent = null; + @Override + public float getZIndex() { + if (mZIndexModifier != null) { + return mZIndexModifier.getValue(); + } + return mZIndex; + } + + @Nullable protected LayoutComponentContent mContent = null; // Should be removed after ImageLayout is in private static final boolean USE_IMAGE_TEMP_FIX = true; @@ -164,6 +183,9 @@ public class LayoutComponent extends Component { for (Component c : mChildrenComponents) { c.mParent = this; mList.add(c); + if (c instanceof LayoutComponent && ((LayoutComponent) c).mZIndexModifier != null) { + mChildrenHaveZIndex = true; + } } mX = 0f; @@ -209,6 +231,12 @@ public class LayoutComponent extends Component { mHeightModifier = (HeightModifierOperation) op; applyVerticalMargin = false; } + if (op instanceof ZIndexModifierOperation) { + mZIndexModifier = (ZIndexModifierOperation) op; + } + if (op instanceof GraphicsLayerModifierOperation) { + mGraphicsLayerModifier = (GraphicsLayerModifierOperation) op; + } } if (mWidthModifier == null) { mWidthModifier = new WidthModifierOperation(DimensionModifierOperation.Type.WRAP); @@ -220,24 +248,64 @@ public class LayoutComponent extends Component { setHeight(computeModifierDefinedHeight()); } + @NonNull @Override public String toString() { return "UNKNOWN LAYOUT_COMPONENT"; } @Override - public void paintingComponent(PaintContext context) { + public void paintingComponent(@NonNull PaintContext context) { + Component prev = context.getContext().lastComponent; + context.getContext().lastComponent = this; context.save(); context.translate(mX, mY); + if (mGraphicsLayerModifier != null) { + context.startGraphicsLayer((int) getWidth(), (int) getHeight()); + float scaleX = mGraphicsLayerModifier.getScaleX(); + float scaleY = mGraphicsLayerModifier.getScaleY(); + float rotationX = mGraphicsLayerModifier.getRotationX(); + float rotationY = mGraphicsLayerModifier.getRotationY(); + float rotationZ = mGraphicsLayerModifier.getRotationZ(); + float shadowElevation = mGraphicsLayerModifier.getShadowElevation(); + float transformOriginX = mGraphicsLayerModifier.getTransformOriginX(); + float transformOriginY = mGraphicsLayerModifier.getTransformOriginY(); + float alpha = mGraphicsLayerModifier.getAlpha(); + int renderEffectId = mGraphicsLayerModifier.getRenderEffectId(); + context.setGraphicsLayer( + scaleX, + scaleY, + rotationX, + rotationY, + rotationZ, + shadowElevation, + transformOriginX, + transformOriginY, + alpha, + renderEffectId); + } mComponentModifiers.paint(context); float tx = mPaddingLeft; float ty = mPaddingTop; context.translate(tx, ty); - for (Component child : mChildrenComponents) { - child.paint(context); + if (mChildrenHaveZIndex) { + // TODO -- should only sort when something has changed + ArrayList sorted = new ArrayList(mChildrenComponents); + sorted.sort((a, b) -> (int) (a.getZIndex() - b.getZIndex())); + for (Component child : sorted) { + child.paint(context); + } + } else { + for (Component child : mChildrenComponents) { + child.paint(context); + } + } + if (mGraphicsLayerModifier != null) { + context.endGraphicsLayer(); } context.translate(-tx, -ty); context.restore(); + context.getContext().lastComponent = prev; } /** Traverse the modifiers to compute indicated dimension */ @@ -248,7 +316,8 @@ public class LayoutComponent extends Component { for (Operation c : mComponentModifiers.getList()) { if (c instanceof WidthModifierOperation) { WidthModifierOperation o = (WidthModifierOperation) c; - if (o.getType() == DimensionModifierOperation.Type.EXACT) { + if (o.getType() == DimensionModifierOperation.Type.EXACT + || o.getType() == DimensionModifierOperation.Type.EXACT_DP) { w = o.getValue(); } break; @@ -291,7 +360,8 @@ public class LayoutComponent extends Component { for (Operation c : mComponentModifiers.getList()) { if (c instanceof HeightModifierOperation) { HeightModifierOperation o = (HeightModifierOperation) c; - if (o.getType() == DimensionModifierOperation.Type.EXACT) { + if (o.getType() == DimensionModifierOperation.Type.EXACT + || o.getType() == DimensionModifierOperation.Type.EXACT_DP) { h = o.getValue(); } break; @@ -326,6 +396,7 @@ public class LayoutComponent extends Component { return t + b; } + @NonNull public ArrayList getChildrenComponents() { return mChildrenComponents; } diff --git a/core/java/com/android/internal/widget/remotecompose/core/operations/layout/LayoutComponentContent.java b/core/java/com/android/internal/widget/remotecompose/core/operations/layout/LayoutComponentContent.java index 66fd053c4b5e7b37dbbdd0f472dc4a31a53e8f0b..0a085b43401c69f99fde7caf6da97d5e1eb24e2d 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 @@ -17,6 +17,8 @@ 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 com.android.internal.widget.remotecompose.core.Operation; import com.android.internal.widget.remotecompose.core.Operations; import com.android.internal.widget.remotecompose.core.WireBuffer; @@ -38,6 +40,7 @@ public class LayoutComponentContent extends Component implements ComponentStartO super(parent, componentId, animationId, x, y, width, height); } + @NonNull public static String name() { return "LayoutContent"; } @@ -46,22 +49,23 @@ public class LayoutComponentContent extends Component implements ComponentStartO return Operations.LAYOUT_CONTENT; } + @NonNull @Override protected String getSerializedName() { return "CONTENT"; } - public static void apply(WireBuffer buffer, int componentId) { + public static void apply(@NonNull WireBuffer buffer, int componentId) { buffer.start(Operations.LAYOUT_CONTENT); buffer.writeInt(componentId); } - public static void read(WireBuffer buffer, List operations) { + public static void read(@NonNull WireBuffer buffer, @NonNull List operations) { int componentId = buffer.readInt(); operations.add(new LayoutComponentContent(componentId, 0, 0, 0, 0, null, -1)); } - public static void documentation(DocumentationBuilder doc) { + public static void documentation(@NonNull DocumentationBuilder doc) { doc.operation("Layout Operations", id(), name()) .field(INT, "COMPONENT_ID", "unique id for this component") .description( @@ -71,7 +75,7 @@ public class LayoutComponentContent extends Component implements ComponentStartO } @Override - public void write(WireBuffer buffer) { + public void write(@NonNull WireBuffer buffer) { apply(buffer, mComponentId); } } 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 new file mode 100644 index 0000000000000000000000000000000000000000..c4df075bb9e8ffd59c9f902af0de201879a812e8 --- /dev/null +++ b/core/java/com/android/internal/widget/remotecompose/core/operations/layout/ListActionsOperation.java @@ -0,0 +1,109 @@ +/* + * 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; + +import com.android.internal.widget.remotecompose.core.CoreDocument; +import com.android.internal.widget.remotecompose.core.Operation; +import com.android.internal.widget.remotecompose.core.PaintContext; +import com.android.internal.widget.remotecompose.core.PaintOperation; +import com.android.internal.widget.remotecompose.core.RemoteContext; +import com.android.internal.widget.remotecompose.core.operations.TextData; +import com.android.internal.widget.remotecompose.core.operations.layout.modifiers.ModifierOperation; +import com.android.internal.widget.remotecompose.core.operations.utilities.StringSerializer; + +import java.util.ArrayList; + +public abstract class ListActionsOperation extends PaintOperation + implements ModifierOperation, DecoratorComponent { + + String mOperationName; + float mWidth = 0; + float mHeight = 0; + + private final float[] mLocationInWindow = new float[2]; + + public ListActionsOperation(String operationName) { + mOperationName = operationName; + } + + public ArrayList mList = new ArrayList<>(); + + public ArrayList getList() { + return mList; + } + + @Override + public String toString() { + return mOperationName; + } + + @Override + public void apply(RemoteContext context) { + for (Operation op : mList) { + if (op instanceof TextData) { + op.apply(context); + } + } + } + + @Override + public String deepToString(String indent) { + return (indent != null ? indent : "") + toString(); + } + + @Override + public void paint(PaintContext context) {} + + @Override + public void layout(RemoteContext context, float width, float height) { + mWidth = width; + mHeight = height; + } + + @Override + public void serializeToString(int indent, StringSerializer serializer) { + serializer.append(indent, mOperationName); + for (Operation o : mList) { + if (o instanceof ActionOperation) { + ((ActionOperation) o).serializeToString(indent + 1, serializer); + } + } + } + + public boolean applyActions( + RemoteContext context, + CoreDocument document, + Component component, + float x, + float y, + boolean force) { + if (!force && !component.isVisible()) { + return false; + } + if (!force && !component.contains(x, y)) { + return false; + } + mLocationInWindow[0] = 0f; + mLocationInWindow[1] = 0f; + component.getLocationInWindow(mLocationInWindow); + for (Operation o : mList) { + if (o instanceof ActionOperation) { + ((ActionOperation) o).runAction(context, document, component, x, y); + } + } + return true; + } +} 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 3086d6aaa7771789e0175b9c3afce9dc6300a2ca..c90077b887823cf4905d5df2d6c57b858c32312f 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 @@ -15,6 +15,9 @@ */ 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; import com.android.internal.widget.remotecompose.core.RemoteContext; @@ -26,10 +29,11 @@ import java.util.List; public class LoopEnd implements Operation { @Override - public void write(WireBuffer buffer) { + public void write(@NonNull WireBuffer buffer) { apply(buffer); } + @NonNull @Override public String toString() { return "LOOP_END"; @@ -40,11 +44,13 @@ public class LoopEnd implements Operation { // nothing } + @NonNull @Override - public String deepToString(String indent) { + public String deepToString(@Nullable String indent) { return (indent != null ? indent : "") + toString(); } + @NonNull public static String name() { return "LoopEnd"; } @@ -53,15 +59,15 @@ public class LoopEnd implements Operation { return Operations.LOOP_END; } - public static void apply(WireBuffer buffer) { + public static void apply(@NonNull WireBuffer buffer) { buffer.start(id()); } - public static void read(WireBuffer buffer, List operations) { + public static void read(WireBuffer buffer, @NonNull List operations) { operations.add(new LoopEnd()); } - public static void documentation(DocumentationBuilder doc) { + public static void documentation(@NonNull DocumentationBuilder doc) { doc.operation("Operations", id(), name()).description("End tag for loops"); } } diff --git a/core/java/com/android/internal/widget/remotecompose/core/operations/layout/LoopOperation.java b/core/java/com/android/internal/widget/remotecompose/core/operations/layout/LoopOperation.java index 691000810c207e9bd7f496601f1eac10e13c9a00..eeaeafd284c03bea8c6012d35cfc24795299339d 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 @@ -15,6 +15,9 @@ */ 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; import com.android.internal.widget.remotecompose.core.PaintContext; @@ -30,7 +33,7 @@ import java.util.List; public class LoopOperation extends PaintOperation { private static final int OP_CODE = Operations.LOOP_START; - public ArrayList mList = new ArrayList<>(); + @NonNull public ArrayList mList = new ArrayList<>(); int mIndexVariableId; float mUntil = 12; @@ -49,27 +52,30 @@ public class LoopOperation extends PaintOperation { mIndexVariableId = indexId; } + @NonNull public ArrayList getList() { return mList; } @Override - public void write(WireBuffer buffer) { + public void write(@NonNull WireBuffer buffer) { apply(buffer, mUntil, mFrom, mStep, mIndexVariableId); } + @NonNull @Override public String toString() { return "LoopOperation"; } + @NonNull @Override - public String deepToString(String indent) { + public String deepToString(@Nullable String indent) { return (indent != null ? indent : "") + toString(); } @Override - public void paint(PaintContext context) { + public void paint(@NonNull PaintContext context) { if (mIndexVariableId == 0) { for (float i = mFrom; i < mUntil; i += mStep) { for (Operation op : mList) { @@ -89,11 +95,13 @@ public class LoopOperation extends PaintOperation { } } + @NonNull public static String name() { return "Loop"; } - public static void apply(WireBuffer buffer, float count, float from, float step, int indexId) { + public static void apply( + @NonNull WireBuffer buffer, float count, float from, float step, int indexId) { buffer.start(OP_CODE); buffer.writeFloat(count); buffer.writeFloat(from); @@ -101,7 +109,7 @@ public class LoopOperation extends PaintOperation { buffer.writeInt(indexId); } - public static void read(WireBuffer buffer, List operations) { + public static void read(@NonNull WireBuffer buffer, @NonNull List operations) { float count = buffer.readFloat(); float from = buffer.readFloat(); float step = buffer.readFloat(); @@ -109,7 +117,7 @@ public class LoopOperation extends PaintOperation { operations.add(new LoopOperation(count, from, step, indexId)); } - public static void documentation(DocumentationBuilder doc) { + public static void documentation(@NonNull DocumentationBuilder doc) { doc.operation("Operations", OP_CODE, name()) .description("Loop. This operation execute" + " a list of action in a loop"); } diff --git a/core/java/com/android/internal/widget/remotecompose/core/operations/layout/ClickModifierEnd.java b/core/java/com/android/internal/widget/remotecompose/core/operations/layout/OperationsListEnd.java similarity index 68% rename from core/java/com/android/internal/widget/remotecompose/core/operations/layout/ClickModifierEnd.java rename to core/java/com/android/internal/widget/remotecompose/core/operations/layout/OperationsListEnd.java index fe726ac78791d2763f7e833346b49a079f1ffcff..bd8d1f0ba9dd2cd609952825f4b7d6b91247c0e0 100644 --- a/core/java/com/android/internal/widget/remotecompose/core/operations/layout/ClickModifierEnd.java +++ b/core/java/com/android/internal/widget/remotecompose/core/operations/layout/OperationsListEnd.java @@ -15,6 +15,9 @@ */ 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; import com.android.internal.widget.remotecompose.core.RemoteContext; @@ -23,16 +26,17 @@ import com.android.internal.widget.remotecompose.core.documentation.Documentatio import java.util.List; -public class ClickModifierEnd implements Operation { +public class OperationsListEnd implements Operation { @Override - public void write(WireBuffer buffer) { + public void write(@NonNull WireBuffer buffer) { apply(buffer); } + @NonNull @Override public String toString() { - return "CLICK_END"; + return "LIST_END"; } @Override @@ -40,31 +44,31 @@ public class ClickModifierEnd implements Operation { // nothing } + @NonNull @Override - public String deepToString(String indent) { + public String deepToString(@Nullable String indent) { return (indent != null ? indent : "") + toString(); } + @NonNull public static String name() { - return "ClickModifierEnd"; + return "ListEnd"; } public static int id() { - return Operations.MODIFIER_CLICK_END; + return Operations.OPERATIONS_LIST_END; } - public static void apply(WireBuffer buffer) { + public static void apply(@NonNull WireBuffer buffer) { buffer.start(id()); } - public static void read(WireBuffer buffer, List operations) { - operations.add(new ClickModifierEnd()); + public static void read(WireBuffer buffer, @NonNull List operations) { + operations.add(new OperationsListEnd()); } - public static void documentation(DocumentationBuilder doc) { + public static void documentation(@NonNull DocumentationBuilder doc) { doc.operation("Layout Operations", id(), name()) - .description( - "End tag for click modifiers. This operation marks the end" - + "of a click modifier"); + .description("End tag for list of operations."); } } diff --git a/core/java/com/android/internal/widget/remotecompose/core/operations/layout/RootLayoutComponent.java b/core/java/com/android/internal/widget/remotecompose/core/operations/layout/RootLayoutComponent.java index 680bb0b064d12208b2367fb635416658e0cf2ca2..524ae59e70ec3e94272bd19fef39d68678d810ca 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 @@ -17,6 +17,8 @@ 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 com.android.internal.widget.remotecompose.core.Operation; import com.android.internal.widget.remotecompose.core.Operations; import com.android.internal.widget.remotecompose.core.PaintContext; @@ -34,7 +36,8 @@ import java.util.List; /** Represents the root layout component. Entry point to the component tree layout/paint. */ public class RootLayoutComponent extends Component implements ComponentStartOperation { - int mCurrentId = -1; + private int mCurrentId = -1; + private boolean mHasTouchListeners = false; public RootLayoutComponent( int componentId, @@ -52,6 +55,7 @@ public class RootLayoutComponent extends Component implements ComponentStartOper super(parent, componentId, -1, x, y, width, height); } + @NonNull @Override public String toString() { return "ROOT " @@ -69,7 +73,7 @@ public class RootLayoutComponent extends Component implements ComponentStartOper } @Override - public void serializeToString(int indent, StringSerializer serializer) { + public void serializeToString(int indent, @NonNull StringSerializer serializer) { serializer.append( indent, "ROOT [" @@ -88,6 +92,15 @@ public class RootLayoutComponent extends Component implements ComponentStartOper + mVisibility); } + /** + * Set the flag to traverse the tree when touch events happen + * + * @param value true to indicate that the tree has touch listeners + */ + public void setHasTouchListeners(boolean value) { + mHasTouchListeners = value; + } + /** * Traverse the hierarchy and assign generated ids to component without ids. Most components * would already have ids assigned during the document creation, but this allow us to take care @@ -100,7 +113,7 @@ public class RootLayoutComponent extends Component implements ComponentStartOper assignId(this); } - private void assignId(Component component) { + private void assignId(@NonNull Component component) { if (component.mComponentId == -1) { mCurrentId--; component.mComponentId = mCurrentId; @@ -113,7 +126,7 @@ public class RootLayoutComponent extends Component implements ComponentStartOper } /** This will measure then layout the tree of components */ - public void layout(RemoteContext context) { + public void layout(@NonNull RemoteContext context) { if (!mNeedsMeasure) { return; } @@ -134,7 +147,7 @@ public class RootLayoutComponent extends Component implements ComponentStartOper } @Override - public void paint(PaintContext context) { + public void paint(@NonNull PaintContext context) { mNeedsRepaint = false; context.getContext().lastComponent = this; context.save(); @@ -152,13 +165,15 @@ public class RootLayoutComponent extends Component implements ComponentStartOper context.restore(); } + @NonNull public String displayHierarchy() { StringSerializer serializer = new StringSerializer(); displayHierarchy(this, 0, serializer); return serializer.toString(); } - public void displayHierarchy(Component component, int indent, StringSerializer serializer) { + public void displayHierarchy( + @NonNull Component component, int indent, @NonNull StringSerializer serializer) { component.serializeToString(indent, serializer); for (Operation c : component.mList) { if (c instanceof ComponentModifiers) { @@ -171,6 +186,7 @@ public class RootLayoutComponent extends Component implements ComponentStartOper } } + @NonNull public static String name() { return "RootLayout"; } @@ -179,17 +195,17 @@ public class RootLayoutComponent extends Component implements ComponentStartOper return Operations.LAYOUT_ROOT; } - public static void apply(WireBuffer buffer, int componentId) { + public static void apply(@NonNull WireBuffer buffer, int componentId) { buffer.start(Operations.LAYOUT_ROOT); buffer.writeInt(componentId); } - public static void read(WireBuffer buffer, List operations) { + public static void read(@NonNull WireBuffer buffer, @NonNull List operations) { int componentId = buffer.readInt(); operations.add(new RootLayoutComponent(componentId, 0, 0, 0, 0, null, -1)); } - public static void documentation(DocumentationBuilder doc) { + public static void documentation(@NonNull DocumentationBuilder doc) { doc.operation("Layout Operations", id(), name()) .field(INT, "COMPONENT_ID", "unique id for this component") .description( @@ -199,7 +215,11 @@ public class RootLayoutComponent extends Component implements ComponentStartOper } @Override - public void write(WireBuffer buffer) { + public void write(@NonNull WireBuffer buffer) { apply(buffer, mComponentId); } + + public boolean hasTouchListeners() { + return mHasTouchListeners; + } } 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 new file mode 100644 index 0000000000000000000000000000000000000000..486efbd6e00f35d75b368235e408bbdf91e9eda9 --- /dev/null +++ b/core/java/com/android/internal/widget/remotecompose/core/operations/layout/TouchCancelModifierOperation.java @@ -0,0 +1,91 @@ +/* + * 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; + +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 java.util.List; + +/** Represents a touch cancel modifier + actions */ +public class TouchCancelModifierOperation extends ListActionsOperation implements TouchHandler { + + private static final int OP_CODE = Operations.MODIFIER_TOUCH_CANCEL; + + public TouchCancelModifierOperation() { + super("TOUCH_CANCEL_MODIFIER"); + } + + @Override + public void write(WireBuffer buffer) { + apply(buffer); + } + + @Override + public String toString() { + return "TouchCancelModifier"; + } + + @Override + public void apply(RemoteContext context) { + RootLayoutComponent root = context.getDocument().getRootLayoutComponent(); + if (root != null) { + root.setHasTouchListeners(true); + } + super.apply(context); + } + + @Override + public void onTouchDown( + RemoteContext context, CoreDocument document, Component component, float x, float y) { + // nothing + } + + @Override + public void onTouchUp( + RemoteContext context, CoreDocument document, Component component, float x, float y) { + // nothing + } + + @Override + public void onTouchCancel( + RemoteContext context, CoreDocument document, Component component, float x, float y) { + applyActions(context, document, component, x, y, true); + } + + public static String name() { + return "TouchCancelModifier"; + } + + public static void apply(WireBuffer buffer) { + buffer.start(OP_CODE); + } + + public static void read(WireBuffer buffer, List operations) { + operations.add(new TouchCancelModifierOperation()); + } + + public static void documentation(DocumentationBuilder doc) { + doc.operation("Modifier Operations", OP_CODE, name()) + .description( + "Touch cancel modifier. This operation contains" + + " a list of action executed on Touch cancel"); + } +} 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 new file mode 100644 index 0000000000000000000000000000000000000000..5d379fe01d618492a3708f8706ae537a7f126fca --- /dev/null +++ b/core/java/com/android/internal/widget/remotecompose/core/operations/layout/TouchDownModifierOperation.java @@ -0,0 +1,93 @@ +/* + * 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; + +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 java.util.List; + +/** Represents a touch down modifier + actions */ +public class TouchDownModifierOperation extends ListActionsOperation implements TouchHandler { + + private static final int OP_CODE = Operations.MODIFIER_TOUCH_DOWN; + + public TouchDownModifierOperation() { + super("TOUCH_DOWN_MODIFIER"); + } + + @Override + public void write(WireBuffer buffer) { + apply(buffer); + } + + @Override + public String toString() { + return "TouchDownModifier"; + } + + @Override + public void apply(RemoteContext context) { + RootLayoutComponent root = context.getDocument().getRootLayoutComponent(); + if (root != null) { + root.setHasTouchListeners(true); + } + super.apply(context); + } + + @Override + public void onTouchDown( + RemoteContext context, CoreDocument document, Component component, float x, float y) { + if (applyActions(context, document, component, x, y, false)) { + document.appliedTouchOperation(component); + } + } + + @Override + public void onTouchUp( + RemoteContext context, CoreDocument document, Component component, float x, float y) { + // nothing + } + + @Override + public void onTouchCancel( + RemoteContext context, CoreDocument document, Component component, float x, float y) { + // nothing + } + + public static String name() { + return "TouchModifier"; + } + + public static void apply(WireBuffer buffer) { + buffer.start(OP_CODE); + } + + public static void read(WireBuffer buffer, List operations) { + operations.add(new TouchDownModifierOperation()); + } + + public static void documentation(DocumentationBuilder doc) { + doc.operation("Modifier Operations", OP_CODE, name()) + .description( + "Touch down modifier. This operation contains" + + " a list of action executed on Touch down"); + } +} 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 new file mode 100644 index 0000000000000000000000000000000000000000..5adfc33b5ef59d2aa3d358c7e322d3f79e8236c8 --- /dev/null +++ b/core/java/com/android/internal/widget/remotecompose/core/operations/layout/TouchHandler.java @@ -0,0 +1,59 @@ +/* + * 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; + +import com.android.internal.widget.remotecompose.core.CoreDocument; +import com.android.internal.widget.remotecompose.core.RemoteContext; + +/** Interface to represent operations that can handle touch events */ +public interface TouchHandler { + + /** + * callback for a touch down 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 onTouchDown( + RemoteContext context, CoreDocument document, Component component, float x, float y); + + /** + * callback for a touch up 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 onTouchUp( + RemoteContext context, CoreDocument document, Component component, float x, float y); + + /** + * callback for a touch cancel 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 onTouchCancel( + RemoteContext context, CoreDocument document, Component component, float x, float y); +} 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 new file mode 100644 index 0000000000000000000000000000000000000000..263cc43d5e74e0be1c7adaf64b6f65f3703b13b3 --- /dev/null +++ b/core/java/com/android/internal/widget/remotecompose/core/operations/layout/TouchUpModifierOperation.java @@ -0,0 +1,91 @@ +/* + * 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; + +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 java.util.List; + +/** Represents a touch up modifier + actions */ +public class TouchUpModifierOperation extends ListActionsOperation implements TouchHandler { + + private static final int OP_CODE = Operations.MODIFIER_TOUCH_UP; + + public TouchUpModifierOperation() { + super("TOUCH_UP_MODIFIER"); + } + + @Override + public void write(WireBuffer buffer) { + apply(buffer); + } + + @Override + public String toString() { + return "TouchUpModifier"; + } + + @Override + public void apply(RemoteContext context) { + RootLayoutComponent root = context.getDocument().getRootLayoutComponent(); + if (root != null) { + root.setHasTouchListeners(true); + } + super.apply(context); + } + + @Override + public void onTouchDown( + RemoteContext context, CoreDocument document, Component component, float x, float y) { + // nothing + } + + @Override + public void onTouchUp( + RemoteContext context, CoreDocument document, Component component, float x, float y) { + applyActions(context, document, component, x, y, true); + } + + @Override + public void onTouchCancel( + RemoteContext context, CoreDocument document, Component component, float x, float y) { + // nothing + } + + public static String name() { + return "TouchUpModifier"; + } + + public static void apply(WireBuffer buffer) { + buffer.start(OP_CODE); + } + + public static void read(WireBuffer buffer, List operations) { + operations.add(new TouchUpModifierOperation()); + } + + public static void documentation(DocumentationBuilder doc) { + doc.operation("Modifier Operations", OP_CODE, name()) + .description( + "Touch up modifier. This operation contains" + + " a list of action executed on Touch up"); + } +} 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 e4505852885929bfe4c69c8a584069cf110a213b..6036b74efad31721ee08892aa19760a19a90294a 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 @@ -15,6 +15,8 @@ */ package com.android.internal.widget.remotecompose.core.operations.layout.animation; +import android.annotation.NonNull; + import com.android.internal.widget.remotecompose.core.Operation; import com.android.internal.widget.remotecompose.core.PaintContext; import com.android.internal.widget.remotecompose.core.operations.layout.Component; @@ -44,18 +46,23 @@ public class AnimateMeasure { float mP = 0f; float mVp = 0f; + + @NonNull FloatAnimation mMotionEasing = new FloatAnimation(mMotionEasingType, mDuration / 1000f, null, 0f, Float.NaN); + + @NonNull FloatAnimation mVisibilityEasing = new FloatAnimation( mVisibilityEasingType, mDurationVisibilityChange / 1000f, null, 0f, Float.NaN); + ParticleAnimation mParticleAnimation; public AnimateMeasure( long startTime, - Component component, + @NonNull Component component, ComponentMeasure original, - ComponentMeasure target, + @NonNull ComponentMeasure target, int duration, int durationVisibilityChange, AnimationSpec.ANIMATION enterAnimation, @@ -94,9 +101,9 @@ public class AnimateMeasure { mVp = mVisibilityEasing.get(visibilityProgress); } - public PaintBundle paint = new PaintBundle(); + @NonNull public PaintBundle paint = new PaintBundle(); - public void apply(PaintContext context) { + public void apply(@NonNull PaintContext context) { update(context.getContext().currentTime); mComponent.setX(getX()); @@ -338,7 +345,7 @@ public class AnimateMeasure { } } - public void updateTarget(ComponentMeasure measure, long currentTime) { + public void updateTarget(@NonNull ComponentMeasure measure, long currentTime) { mOriginal.setX(getX()); mOriginal.setY(getY()); mOriginal.setW(getWidth()); 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 35533cb95190d59e5dc93782aeb4726bdfcda8b7..47abadeb70fa2db72ae5d5ed3ad417f552cf1462 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 @@ -17,6 +17,9 @@ 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; import com.android.internal.widget.remotecompose.core.RemoteContext; @@ -92,6 +95,7 @@ public class AnimationSpec implements Operation { return mExitAnimation; } + @NonNull @Override public String toString() { return "ANIMATION_SPEC (" + mMotionDuration + " ms)"; @@ -109,7 +113,7 @@ public class AnimationSpec implements Operation { } @Override - public void write(WireBuffer buffer) { + public void write(@NonNull WireBuffer buffer) { apply( buffer, mAnimationId, @@ -126,11 +130,13 @@ public class AnimationSpec implements Operation { // nothing here } + @NonNull @Override - public String deepToString(String indent) { + public String deepToString(@Nullable String indent) { return (indent != null ? indent : "") + toString(); } + @NonNull public static String name() { return "AnimationSpec"; } @@ -139,10 +145,11 @@ public class AnimationSpec implements Operation { return Operations.ANIMATION_SPEC; } - public static int animationToInt(ANIMATION animation) { + public static int animationToInt(@NonNull ANIMATION animation) { return animation.ordinal(); } + @NonNull public static ANIMATION intToAnimation(int value) { switch (value) { case 0: @@ -167,14 +174,14 @@ public class AnimationSpec implements Operation { } public static void apply( - WireBuffer buffer, + @NonNull WireBuffer buffer, int animationId, int motionDuration, int motionEasingType, int visibilityDuration, int visibilityEasingType, - ANIMATION enterAnimation, - ANIMATION exitAnimation) { + @NonNull ANIMATION enterAnimation, + @NonNull ANIMATION exitAnimation) { buffer.start(Operations.ANIMATION_SPEC); buffer.writeInt(animationId); buffer.writeInt(motionDuration); @@ -185,7 +192,7 @@ public class AnimationSpec implements Operation { buffer.writeInt(animationToInt(exitAnimation)); } - public static void read(WireBuffer buffer, List operations) { + public static void read(@NonNull WireBuffer buffer, @NonNull List operations) { int animationId = buffer.readInt(); int motionDuration = buffer.readInt(); int motionEasingType = buffer.readInt(); @@ -205,7 +212,7 @@ public class AnimationSpec implements Operation { operations.add(op); } - public static void documentation(DocumentationBuilder doc) { + public static void documentation(@NonNull DocumentationBuilder doc) { doc.operation("Layout Operations", id(), name()) .description("define the animation") .field(INT, "animationId", "") 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 686643fbe1bc7d41f68a1153c9975873e01d84b2..37d20781f4fa4f602750020325bd600f277c7672 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 @@ -15,6 +15,8 @@ */ package com.android.internal.widget.remotecompose.core.operations.layout.animation; +import android.annotation.NonNull; + import com.android.internal.widget.remotecompose.core.PaintContext; import com.android.internal.widget.remotecompose.core.operations.layout.Component; import com.android.internal.widget.remotecompose.core.operations.layout.measure.ComponentMeasure; @@ -24,14 +26,14 @@ import java.util.ArrayList; import java.util.HashMap; public class ParticleAnimation { - HashMap> mAllParticles = new HashMap<>(); + @NonNull HashMap> mAllParticles = new HashMap<>(); - PaintBundle mPaint = new PaintBundle(); + @NonNull PaintBundle mPaint = new PaintBundle(); public void animate( - PaintContext context, - Component component, - ComponentMeasure start, + @NonNull PaintContext context, + @NonNull Component component, + @NonNull ComponentMeasure start, ComponentMeasure end, float progress) { ArrayList particles = mAllParticles.get(component.getComponentId()); 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 047a968785c4a04be82444f206c856b576a0c4c9..f3e550903a6507787d4c12c70b55430667dbc33d 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 @@ -17,6 +17,8 @@ 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 com.android.internal.widget.remotecompose.core.Operation; import com.android.internal.widget.remotecompose.core.Operations; import com.android.internal.widget.remotecompose.core.PaintContext; @@ -75,6 +77,7 @@ public class BoxLayout extends LayoutManager implements ComponentStartOperation verticalPositioning); } + @NonNull @Override public String toString() { return "BOX [" @@ -93,6 +96,7 @@ public class BoxLayout extends LayoutManager implements ComponentStartOperation + mVisibility; } + @NonNull @Override protected String getSerializedName() { return "BOX"; @@ -100,7 +104,11 @@ public class BoxLayout extends LayoutManager implements ComponentStartOperation @Override public void computeWrapSize( - PaintContext context, float maxWidth, float maxHeight, MeasurePass measure, Size size) { + PaintContext context, + float maxWidth, + float maxHeight, + @NonNull MeasurePass measure, + @NonNull Size size) { for (Component c : mChildrenComponents) { c.measure(context, 0f, maxWidth, 0f, maxHeight, measure); ComponentMeasure m = measure.get(c); @@ -119,14 +127,14 @@ public class BoxLayout extends LayoutManager implements ComponentStartOperation float maxWidth, float minHeight, float maxHeight, - MeasurePass measure) { + @NonNull MeasurePass measure) { for (Component child : mChildrenComponents) { child.measure(context, minWidth, maxWidth, minHeight, maxHeight, measure); } } @Override - public void internalLayoutMeasure(PaintContext context, MeasurePass measure) { + public void internalLayoutMeasure(PaintContext context, @NonNull MeasurePass measure) { ComponentMeasure selfMeasure = measure.get(this); float selfWidth = selfMeasure.getW() - mPaddingLeft - mPaddingRight; float selfHeight = selfMeasure.getH() - mPaddingTop - mPaddingBottom; @@ -161,6 +169,7 @@ public class BoxLayout extends LayoutManager implements ComponentStartOperation } } + @NonNull public static String name() { return "BoxLayout"; } @@ -170,7 +179,7 @@ public class BoxLayout extends LayoutManager implements ComponentStartOperation } public static void apply( - WireBuffer buffer, + @NonNull WireBuffer buffer, int componentId, int animationId, int horizontalPositioning, @@ -182,7 +191,7 @@ public class BoxLayout extends LayoutManager implements ComponentStartOperation buffer.writeInt(verticalPositioning); } - public static void read(WireBuffer buffer, List operations) { + public static void read(@NonNull WireBuffer buffer, @NonNull List operations) { int componentId = buffer.readInt(); int animationId = buffer.readInt(); int horizontalPositioning = buffer.readInt(); @@ -196,7 +205,7 @@ public class BoxLayout extends LayoutManager implements ComponentStartOperation verticalPositioning)); } - public static void documentation(DocumentationBuilder doc) { + public static void documentation(@NonNull DocumentationBuilder doc) { doc.operation("Layout Operations", id(), name()) .description( "Box layout implementation.\n\n" @@ -224,7 +233,7 @@ public class BoxLayout extends LayoutManager implements ComponentStartOperation } @Override - public void write(WireBuffer buffer) { + public void write(@NonNull WireBuffer buffer) { apply(buffer, mComponentId, mAnimationId, mHorizontalPositioning, mVerticalPositioning); } } 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 f79976715ab3ed5d544cf32f8a9759a5379bcc8d..12ff969530b3f9dee6f9799922ec04c3ff3381e9 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 @@ -17,6 +17,8 @@ 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 com.android.internal.widget.remotecompose.core.Operation; import com.android.internal.widget.remotecompose.core.Operations; import com.android.internal.widget.remotecompose.core.PaintContext; @@ -44,6 +46,7 @@ public class CanvasLayout extends BoxLayout { this(parent, componentId, animationId, 0, 0, 0, 0); } + @NonNull @Override public String toString() { return "CANVAS [" @@ -62,11 +65,13 @@ public class CanvasLayout extends BoxLayout { + mVisibility; } + @NonNull @Override protected String getSerializedName() { return "CANVAS"; } + @NonNull public static String name() { return "CanvasLayout"; } @@ -75,19 +80,19 @@ public class CanvasLayout extends BoxLayout { return Operations.LAYOUT_CANVAS; } - public static void apply(WireBuffer buffer, int componentId, int animationId) { + public static void apply(@NonNull WireBuffer buffer, int componentId, int animationId) { buffer.start(Operations.LAYOUT_CANVAS); buffer.writeInt(componentId); buffer.writeInt(animationId); } - public static void read(WireBuffer buffer, List operations) { + public static void read(@NonNull WireBuffer buffer, @NonNull List operations) { int componentId = buffer.readInt(); int animationId = buffer.readInt(); operations.add(new CanvasLayout(null, componentId, animationId)); } - public static void documentation(DocumentationBuilder doc) { + public static void documentation(@NonNull DocumentationBuilder doc) { doc.operation("Layout Operations", id(), name()) .description("Canvas implementation. Encapsulate draw operations.\n\n") .field(INT, "COMPONENT_ID", "unique id for this component") @@ -98,7 +103,7 @@ public class CanvasLayout extends BoxLayout { } @Override - public void internalLayoutMeasure(PaintContext context, MeasurePass measure) { + public void internalLayoutMeasure(PaintContext context, @NonNull MeasurePass measure) { ComponentMeasure selfMeasure = measure.get(this); float selfWidth = selfMeasure.getW() - mPaddingLeft - mPaddingRight; float selfHeight = selfMeasure.getH() - mPaddingTop - mPaddingBottom; @@ -112,7 +117,7 @@ public class CanvasLayout extends BoxLayout { } @Override - public void write(WireBuffer buffer) { + public void write(@NonNull WireBuffer buffer) { apply(buffer, mComponentId, mAnimationId); } } 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 402b784343ad76efc71bd0a66bdd7b8d845c73b0..52bf4c54faf69c2b90bde3ef82ff6eb5a5c8ce9e 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 @@ -18,6 +18,8 @@ package com.android.internal.widget.remotecompose.core.operations.layout.manager 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; @@ -87,6 +89,7 @@ public class ColumnLayout extends LayoutManager implements ComponentStartOperati spacedBy); } + @NonNull @Override public String toString() { return "COLUMN [" @@ -105,14 +108,24 @@ public class ColumnLayout extends LayoutManager implements ComponentStartOperati + mVisibility; } + @NonNull @Override protected String getSerializedName() { return "COLUMN"; } + @Override + public boolean isInVerticalFill() { + return super.isInVerticalFill() || childrenHaveVerticalWeights(); + } + @Override public void computeWrapSize( - PaintContext context, float maxWidth, float maxHeight, MeasurePass measure, Size size) { + PaintContext context, + float maxWidth, + float maxHeight, + @NonNull MeasurePass measure, + @NonNull Size size) { DebugLog.s(() -> "COMPUTE WRAP SIZE in " + this + " (" + mComponentId + ")"); int visibleChildrens = 0; for (Component c : mChildrenComponents) { @@ -137,7 +150,7 @@ public class ColumnLayout extends LayoutManager implements ComponentStartOperati float maxWidth, float minHeight, float maxHeight, - MeasurePass measure) { + @NonNull MeasurePass measure) { DebugLog.s(() -> "COMPUTE SIZE in " + this + " (" + mComponentId + ")"); float mh = maxHeight; for (Component child : mChildrenComponents) { @@ -151,7 +164,7 @@ public class ColumnLayout extends LayoutManager implements ComponentStartOperati } @Override - public void internalLayoutMeasure(PaintContext context, MeasurePass measure) { + public void internalLayoutMeasure(PaintContext context, @NonNull MeasurePass measure) { ComponentMeasure selfMeasure = measure.get(this); DebugLog.s( () -> @@ -302,6 +315,7 @@ public class ColumnLayout extends LayoutManager implements ComponentStartOperati DebugLog.e(); } + @NonNull public static String name() { return "ColumnLayout"; } @@ -311,7 +325,7 @@ public class ColumnLayout extends LayoutManager implements ComponentStartOperati } public static void apply( - WireBuffer buffer, + @NonNull WireBuffer buffer, int componentId, int animationId, int horizontalPositioning, @@ -325,7 +339,7 @@ public class ColumnLayout extends LayoutManager implements ComponentStartOperati buffer.writeFloat(spacedBy); } - public static void read(WireBuffer buffer, List operations) { + public static void read(@NonNull WireBuffer buffer, @NonNull List operations) { int componentId = buffer.readInt(); int animationId = buffer.readInt(); int horizontalPositioning = buffer.readInt(); @@ -341,7 +355,7 @@ public class ColumnLayout extends LayoutManager implements ComponentStartOperati spacedBy)); } - public static void documentation(DocumentationBuilder doc) { + public static void documentation(@NonNull DocumentationBuilder doc) { doc.operation("Layout Operations", id(), name()) .description( "Column layout implementation, positioning components one" @@ -374,7 +388,7 @@ public class ColumnLayout extends LayoutManager implements ComponentStartOperati } @Override - public void write(WireBuffer buffer) { + public void write(@NonNull WireBuffer buffer) { apply( buffer, mComponentId, 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 308ed64ee8eafbb101f124b2496672e88c9d982e..0c4d24a4561a36486d5540f0977898f3fd026967 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 @@ -15,6 +15,8 @@ */ package com.android.internal.widget.remotecompose.core.operations.layout.managers; +import android.annotation.NonNull; + import com.android.internal.widget.remotecompose.core.PaintContext; import com.android.internal.widget.remotecompose.core.RemoteContext; import com.android.internal.widget.remotecompose.core.operations.layout.Component; @@ -27,7 +29,7 @@ import com.android.internal.widget.remotecompose.core.operations.layout.measure. /** Base class for layout managers -- resizable components. */ public abstract class LayoutManager extends LayoutComponent implements Measurable { - Size mCachedWrapSize = new Size(0f, 0f); + @NonNull Size mCachedWrapSize = new Size(0f, 0f); public LayoutManager( Component parent, @@ -62,6 +64,38 @@ public abstract class LayoutManager extends LayoutComponent implements Measurabl // nothing here } + protected boolean childrenHaveHorizontalWeights() { + for (Component c : mChildrenComponents) { + if (c instanceof LayoutManager) { + LayoutManager m = (LayoutManager) c; + if (m.getWidthModifier() != null && m.getWidthModifier().hasWeight()) { + return true; + } + } + } + return false; + } + + protected boolean childrenHaveVerticalWeights() { + for (Component c : mChildrenComponents) { + if (c instanceof LayoutManager) { + LayoutManager m = (LayoutManager) c; + if (m.getHeightModifier() != null && m.getHeightModifier().hasWeight()) { + return true; + } + } + } + return false; + } + + public boolean isInHorizontalFill() { + return mWidthModifier.isFill(); + } + + public boolean isInVerticalFill() { + return mHeightModifier.isFill(); + } + /** Base implementation of the measure resolution */ @Override public void measure( @@ -70,7 +104,7 @@ public abstract class LayoutManager extends LayoutComponent implements Measurabl float maxWidth, float minHeight, float maxHeight, - MeasurePass measure) { + @NonNull MeasurePass measure) { boolean hasWrap = true; float measuredWidth = Math.min(maxWidth, computeModifierDefinedWidth() - mMarginLeft - mMarginRight); @@ -87,7 +121,7 @@ public abstract class LayoutManager extends LayoutComponent implements Measurabl } else { hasWrap = false; } - if (mWidthModifier.isFill()) { + if (isInHorizontalFill()) { measuredWidth = insetMaxWidth; } else if (mWidthModifier.hasWeight()) { measuredWidth = Math.max(measuredWidth, computeModifierDefinedWidth()); @@ -95,7 +129,7 @@ public abstract class LayoutManager extends LayoutComponent implements Measurabl measuredWidth = Math.max(measuredWidth, minWidth); measuredWidth = Math.min(measuredWidth, insetMaxWidth); } - if (mHeightModifier.isFill()) { + if (isInVerticalFill()) { measuredHeight = insetMaxHeight; } else if (mHeightModifier.hasWeight()) { measuredHeight = Math.max(measuredHeight, computeModifierDefinedHeight()); @@ -136,7 +170,7 @@ public abstract class LayoutManager extends LayoutComponent implements Measurabl /** basic layout of internal components */ @Override - public void layout(RemoteContext context, MeasurePass measure) { + public void layout(@NonNull RemoteContext context, @NonNull MeasurePass measure) { super.layout(context, measure); ComponentMeasure self = measure.get(this); @@ -153,7 +187,7 @@ public abstract class LayoutManager extends LayoutComponent implements Measurabl * @param context * @param measure */ - public void selfLayout(RemoteContext context, MeasurePass measure) { + public void selfLayout(@NonNull RemoteContext context, @NonNull MeasurePass measure) { super.layout(context, measure); ComponentMeasure self = measure.get(this); 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 b29a05c27e5f87a984cf4bf23abe9018485de7b3..a366dc804758149fa8e2e85d59fc8e0433d36a13 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 @@ -18,6 +18,8 @@ package com.android.internal.widget.remotecompose.core.operations.layout.manager 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; @@ -85,6 +87,7 @@ public class RowLayout extends LayoutManager implements ComponentStartOperation spacedBy); } + @NonNull @Override public String toString() { return "ROW [" @@ -103,14 +106,24 @@ public class RowLayout extends LayoutManager implements ComponentStartOperation + mVisibility; } + @NonNull @Override protected String getSerializedName() { return "ROW"; } + @Override + public boolean isInHorizontalFill() { + return super.isInHorizontalFill() || childrenHaveHorizontalWeights(); + } + @Override public void computeWrapSize( - PaintContext context, float maxWidth, float maxHeight, MeasurePass measure, Size size) { + PaintContext context, + float maxWidth, + float maxHeight, + @NonNull MeasurePass measure, + @NonNull Size size) { DebugLog.s(() -> "COMPUTE WRAP SIZE in " + this + " (" + mComponentId + ")"); // int visibleChildrens = 0; for (Component c : mChildrenComponents) { @@ -135,7 +148,7 @@ public class RowLayout extends LayoutManager implements ComponentStartOperation float maxWidth, float minHeight, float maxHeight, - MeasurePass measure) { + @NonNull MeasurePass measure) { DebugLog.s(() -> "COMPUTE SIZE in " + this + " (" + mComponentId + ")"); float mw = maxWidth; for (Component child : mChildrenComponents) { @@ -149,7 +162,7 @@ public class RowLayout extends LayoutManager implements ComponentStartOperation } @Override - public void internalLayoutMeasure(PaintContext context, MeasurePass measure) { + public void internalLayoutMeasure(PaintContext context, @NonNull MeasurePass measure) { ComponentMeasure selfMeasure = measure.get(this); DebugLog.s( () -> @@ -305,6 +318,7 @@ public class RowLayout extends LayoutManager implements ComponentStartOperation DebugLog.e(); } + @NonNull public static String name() { return "RowLayout"; } @@ -314,7 +328,7 @@ public class RowLayout extends LayoutManager implements ComponentStartOperation } public static void apply( - WireBuffer buffer, + @NonNull WireBuffer buffer, int componentId, int animationId, int horizontalPositioning, @@ -328,7 +342,7 @@ public class RowLayout extends LayoutManager implements ComponentStartOperation buffer.writeFloat(spacedBy); } - public static void read(WireBuffer buffer, List operations) { + public static void read(@NonNull WireBuffer buffer, @NonNull List operations) { int componentId = buffer.readInt(); int animationId = buffer.readInt(); int horizontalPositioning = buffer.readInt(); @@ -344,7 +358,7 @@ public class RowLayout extends LayoutManager implements ComponentStartOperation spacedBy)); } - public static void documentation(DocumentationBuilder doc) { + public static void documentation(@NonNull DocumentationBuilder doc) { doc.operation("Layout Operations", id(), name()) .description( "Row layout implementation, positioning components one" @@ -377,7 +391,7 @@ public class RowLayout extends LayoutManager implements ComponentStartOperation } @Override - public void write(WireBuffer buffer) { + public void write(@NonNull WireBuffer buffer) { apply( buffer, mComponentId, 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 b5c728135f76b9834e6431a0c5f9b2a32f1b3339..e47ffdebb25397484422039da1dc8f1c49a2c6fb 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 @@ -15,6 +15,8 @@ */ package com.android.internal.widget.remotecompose.core.operations.layout.managers; +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; @@ -50,10 +52,10 @@ public class StateLayout extends LayoutManager implements ComponentStartOperatio // This keep track of all the components associated with a given Id, // (the key being the id), and the set of components corresponds to the set of states // TODO: we should be able to optimize this - public Map statePaintedComponents = new HashMap<>(); + @NonNull public Map statePaintedComponents = new HashMap<>(); public int MAX_CACHE_ELEMENTS = 16; - public int[] cacheListElementsId = new int[MAX_CACHE_ELEMENTS]; + @NonNull public int[] cacheListElementsId = new int[MAX_CACHE_ELEMENTS]; public boolean inTransition = false; @@ -168,7 +170,7 @@ public class StateLayout extends LayoutManager implements ComponentStartOperatio } @Override - public void layout(RemoteContext context, MeasurePass measure) { + public void layout(@NonNull RemoteContext context, @NonNull MeasurePass measure) { ComponentMeasure self = measure.get(this); super.selfLayout(context, measure); @@ -207,12 +209,12 @@ public class StateLayout extends LayoutManager implements ComponentStartOperatio @Override public void measure( - PaintContext context, + @NonNull PaintContext context, float minWidth, float maxWidth, float minHeight, float maxHeight, - MeasurePass measure) { + @NonNull MeasurePass measure) { // The general approach for this widget is to do most of the work/setup in measure. // layout and paint then simply use what's been setup in the measure phase. @@ -364,19 +366,20 @@ public class StateLayout extends LayoutManager implements ComponentStartOperatio } @Override - public void paint(PaintContext context) { + public void paint(@NonNull PaintContext context) { if (mIndexId != 0) { int newValue = context.getContext().mRemoteComposeState.getInteger(mIndexId); if (newValue != currentLayoutIndex) { previousLayoutIndex = currentLayoutIndex; currentLayoutIndex = newValue; inTransition = true; - System.out.println("currentLayout index is $currentLayoutIndex"); + // System.out.println("currentLayout index is $currentLayoutIndex"); // executeValueSetActions(getLayout(currentLayoutIndex)); invalidateMeasure(); } } - System.out.println("PAINTING LAYOUT STATELAYOUT, CURRENT INDEX " + currentLayoutIndex); + // System.out.println("PAINTING LAYOUT STATELAYOUT, CURRENT INDEX " + + // currentLayoutIndex); // Make sure to mark any components that are not in either the current or previous layout // as being GONE. int index = 0; @@ -529,6 +532,7 @@ public class StateLayout extends LayoutManager implements ComponentStartOperatio // } // } + @NonNull @Override public String toString() { return "STATE_LAYOUT"; @@ -539,7 +543,7 @@ public class StateLayout extends LayoutManager implements ComponentStartOperatio // } public static void apply( - WireBuffer buffer, + @NonNull WireBuffer buffer, int componentId, int animationId, int horizontalPositioning, @@ -553,7 +557,7 @@ public class StateLayout extends LayoutManager implements ComponentStartOperatio buffer.writeInt(indexId); } - public static void read(WireBuffer buffer, List operations) { + public static void read(@NonNull WireBuffer buffer, @NonNull List operations) { int componentId = buffer.readInt(); int animationId = buffer.readInt(); buffer.readInt(); // horizontalPositioning 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 c1cabcd09c395dfea3d5634a72ac141a1fd95ee7..8aa7712635fc5473ce1b36909d2aab769f4206a2 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 @@ -18,6 +18,8 @@ package com.android.internal.widget.remotecompose.core.operations.layout.manager 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; @@ -44,22 +46,24 @@ public class TextLayout extends LayoutManager implements ComponentStartOperation private int mFontStyle = 0; private float mFontWeight = 400f; private int mFontFamilyId = -1; + private int mTextAlign = -1; private int mType = -1; private float mTextX; private float mTextY; + private float mTextW; private String mCachedString = ""; @Override - public void registerListening(RemoteContext context) { + public void registerListening(@NonNull RemoteContext context) { if (mTextId != -1) { context.listensTo(mTextId, this); } } @Override - public void updateVariables(RemoteContext context) { + public void updateVariables(@NonNull RemoteContext context) { mCachedString = context.getText(mTextId); if (mType == -1) { if (mFontFamilyId != -1) { @@ -97,7 +101,8 @@ public class TextLayout extends LayoutManager implements ComponentStartOperation float fontSize, int fontStyle, float fontWeight, - int fontFamilyId) { + int fontFamilyId, + int textAlign) { super(parent, componentId, animationId, x, y, width, height); mTextId = textId; mColor = color; @@ -105,6 +110,7 @@ public class TextLayout extends LayoutManager implements ComponentStartOperation mFontStyle = fontStyle; mFontWeight = fontWeight; mFontFamilyId = fontFamilyId; + mTextAlign = textAlign; } public TextLayout( @@ -116,7 +122,8 @@ public class TextLayout extends LayoutManager implements ComponentStartOperation float fontSize, int fontStyle, float fontWeight, - int fontFamilyId) { + int fontFamilyId, + int textAlign) { this( parent, componentId, @@ -130,13 +137,14 @@ public class TextLayout extends LayoutManager implements ComponentStartOperation fontSize, fontStyle, fontWeight, - fontFamilyId); + fontFamilyId, + textAlign); } - public PaintBundle mPaint = new PaintBundle(); + @NonNull public PaintBundle mPaint = new PaintBundle(); @Override - public void paintingComponent(PaintContext context) { + public void paintingComponent(@NonNull PaintContext context) { context.save(); context.translate(mX, mY); mComponentModifiers.paint(context); @@ -176,6 +184,7 @@ public class TextLayout extends LayoutManager implements ComponentStartOperation context.restore(); } + @NonNull @Override public String toString() { return "TEXT_LAYOUT [" @@ -194,13 +203,14 @@ public class TextLayout extends LayoutManager implements ComponentStartOperation + mVisibility; } + @NonNull @Override protected String getSerializedName() { return "TEXT_LAYOUT"; } @Override - public void serializeToString(int indent, StringSerializer serializer) { + public void serializeToString(int indent, @NonNull StringSerializer serializer) { serializer.append( indent, getSerializedName() @@ -228,7 +238,11 @@ public class TextLayout extends LayoutManager implements ComponentStartOperation @Override public void computeWrapSize( - PaintContext context, float maxWidth, float maxHeight, MeasurePass measure, Size size) { + @NonNull PaintContext context, + float maxWidth, + float maxHeight, + MeasurePass measure, + @NonNull Size size) { context.savePaint(); mPaint.reset(); mPaint.setTextSize(mFontSize); @@ -244,8 +258,10 @@ public class TextLayout extends LayoutManager implements ComponentStartOperation mTextX = -bounds[0]; size.setHeight(h); mTextY = -bounds[1]; + mTextW = w; } + @NonNull public static String name() { return "TextLayout"; } @@ -255,7 +271,7 @@ public class TextLayout extends LayoutManager implements ComponentStartOperation } public static void apply( - WireBuffer buffer, + @NonNull WireBuffer buffer, int componentId, int animationId, int textId, @@ -263,7 +279,8 @@ public class TextLayout extends LayoutManager implements ComponentStartOperation float fontSize, int fontStyle, float fontWeight, - int fontFamilyId) { + int fontFamilyId, + int textAlign) { buffer.start(id()); buffer.writeInt(componentId); buffer.writeInt(animationId); @@ -273,9 +290,10 @@ public class TextLayout extends LayoutManager implements ComponentStartOperation buffer.writeInt(fontStyle); buffer.writeFloat(fontWeight); buffer.writeInt(fontFamilyId); + buffer.writeInt(textAlign); } - public static void read(WireBuffer buffer, List operations) { + public static void read(@NonNull WireBuffer buffer, @NonNull List operations) { int componentId = buffer.readInt(); int animationId = buffer.readInt(); int textId = buffer.readInt(); @@ -284,6 +302,7 @@ public class TextLayout extends LayoutManager implements ComponentStartOperation int fontStyle = buffer.readInt(); float fontWeight = buffer.readFloat(); int fontFamilyId = buffer.readInt(); + int textAlign = buffer.readInt(); operations.add( new TextLayout( null, @@ -294,10 +313,11 @@ public class TextLayout extends LayoutManager implements ComponentStartOperation fontSize, fontStyle, fontWeight, - fontFamilyId)); + fontFamilyId, + textAlign)); } - public static void documentation(DocumentationBuilder doc) { + public static void documentation(@NonNull DocumentationBuilder doc) { doc.operation("Layout Operations", id(), name()) .description("Text layout implementation.\n\n") .field(INT, "COMPONENT_ID", "unique id for this component") @@ -313,7 +333,7 @@ public class TextLayout extends LayoutManager implements ComponentStartOperation } @Override - public void write(WireBuffer buffer) { + public void write(@NonNull WireBuffer buffer) { apply( buffer, mComponentId, @@ -323,6 +343,7 @@ public class TextLayout extends LayoutManager implements ComponentStartOperation mFontSize, mFontStyle, mFontWeight, - mFontFamilyId); + mFontFamilyId, + mTextAlign); } } 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 285425f99765bddc0dd96d16b37ab887fb768aef..426e02337f5bac42ca72bfcc1551837f0faf3f14 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 @@ -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.operations.layout.Component; /** Encapsulate the result of a measure pass for a component */ @@ -80,7 +82,7 @@ public class ComponentMeasure { this(id, x, y, w, h, Component.Visibility.VISIBLE); } - public ComponentMeasure(Component component) { + public ComponentMeasure(@NonNull Component component) { this( component.getComponentId(), component.getX(), @@ -90,7 +92,7 @@ public class ComponentMeasure { component.mVisibility); } - public void copyFrom(ComponentMeasure m) { + public void copyFrom(@NonNull ComponentMeasure m) { mX = m.mX; mY = m.mY; mW = m.mW; @@ -98,7 +100,7 @@ public class ComponentMeasure { mVisibility = m.mVisibility; } - public boolean same(ComponentMeasure m) { + public boolean same(@NonNull ComponentMeasure m) { return mX == m.mX && mY == m.mY && mW == m.mW && mH == m.mH && mVisibility == m.mVisibility; } } 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 8d01fea03690fd537c83ece0a1752aca94082198..112ab1b93474825871791eecd17d3b5302e44463 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 @@ -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.operations.layout.Component; import java.util.HashMap; @@ -24,13 +26,13 @@ import java.util.HashMap; * array vs the current hashmap */ public class MeasurePass { - HashMap mList = new HashMap<>(); + @NonNull HashMap mList = new HashMap<>(); public void clear() { mList.clear(); } - public void add(ComponentMeasure measure) throws Exception { + public void add(@NonNull ComponentMeasure measure) throws Exception { if (measure.mId == -1) { throw new Exception("Component has no id!"); } @@ -41,7 +43,7 @@ public class MeasurePass { return mList.containsKey(id); } - public ComponentMeasure get(Component c) { + public ComponentMeasure get(@NonNull Component c) { if (!mList.containsKey(c.getComponentId())) { ComponentMeasure measure = new ComponentMeasure( 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 64e40f7c591c79e831778b64ba519397d3810b88..76a97ca0eb51ee3987c2e3d2b89d2f935275d703 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 @@ -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; @@ -42,7 +44,7 @@ public class BackgroundModifierOperation extends DecoratorModifierOperation { float mA; int mShapeType = ShapeType.RECTANGLE; - public PaintBundle mPaint = new PaintBundle(); + @NonNull public PaintBundle mPaint = new PaintBundle(); public BackgroundModifierOperation( float x, @@ -66,12 +68,12 @@ public class BackgroundModifierOperation extends DecoratorModifierOperation { } @Override - public void write(WireBuffer buffer) { + public void write(@NonNull WireBuffer buffer) { apply(buffer, mX, mY, mWidth, mHeight, mR, mG, mB, mA, mShapeType); } @Override - public void serializeToString(int indent, StringSerializer serializer) { + public void serializeToString(int indent, @NonNull StringSerializer serializer) { serializer.append( indent, "BACKGROUND = [" @@ -101,11 +103,13 @@ public class BackgroundModifierOperation extends DecoratorModifierOperation { this.mHeight = height; } + @NonNull @Override public String toString() { return "BackgroundModifierOperation(" + mWidth + " x " + mHeight + ")"; } + @NonNull public static String name() { return CLASS_NAME; } @@ -115,7 +119,7 @@ public class BackgroundModifierOperation extends DecoratorModifierOperation { } public static void apply( - WireBuffer buffer, + @NonNull WireBuffer buffer, float x, float y, float width, @@ -138,7 +142,7 @@ public class BackgroundModifierOperation extends DecoratorModifierOperation { buffer.writeInt(shapeType); } - public static void read(WireBuffer buffer, List operations) { + public static void read(@NonNull WireBuffer buffer, @NonNull List operations) { float x = buffer.readFloat(); float y = buffer.readFloat(); float width = buffer.readFloat(); @@ -153,7 +157,7 @@ public class BackgroundModifierOperation extends DecoratorModifierOperation { } @Override - public void paint(PaintContext context) { + public void paint(@NonNull PaintContext context) { context.savePaint(); mPaint.reset(); mPaint.setStyle(PaintBundle.STYLE_FILL); @@ -167,7 +171,7 @@ public class BackgroundModifierOperation extends DecoratorModifierOperation { context.restorePaint(); } - public static void documentation(DocumentationBuilder doc) { + public static void documentation(@NonNull DocumentationBuilder doc) { doc.operation("Modifier Operations", OP_CODE, CLASS_NAME) .description("define the Background Modifier") .field(FLOAT, "x", "") 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 92c0a733d8a1d04ce41ddd216eb291d047fbd5aa..d48a9c732cd52053f924f7d5534c6fa26c14bd8b 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 @@ -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; @@ -45,7 +47,7 @@ public class BorderModifierOperation extends DecoratorModifierOperation { float mA; int mShapeType = ShapeType.RECTANGLE; - public PaintBundle paint = new PaintBundle(); + @NonNull public PaintBundle paint = new PaintBundle(); public BorderModifierOperation( float x, @@ -73,7 +75,7 @@ public class BorderModifierOperation extends DecoratorModifierOperation { } @Override - public void serializeToString(int indent, StringSerializer serializer) { + public void serializeToString(int indent, @NonNull StringSerializer serializer) { serializer.append( indent, "BORDER = [" @@ -105,7 +107,7 @@ public class BorderModifierOperation extends DecoratorModifierOperation { } @Override - public void write(WireBuffer buffer) { + public void write(@NonNull WireBuffer buffer) { apply( buffer, mX, @@ -127,6 +129,7 @@ public class BorderModifierOperation extends DecoratorModifierOperation { this.mHeight = height; } + @NonNull @Override public String toString() { return "BorderModifierOperation(" @@ -152,6 +155,7 @@ public class BorderModifierOperation extends DecoratorModifierOperation { + ")"; } + @NonNull public static String name() { return CLASS_NAME; } @@ -161,7 +165,7 @@ public class BorderModifierOperation extends DecoratorModifierOperation { } public static void apply( - WireBuffer buffer, + @NonNull WireBuffer buffer, float x, float y, float width, @@ -188,7 +192,7 @@ public class BorderModifierOperation extends DecoratorModifierOperation { buffer.writeInt(shapeType); } - public static void read(WireBuffer buffer, List operations) { + public static void read(@NonNull WireBuffer buffer, @NonNull List operations) { float x = buffer.readFloat(); float y = buffer.readFloat(); float width = buffer.readFloat(); @@ -206,7 +210,7 @@ public class BorderModifierOperation extends DecoratorModifierOperation { } @Override - public void paint(PaintContext context) { + public void paint(@NonNull PaintContext context) { context.savePaint(); paint.reset(); paint.setColor(mR, mG, mB, mA); @@ -225,7 +229,7 @@ public class BorderModifierOperation extends DecoratorModifierOperation { context.restorePaint(); } - public static void documentation(DocumentationBuilder doc) { + public static void documentation(@NonNull DocumentationBuilder doc) { doc.operation("Modifier Operations", OP_CODE, CLASS_NAME) .description("define the Border Modifier") .field(FLOAT, "x", "") 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 0d8aeaa2f06a76060e785d0b9abb3fc2f9854940..78b51c3f83aa7fe6cbfb678243a069ce9cf34fcf 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 @@ -15,14 +15,14 @@ */ package com.android.internal.widget.remotecompose.core.operations.layout.modifiers; -import com.android.internal.widget.remotecompose.core.CoreDocument; +import android.annotation.NonNull; + import com.android.internal.widget.remotecompose.core.Operation; import com.android.internal.widget.remotecompose.core.Operations; import com.android.internal.widget.remotecompose.core.PaintContext; import com.android.internal.widget.remotecompose.core.RemoteContext; import com.android.internal.widget.remotecompose.core.WireBuffer; import com.android.internal.widget.remotecompose.core.documentation.DocumentationBuilder; -import com.android.internal.widget.remotecompose.core.operations.layout.Component; import com.android.internal.widget.remotecompose.core.operations.utilities.StringSerializer; import java.util.List; @@ -35,7 +35,7 @@ public class ClipRectModifierOperation extends DecoratorModifierOperation { float mHeight; @Override - public void paint(PaintContext context) { + public void paint(@NonNull PaintContext context) { context.clipRect(0f, 0f, mWidth, mHeight); } @@ -46,21 +46,16 @@ public class ClipRectModifierOperation extends DecoratorModifierOperation { } @Override - public void onClick( - RemoteContext context, CoreDocument document, Component component, float x, float y) { - // nothing - } - - @Override - public void serializeToString(int indent, StringSerializer serializer) { + public void serializeToString(int indent, @NonNull StringSerializer serializer) { serializer.append(indent, "CLIP_RECT = [" + mWidth + ", " + mHeight + "]"); } @Override - public void write(WireBuffer buffer) { + public void write(@NonNull WireBuffer buffer) { apply(buffer); } + @NonNull public static String name() { return CLASS_NAME; } @@ -69,15 +64,15 @@ public class ClipRectModifierOperation extends DecoratorModifierOperation { return OP_CODE; } - public static void apply(WireBuffer buffer) { + public static void apply(@NonNull WireBuffer buffer) { buffer.start(OP_CODE); } - public static void read(WireBuffer buffer, List operations) { + public static void read(WireBuffer buffer, @NonNull List operations) { operations.add(new ClipRectModifierOperation()); } - public static void documentation(DocumentationBuilder doc) { + public static void documentation(@NonNull DocumentationBuilder doc) { doc.operation("Canvas Operations", OP_CODE, CLASS_NAME) .description("Draw the specified round-rect"); } diff --git a/core/java/com/android/internal/widget/remotecompose/core/operations/layout/modifiers/ComponentModifiers.java b/core/java/com/android/internal/widget/remotecompose/core/operations/layout/modifiers/ComponentModifiers.java index 95786a8b62b0dabe9d432f04dedb0ee7de0c6323..011d7edd18c8e89e74244226550829e28fd81731 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 @@ -15,6 +15,8 @@ */ package com.android.internal.widget.remotecompose.core.operations.layout.modifiers; +import android.annotation.NonNull; + import com.android.internal.widget.remotecompose.core.CoreDocument; import com.android.internal.widget.remotecompose.core.PaintContext; import com.android.internal.widget.remotecompose.core.PaintOperation; @@ -22,29 +24,34 @@ import com.android.internal.widget.remotecompose.core.RemoteContext; import com.android.internal.widget.remotecompose.core.WireBuffer; import com.android.internal.widget.remotecompose.core.operations.MatrixRestore; import com.android.internal.widget.remotecompose.core.operations.MatrixSave; +import com.android.internal.widget.remotecompose.core.operations.layout.ClickHandler; import com.android.internal.widget.remotecompose.core.operations.layout.ClickModifierOperation; import com.android.internal.widget.remotecompose.core.operations.layout.Component; import com.android.internal.widget.remotecompose.core.operations.layout.DecoratorComponent; +import com.android.internal.widget.remotecompose.core.operations.layout.TouchHandler; import com.android.internal.widget.remotecompose.core.operations.utilities.StringSerializer; import java.util.ArrayList; /** Maintain a list of modifiers */ -public class ComponentModifiers extends PaintOperation implements DecoratorComponent { - ArrayList mList = new ArrayList<>(); +public class ComponentModifiers extends PaintOperation + implements DecoratorComponent, ClickHandler, TouchHandler { + @NonNull ArrayList mList = new ArrayList<>(); + @NonNull public ArrayList getList() { return mList; } @Override - public void apply(RemoteContext context) { + public void apply(@NonNull RemoteContext context) { super.apply(context); for (ModifierOperation op : mList) { op.apply(context); } } + @NonNull @Override public String toString() { String str = "ComponentModifiers \n"; @@ -59,7 +66,7 @@ public class ComponentModifiers extends PaintOperation implements DecoratorCompo // nothing } - public void serializeToString(int indent, StringSerializer serializer) { + public void serializeToString(int indent, @NonNull StringSerializer serializer) { serializer.append(indent, "MODIFIERS"); for (ModifierOperation m : mList) { m.serializeToString(indent + 1, serializer); @@ -75,7 +82,7 @@ public class ComponentModifiers extends PaintOperation implements DecoratorCompo } @Override - public void paint(PaintContext context) { + public void paint(@NonNull PaintContext context) { float tx = 0f; float ty = 0f; for (ModifierOperation op : mList) { @@ -127,8 +134,38 @@ public class ComponentModifiers extends PaintOperation implements DecoratorCompo public void onClick( RemoteContext context, CoreDocument document, Component component, float x, float y) { for (ModifierOperation op : mList) { - if (op instanceof DecoratorComponent) { - ((DecoratorComponent) op).onClick(context, document, component, x, y); + if (op instanceof ClickHandler) { + ((ClickHandler) op).onClick(context, document, component, x, y); + } + } + } + + @Override + public void onTouchDown( + RemoteContext context, CoreDocument document, Component component, float x, float y) { + for (ModifierOperation op : mList) { + if (op instanceof TouchHandler) { + ((TouchHandler) op).onTouchDown(context, document, component, x, y); + } + } + } + + @Override + public void onTouchUp( + RemoteContext context, CoreDocument document, Component component, float x, float y) { + for (ModifierOperation op : mList) { + if (op instanceof TouchHandler) { + ((TouchHandler) op).onTouchUp(context, document, component, x, y); + } + } + } + + @Override + public void onTouchCancel( + RemoteContext context, CoreDocument document, Component component, float x, float y) { + for (ModifierOperation op : mList) { + if (op instanceof TouchHandler) { + ((TouchHandler) op).onTouchCancel(context, document, component, x, y); } } } 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 312d016029fb7b1279d0d525e157a7a9f5fe2f09..26e737b32027231e166e11742fb6b09bc36cdc3b 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 @@ -17,7 +17,9 @@ package com.android.internal.widget.remotecompose.core.operations.layout.modifie import static com.android.internal.widget.remotecompose.core.documentation.DocumentedOperation.INT; -import com.android.internal.widget.remotecompose.core.CoreDocument; +import android.annotation.NonNull; +import android.annotation.Nullable; + import com.android.internal.widget.remotecompose.core.Operation; import com.android.internal.widget.remotecompose.core.Operations; import com.android.internal.widget.remotecompose.core.RemoteContext; @@ -37,49 +39,52 @@ public class ComponentVisibilityOperation private static final int OP_CODE = Operations.MODIFIER_VISIBILITY; int mVisibilityId; - Component.Visibility mVisibility = Component.Visibility.VISIBLE; + @NonNull Component.Visibility mVisibility = Component.Visibility.VISIBLE; private LayoutComponent mParent; public ComponentVisibilityOperation(int id) { mVisibilityId = id; } + @NonNull @Override public String toString() { return "ComponentVisibilityOperation(" + mVisibilityId + ")"; } + @NonNull public String serializedName() { return "COMPONENT_VISIBILITY"; } @Override - public void serializeToString(int indent, StringSerializer serializer) { + public void serializeToString(int indent, @NonNull StringSerializer serializer) { serializer.append(indent, serializedName() + " = " + mVisibilityId); } @Override public void apply(RemoteContext context) {} + @NonNull @Override - public String deepToString(String indent) { + public String deepToString(@Nullable String indent) { return (indent != null ? indent : "") + toString(); } @Override public void write(WireBuffer buffer) {} - public static void apply(WireBuffer buffer, int valueId) { + public static void apply(@NonNull WireBuffer buffer, int valueId) { buffer.start(OP_CODE); buffer.writeInt(valueId); } - public static void read(WireBuffer buffer, List operations) { + public static void read(@NonNull WireBuffer buffer, @NonNull List operations) { int valueId = buffer.readInt(); operations.add(new ComponentVisibilityOperation(valueId)); } - public static void documentation(DocumentationBuilder doc) { + public static void documentation(@NonNull DocumentationBuilder doc) { doc.operation("Layout Operations", OP_CODE, "ComponentVisibility") .description( "This operation allows setting a component" @@ -88,12 +93,12 @@ public class ComponentVisibilityOperation } @Override - public void registerListening(RemoteContext context) { + public void registerListening(@NonNull RemoteContext context) { context.listensTo(mVisibilityId, this); } @Override - public void updateVariables(RemoteContext context) { + public void updateVariables(@NonNull RemoteContext context) { int visibility = context.getInteger(mVisibilityId); if (visibility == Component.Visibility.VISIBLE.ordinal()) { mVisibility = Component.Visibility.VISIBLE; @@ -115,8 +120,4 @@ public class ComponentVisibilityOperation @Override public void layout(RemoteContext context, float width, float height) {} - - @Override - public void onClick( - RemoteContext context, CoreDocument document, Component component, float x, float y) {} } diff --git a/core/java/com/android/internal/widget/remotecompose/core/operations/layout/modifiers/DecoratorModifierOperation.java b/core/java/com/android/internal/widget/remotecompose/core/operations/layout/modifiers/DecoratorModifierOperation.java index 41e18cbafbe6094162d88b06e09b27f79bb1e180..b4c4108802eece72b5ec7cfd03371bf4050dc00c 100644 --- a/core/java/com/android/internal/widget/remotecompose/core/operations/layout/modifiers/DecoratorModifierOperation.java +++ b/core/java/com/android/internal/widget/remotecompose/core/operations/layout/modifiers/DecoratorModifierOperation.java @@ -15,10 +15,7 @@ */ package com.android.internal.widget.remotecompose.core.operations.layout.modifiers; -import com.android.internal.widget.remotecompose.core.CoreDocument; import com.android.internal.widget.remotecompose.core.PaintOperation; -import com.android.internal.widget.remotecompose.core.RemoteContext; -import com.android.internal.widget.remotecompose.core.operations.layout.Component; import com.android.internal.widget.remotecompose.core.operations.layout.DecoratorComponent; /** @@ -26,11 +23,4 @@ import com.android.internal.widget.remotecompose.core.operations.layout.Decorato * output (background, border...) */ public abstract class DecoratorModifierOperation extends PaintOperation - implements ModifierOperation, DecoratorComponent { - - @Override - public void onClick( - RemoteContext context, CoreDocument document, Component component, float x, float y) { - // nothing - } -} + implements ModifierOperation, DecoratorComponent {} 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 408bebcfb7d9394bdf832dcba68616c055f301af..3c2d85cfee5bbdf120e92dc7b2971f63073fcad8 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 @@ -15,6 +15,9 @@ */ 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; import com.android.internal.widget.remotecompose.core.operations.Utils; @@ -29,8 +32,10 @@ public abstract class DimensionModifierOperation implements ModifierOperation, V WRAP, WEIGHT, INTRINSIC_MIN, - INTRINSIC_MAX; + INTRINSIC_MAX, + EXACT_DP; + @NonNull static Type fromInt(int value) { switch (value) { case 0: @@ -45,6 +50,8 @@ public abstract class DimensionModifierOperation implements ModifierOperation, V return INTRINSIC_MIN; case 5: return INTRINSIC_MAX; + case 6: + return EXACT_DP; } return EXACT; } @@ -68,19 +75,32 @@ public abstract class DimensionModifierOperation implements ModifierOperation, V } @Override - public void updateVariables(RemoteContext context) { + public void updateVariables(@NonNull RemoteContext context) { if (mType == Type.EXACT) { mOutValue = Float.isNaN(mValue) ? context.getFloat(Utils.idFromNan(mValue)) : mValue; } + if (mType == Type.EXACT_DP) { + float pre = mOutValue; + mOutValue = Float.isNaN(mValue) ? context.getFloat(Utils.idFromNan(mValue)) : mValue; + mOutValue *= context.getDensity(); + if (pre != mOutValue) { + context.getDocument().getRootLayoutComponent().invalidateMeasure(); + } + } } @Override - public void registerListening(RemoteContext context) { + public void registerListening(@NonNull RemoteContext context) { if (mType == Type.EXACT) { if (Float.isNaN(mValue)) { context.listensTo(Utils.idFromNan(mValue), this); } } + if (mType == Type.EXACT_DP) { + if (Float.isNaN(mValue)) { + context.listensTo(Utils.idFromNan(mValue), this); + } + } } public boolean hasWeight() { @@ -107,25 +127,31 @@ public abstract class DimensionModifierOperation implements ModifierOperation, V mOutValue = mValue = value; } + @NonNull public String serializedName() { return "DIMENSION"; } @Override - public void serializeToString(int indent, StringSerializer serializer) { + public void serializeToString(int indent, @NonNull StringSerializer serializer) { if (mType == Type.EXACT) { serializer.append(indent, serializedName() + " = " + mValue); } + if (mType == Type.EXACT_DP) { + serializer.append(indent, serializedName() + " = " + mValue + " dp"); + } } @Override public void apply(RemoteContext context) {} + @NonNull @Override - public String deepToString(String indent) { + public String deepToString(@Nullable String indent) { return (indent != null ? indent : "") + toString(); } + @NonNull @Override public String toString() { return "DimensionModifierOperation(" + mValue + ")"; 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 new file mode 100644 index 0000000000000000000000000000000000000000..2b3038281d57fd6307a98fba621c717ff9a2dcf9 --- /dev/null +++ b/core/java/com/android/internal/widget/remotecompose/core/operations/layout/modifiers/GraphicsLayerModifierOperation.java @@ -0,0 +1,302 @@ +/* + * Copyright (C) 2024 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.android.internal.widget.remotecompose.core.operations.layout.modifiers; + +import static com.android.internal.widget.remotecompose.core.documentation.DocumentedOperation.FLOAT; +import static com.android.internal.widget.remotecompose.core.documentation.DocumentedOperation.INT; + +import com.android.internal.widget.remotecompose.core.Operation; +import com.android.internal.widget.remotecompose.core.Operations; +import com.android.internal.widget.remotecompose.core.PaintContext; +import com.android.internal.widget.remotecompose.core.RemoteContext; +import com.android.internal.widget.remotecompose.core.WireBuffer; +import com.android.internal.widget.remotecompose.core.documentation.DocumentationBuilder; +import com.android.internal.widget.remotecompose.core.operations.layout.AnimatableValue; +import com.android.internal.widget.remotecompose.core.operations.utilities.StringSerializer; + +import java.util.List; + +/** + * Represents a padding modifier. Padding modifiers can be chained and will impact following + * modifiers. + */ +public class GraphicsLayerModifierOperation extends DecoratorModifierOperation { + private static final int OP_CODE = Operations.MODIFIER_GRAPHICS_LAYER; + public static final String CLASS_NAME = "GraphicsLayerModifierOperation"; + + AnimatableValue mScaleX; + AnimatableValue mScaleY; + AnimatableValue mRotationX; + AnimatableValue mRotationY; + AnimatableValue mRotationZ; + AnimatableValue mTransformOriginX; + AnimatableValue mTransformOriginY; + AnimatableValue mShadowElevation; + AnimatableValue mAlpha; + AnimatableValue mCameraDistance; + int mBlendMode; + int mSpotShadowColorId; + int mAmbientShadowColorId; + int mColorFilterId; + int mRenderEffectId; + + public GraphicsLayerModifierOperation( + float scaleX, + float scaleY, + float rotationX, + float rotationY, + float rotationZ, + float shadowElevation, + float transformOriginX, + float transformOriginY, + float alpha, + float cameraDistance, + int blendMode, + int spotShadowColorId, + int ambientShadowColorId, + int colorFilterId, + int renderEffectId) { + mScaleX = new AnimatableValue(scaleX); + mScaleY = new AnimatableValue(scaleY); + mRotationX = new AnimatableValue(rotationX); + mRotationY = new AnimatableValue(rotationY); + mRotationZ = new AnimatableValue(rotationZ); + mShadowElevation = new AnimatableValue(shadowElevation); + mTransformOriginX = new AnimatableValue(transformOriginX); + mTransformOriginY = new AnimatableValue(transformOriginY); + mAlpha = new AnimatableValue(alpha); + mCameraDistance = new AnimatableValue(cameraDistance); + mBlendMode = blendMode; + mSpotShadowColorId = spotShadowColorId; + mAmbientShadowColorId = ambientShadowColorId; + mColorFilterId = colorFilterId; + mRenderEffectId = renderEffectId; + } + + public float getScaleX() { + return mScaleX.getValue(); + } + + public float getScaleY() { + return mScaleY.getValue(); + } + + public float getRotationX() { + return mRotationX.getValue(); + } + + public float getRotationY() { + return mRotationY.getValue(); + } + + public float getRotationZ() { + return mRotationZ.getValue(); + } + + public float getShadowElevation() { + return mShadowElevation.getValue(); + } + + public float getTransformOriginX() { + return mTransformOriginX.getValue(); + } + + public float getTransformOriginY() { + return mTransformOriginY.getValue(); + } + + public float getAlpha() { + return mAlpha.getValue(); + } + + public float getCameraDistance() { + return mCameraDistance.getValue(); + } + + // TODO: add implementation for blendmode + public int getBlendModeId() { + return mBlendMode; + } + + // TODO: add implementation for shadow + public int getSpotShadowColorId() { + return mSpotShadowColorId; + } + + public int getAmbientShadowColorId() { + return mAmbientShadowColorId; + } + + // TODO: add implementation for color filters + public int getColorFilterId() { + return mColorFilterId; + } + + public int getRenderEffectId() { + return mRenderEffectId; + } + + @Override + public void write(WireBuffer buffer) { + apply( + buffer, + mScaleX.getValue(), + mScaleY.getValue(), + mRotationX.getValue(), + mRotationY.getValue(), + mRotationZ.getValue(), + mShadowElevation.getValue(), + mTransformOriginX.getValue(), + mTransformOriginY.getValue(), + mAlpha.getValue(), + mCameraDistance.getValue(), + mBlendMode, + mSpotShadowColorId, + mAmbientShadowColorId, + mColorFilterId, + mRenderEffectId); + } + + @Override + public void serializeToString(int indent, StringSerializer serializer) { + serializer.append(indent, "GRAPHICS_LAYER = [" + mScaleX + ", " + mScaleY + "]"); + } + + @Override + public String deepToString(String indent) { + return (indent != null ? indent : "") + toString(); + } + + @Override + public void paint(PaintContext context) { + mScaleX.evaluate(context); + mScaleY.evaluate(context); + mRotationX.evaluate(context); + mRotationY.evaluate(context); + mRotationZ.evaluate(context); + mTransformOriginX.evaluate(context); + mTransformOriginY.evaluate(context); + mShadowElevation.evaluate(context); + mAlpha.evaluate(context); + mCameraDistance.evaluate(context); + } + + @Override + public String toString() { + return "GraphicsLayerModifierOperation(" + mScaleX + ", " + mScaleY + ")"; + } + + public static String name() { + return CLASS_NAME; + } + + public static int id() { + return OP_CODE; + } + + public static void apply( + WireBuffer buffer, + float scaleX, + float scaleY, + float rotationX, + float rotationY, + float rotationZ, + float shadowElevation, + float transformOriginX, + float transformOriginY, + float alpha, + float cameraDistance, + int blendMode, + int spotShadowColorId, + int ambientShadowColorId, + int colorFilterId, + int renderEffectId) { + buffer.start(OP_CODE); + buffer.writeFloat(scaleX); + buffer.writeFloat(scaleY); + buffer.writeFloat(rotationX); + buffer.writeFloat(rotationY); + buffer.writeFloat(rotationZ); + buffer.writeFloat(shadowElevation); + buffer.writeFloat(transformOriginX); + buffer.writeFloat(transformOriginY); + buffer.writeFloat(alpha); + buffer.writeFloat(cameraDistance); + buffer.writeInt(blendMode); + buffer.writeInt(spotShadowColorId); + buffer.writeInt(ambientShadowColorId); + buffer.writeInt(colorFilterId); + buffer.writeInt(renderEffectId); + } + + public static void read(WireBuffer buffer, List operations) { + float scaleX = buffer.readFloat(); + float scaleY = buffer.readFloat(); + float rotationX = buffer.readFloat(); + float rotationY = buffer.readFloat(); + float rotationZ = buffer.readFloat(); + float shadowElevation = buffer.readFloat(); + float transformOriginX = buffer.readFloat(); + float transformOriginY = buffer.readFloat(); + float alpha = buffer.readFloat(); + float cameraDistance = buffer.readFloat(); + int blendMode = buffer.readInt(); + int spotShadowColorId = buffer.readInt(); + int ambientShadowColorId = buffer.readInt(); + int colorFilterId = buffer.readInt(); + int renderEffectId = buffer.readInt(); + operations.add( + new GraphicsLayerModifierOperation( + scaleX, + scaleY, + rotationX, + rotationY, + rotationZ, + shadowElevation, + transformOriginX, + transformOriginY, + alpha, + cameraDistance, + blendMode, + spotShadowColorId, + ambientShadowColorId, + colorFilterId, + renderEffectId)); + } + + public static void documentation(DocumentationBuilder doc) { + doc.operation("Modifier Operations", OP_CODE, CLASS_NAME) + .description("define the GraphicsLayer Modifier") + .field(FLOAT, "scaleX", "") + .field(FLOAT, "scaleY", "") + .field(FLOAT, "rotationX", "") + .field(FLOAT, "rotationY", "") + .field(FLOAT, "rotationZ", "") + .field(FLOAT, "shadowElevation", "") + .field(FLOAT, "transformOriginX", "") + .field(FLOAT, "transformOriginY", "") + .field(FLOAT, "alpha", "") + .field(FLOAT, "cameraDistance", "") + .field(INT, "blendMode", "") + .field(INT, "spotShadowColorId", "") + .field(INT, "ambientShadowColorId", "") + .field(INT, "colorFilterId", "") + .field(INT, "renderEffectId", ""); + } + + @Override + public void layout(RemoteContext context, float width, float height) {} +} diff --git a/core/java/com/android/internal/widget/remotecompose/core/operations/layout/modifiers/HeightModifierOperation.java b/core/java/com/android/internal/widget/remotecompose/core/operations/layout/modifiers/HeightModifierOperation.java index d3613f84498133eccdbbbfbc064fb154ce0f3089..97c76c0aedf7343dacb4b7d2b43c93a43f9039fd 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 @@ -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.WireBuffer; @@ -30,6 +32,7 @@ public class HeightModifierOperation extends DimensionModifierOperation { private static final int OP_CODE = Operations.MODIFIER_HEIGHT; public static final String CLASS_NAME = "HeightModifierOperation"; + @NonNull public static String name() { return CLASS_NAME; } @@ -38,13 +41,13 @@ public class HeightModifierOperation extends DimensionModifierOperation { return OP_CODE; } - public static void apply(WireBuffer buffer, int type, float value) { + public static void apply(@NonNull WireBuffer buffer, int type, float value) { buffer.start(OP_CODE); buffer.writeInt(type); buffer.writeFloat(value); } - public static void read(WireBuffer buffer, List operations) { + public static void read(@NonNull WireBuffer buffer, @NonNull List operations) { Type type = Type.fromInt(buffer.readInt()); float value = buffer.readFloat(); Operation op = new HeightModifierOperation(type, value); @@ -52,7 +55,7 @@ public class HeightModifierOperation extends DimensionModifierOperation { } @Override - public void write(WireBuffer buffer) { + public void write(@NonNull WireBuffer buffer) { apply(buffer, mType.ordinal(), mValue); } @@ -68,17 +71,19 @@ public class HeightModifierOperation extends DimensionModifierOperation { super(value); } + @NonNull @Override public String toString() { - return "Height(" + mValue + ")"; + return "Height(" + mType + ", " + mValue + ")"; } + @NonNull @Override public String serializedName() { return "HEIGHT"; } - public static void documentation(DocumentationBuilder doc) { + public static void documentation(@NonNull DocumentationBuilder doc) { doc.operation("Modifier Operations", OP_CODE, CLASS_NAME) .description("define the animation") .field(INT, "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 ac42470a6f8f8870acc2d94e4af89dd37afd13c2..836321fff8e6d93ed5023c291ef2d72789bb7bbf 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 @@ -17,6 +17,9 @@ 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; import com.android.internal.widget.remotecompose.core.Operations; @@ -39,6 +42,7 @@ public class HostActionOperation implements ActionOperation { mActionId = id; } + @NonNull @Override public String toString() { return "HostActionOperation(" + mActionId + ")"; @@ -48,20 +52,22 @@ public class HostActionOperation implements ActionOperation { return mActionId; } + @NonNull public String serializedName() { return "HOST_ACTION"; } @Override - public void serializeToString(int indent, StringSerializer serializer) { + public void serializeToString(int indent, @NonNull StringSerializer serializer) { serializer.append(indent, serializedName() + " = " + mActionId); } @Override public void apply(RemoteContext context) {} + @NonNull @Override - public String deepToString(String indent) { + public String deepToString(@Nullable String indent) { return (indent != null ? indent : "") + toString(); } @@ -70,21 +76,25 @@ public class HostActionOperation implements ActionOperation { @Override public void runAction( - RemoteContext context, CoreDocument document, Component component, float x, float y) { + @NonNull RemoteContext context, + CoreDocument document, + Component component, + float x, + float y) { context.runAction(mActionId, ""); } - public static void apply(WireBuffer buffer, int actionId) { + public static void apply(@NonNull WireBuffer buffer, int actionId) { buffer.start(OP_CODE); buffer.writeInt(actionId); } - public static void read(WireBuffer buffer, List operations) { + public static void read(@NonNull WireBuffer buffer, @NonNull List operations) { int actionId = buffer.readInt(); operations.add(new HostActionOperation(actionId)); } - public static void documentation(DocumentationBuilder doc) { + public static void documentation(@NonNull DocumentationBuilder doc) { doc.operation("Layout Operations", OP_CODE, "HostAction") .description("Host action. This operation represents a host action") .field(INT, "ACTION_ID", "Host Action ID"); 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 b674a582fc14dd66ce30c6f013d13fcec792c7a5..e97e89784a230baeb2fd467d6d8b0b068f3b2408 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 @@ -17,6 +17,9 @@ 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; import com.android.internal.widget.remotecompose.core.Operations; @@ -33,31 +36,47 @@ import java.util.List; public class HostNamedActionOperation implements ActionOperation { private static final int OP_CODE = Operations.HOST_NAMED_ACTION; + 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 NONE_TYPE = -1; + int mTextId = -1; + int mType = NONE_TYPE; + int mValueId = -1; - public HostNamedActionOperation(int id) { + public HostNamedActionOperation(int id, int type, int valueId) { mTextId = id; + mType = type; + mValueId = valueId; } + @NonNull @Override public String toString() { - return "HostNamedActionOperation(" + mTextId + ")"; + return "HostNamedActionOperation(" + mTextId + " : " + mValueId + ")"; } + @NonNull public String serializedName() { return "HOST_NAMED_ACTION"; } @Override - public void serializeToString(int indent, StringSerializer serializer) { - serializer.append(indent, serializedName() + " = " + mTextId); + public void serializeToString(int indent, @NonNull StringSerializer serializer) { + if (mValueId != -1) { + serializer.append(indent, serializedName() + " = " + mTextId + " : " + mValueId); + } else { + serializer.append(indent, serializedName() + " = " + mTextId); + } } @Override public void apply(RemoteContext context) {} + @NonNull @Override - public String deepToString(String indent) { + public String deepToString(@Nullable String indent) { return (indent != null ? indent : "") + toString(); } @@ -66,23 +85,42 @@ public class HostNamedActionOperation implements ActionOperation { @Override public void runAction( - RemoteContext context, CoreDocument document, Component component, float x, float y) { - context.runNamedAction(mTextId); + @NonNull RemoteContext context, + CoreDocument document, + Component component, + float x, + float y) { + Object value = null; + if (mValueId != -1) { + if (mType == INT_TYPE) { + value = context.mRemoteComposeState.getInteger(mValueId); + } else if (mType == STRING_TYPE) { + value = context.mRemoteComposeState.getFromId(mValueId); + } else if (mType == FLOAT_TYPE) { + value = context.mRemoteComposeState.getFloat(mValueId); + } + } + context.runNamedAction(mTextId, value); } - public static void apply(WireBuffer buffer, int textId) { + public static void apply(@NonNull WireBuffer buffer, int textId, int type, int valueId) { buffer.start(OP_CODE); buffer.writeInt(textId); + buffer.writeInt(type); + buffer.writeInt(valueId); } - public static void read(WireBuffer buffer, List operations) { + public static void read(@NonNull WireBuffer buffer, @NonNull List operations) { int textId = buffer.readInt(); - operations.add(new HostNamedActionOperation(textId)); + int type = buffer.readInt(); + int valueId = buffer.readInt(); + operations.add(new HostNamedActionOperation(textId, type, valueId)); } - public static void documentation(DocumentationBuilder doc) { + public static void documentation(@NonNull DocumentationBuilder doc) { doc.operation("Layout Operations", OP_CODE, "HostNamedAction") .description("Host Named action. This operation represents a host action") - .field(INT, "TEXT_ID", "Named Host Action Text ID"); + .field(INT, "TEXT_ID", "Named Host Action Text ID") + .field(INT, "VALUE_ID", "Named Host Action Value ID"); } } 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 new file mode 100644 index 0000000000000000000000000000000000000000..65fe345ac920aa3471aaade1516fc86dd930b447 --- /dev/null +++ b/core/java/com/android/internal/widget/remotecompose/core/operations/layout/modifiers/OffsetModifierOperation.java @@ -0,0 +1,119 @@ +/* + * Copyright (C) 2024 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.android.internal.widget.remotecompose.core.operations.layout.modifiers; + +import static com.android.internal.widget.remotecompose.core.documentation.DocumentedOperation.FLOAT; + +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.utilities.StringSerializer; + +import java.util.List; + +/** Represents an offset modifier. */ +public class OffsetModifierOperation extends DecoratorModifierOperation { + private static final int OP_CODE = Operations.MODIFIER_OFFSET; + public static final String CLASS_NAME = "OffsetModifierOperation"; + + float mX; + float mY; + + public OffsetModifierOperation(float x, float y) { + this.mX = x; + this.mY = y; + } + + public float getX() { + return mX; + } + + public float getY() { + return mY; + } + + public void setX(float x) { + this.mX = x; + } + + public void setY(float y) { + this.mY = y; + } + + @Override + public void write(WireBuffer buffer) { + apply(buffer, mX, mY); + } + + // @Override + public void serializeToString(int indent, StringSerializer serializer) { + serializer.append(indent, "OFFSET = [" + mX + ", " + mY + "]"); + } + + @Override + public String deepToString(String indent) { + return (indent != null ? indent : "") + toString(); + } + + @Override + public void paint(PaintContext context) { + float x = context.getContext().mRemoteComposeState.getFloat(Utils.idFromNan(mX)); + float y = context.getContext().mRemoteComposeState.getFloat(Utils.idFromNan(mY)); + float density = context.getContext().getDensity(); + x *= density; + y *= density; + context.translate(x, y); + } + + @Override + public String toString() { + return "OffsetModifierOperation(" + mX + ", " + mY + ")"; + } + + public static String name() { + return CLASS_NAME; + } + + public static int id() { + return OP_CODE; + } + + public static void apply(WireBuffer buffer, float x, float y) { + buffer.start(OP_CODE); + buffer.writeFloat(x); + buffer.writeFloat(y); + } + + public static void read(WireBuffer buffer, List operations) { + float x = buffer.readFloat(); + float y = buffer.readFloat(); + operations.add(new OffsetModifierOperation(x, y)); + } + + public static void documentation(DocumentationBuilder doc) { + doc.operation("Modifier Operations", OP_CODE, CLASS_NAME) + .description("define the Offset Modifier") + .field(FLOAT, "x", "") + .field(FLOAT, "y", ""); + } + + @Override + public void layout(RemoteContext context, float width, float height) {} +} diff --git a/core/java/com/android/internal/widget/remotecompose/core/operations/layout/modifiers/PaddingModifierOperation.java b/core/java/com/android/internal/widget/remotecompose/core/operations/layout/modifiers/PaddingModifierOperation.java index e0ec1a60ef7edd0f7bbd58c2d0f0c06d701704df..ed5522ea865f8dbc2bfb1952c1189adb2d71c412 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 @@ -17,6 +17,9 @@ 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; import com.android.internal.widget.remotecompose.core.RemoteContext; @@ -78,12 +81,12 @@ public class PaddingModifierOperation implements ModifierOperation { } @Override - public void write(WireBuffer buffer) { + public void write(@NonNull WireBuffer buffer) { apply(buffer, mLeft, mTop, mRight, mBottom); } @Override - public void serializeToString(int indent, StringSerializer serializer) { + public void serializeToString(int indent, @NonNull StringSerializer serializer) { serializer.append( indent, "PADDING = [" + mLeft + ", " + mTop + ", " + mRight + ", " + mBottom + "]"); } @@ -91,11 +94,13 @@ public class PaddingModifierOperation implements ModifierOperation { @Override public void apply(RemoteContext context) {} + @NonNull @Override - public String deepToString(String indent) { + public String deepToString(@Nullable String indent) { return (indent != null ? indent : "") + toString(); } + @NonNull @Override public String toString() { return "PaddingModifierOperation(" @@ -109,6 +114,7 @@ public class PaddingModifierOperation implements ModifierOperation { + ")"; } + @NonNull public static String name() { return CLASS_NAME; } @@ -117,7 +123,8 @@ public class PaddingModifierOperation implements ModifierOperation { return Operations.MODIFIER_PADDING; } - public static void apply(WireBuffer buffer, float left, float top, float right, float bottom) { + public static void apply( + @NonNull WireBuffer buffer, float left, float top, float right, float bottom) { buffer.start(Operations.MODIFIER_PADDING); buffer.writeFloat(left); buffer.writeFloat(top); @@ -125,7 +132,7 @@ public class PaddingModifierOperation implements ModifierOperation { buffer.writeFloat(bottom); } - public static void read(WireBuffer buffer, List operations) { + public static void read(@NonNull WireBuffer buffer, @NonNull List operations) { float left = buffer.readFloat(); float top = buffer.readFloat(); float right = buffer.readFloat(); @@ -133,7 +140,7 @@ public class PaddingModifierOperation implements ModifierOperation { operations.add(new PaddingModifierOperation(left, top, right, bottom)); } - public static void documentation(DocumentationBuilder doc) { + public static void documentation(@NonNull DocumentationBuilder doc) { doc.operation("Modifier Operations", OP_CODE, CLASS_NAME) .description("define the Padding Modifier") .field(FLOAT, "left", "") 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 dc95fe7774aa168251dfacdb29ec38479aaea702..6218dd5f331110ab413a5b90a7c61e18ecea713f 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 @@ -17,7 +17,8 @@ package com.android.internal.widget.remotecompose.core.operations.layout.modifie import static com.android.internal.widget.remotecompose.core.documentation.DocumentedOperation.FLOAT; -import com.android.internal.widget.remotecompose.core.CoreDocument; +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; @@ -25,7 +26,6 @@ import com.android.internal.widget.remotecompose.core.RemoteContext; import com.android.internal.widget.remotecompose.core.WireBuffer; import com.android.internal.widget.remotecompose.core.documentation.DocumentationBuilder; import com.android.internal.widget.remotecompose.core.operations.DrawBase4; -import com.android.internal.widget.remotecompose.core.operations.layout.Component; import com.android.internal.widget.remotecompose.core.operations.layout.DecoratorComponent; import com.android.internal.widget.remotecompose.core.operations.utilities.StringSerializer; @@ -37,7 +37,7 @@ public class RoundedClipRectModifierOperation extends DrawBase4 public static final int OP_CODE = Operations.MODIFIER_ROUNDED_CLIP_RECT; public static final String CLASS_NAME = "RoundedClipRectModifierOperation"; - public static void read(WireBuffer buffer, List operations) { + public static void read(@NonNull WireBuffer buffer, @NonNull List operations) { Maker m = RoundedClipRectModifierOperation::new; read(m, buffer, operations); } @@ -46,16 +46,17 @@ public class RoundedClipRectModifierOperation extends DrawBase4 return OP_CODE; } + @NonNull public static String name() { return CLASS_NAME; } @Override - protected void write(WireBuffer buffer, float v1, float v2, float v3, float v4) { + protected void write(@NonNull WireBuffer buffer, float v1, float v2, float v3, float v4) { apply(buffer, v1, v2, v3, v4); } - public static void documentation(DocumentationBuilder doc) { + public static void documentation(@NonNull DocumentationBuilder doc) { doc.operation("Modifier Operations", id(), "RoundedClipRectModifierOperation") .description("clip with rectangle") .field( @@ -90,7 +91,7 @@ public class RoundedClipRectModifierOperation extends DrawBase4 } @Override - public void paint(PaintContext context) { + public void paint(@NonNull PaintContext context) { context.roundedClipRect(mWidth, mHeight, mX1, mY1, mX2, mY2); } @@ -101,13 +102,7 @@ public class RoundedClipRectModifierOperation extends DrawBase4 } @Override - public void onClick( - RemoteContext context, CoreDocument document, Component component, float x, float y) { - // nothing - } - - @Override - public void serializeToString(int indent, StringSerializer serializer) { + public void serializeToString(int indent, @NonNull StringSerializer serializer) { serializer.append( indent, "ROUNDED_CLIP_RECT = [" @@ -135,7 +130,11 @@ public class RoundedClipRectModifierOperation extends DrawBase4 * @param bottomEnd bottomEnd radius */ public static void apply( - WireBuffer buffer, float topStart, float topEnd, float bottomStart, float bottomEnd) { + @NonNull WireBuffer buffer, + float topStart, + float topEnd, + float bottomStart, + float bottomEnd) { write(buffer, OP_CODE, topStart, topEnd, bottomStart, bottomEnd); } } 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 new file mode 100644 index 0000000000000000000000000000000000000000..29ec82810a7c679b537408f915a2a502577597cb --- /dev/null +++ b/core/java/com/android/internal/widget/remotecompose/core/operations/layout/modifiers/ValueFloatChangeActionOperation.java @@ -0,0 +1,97 @@ +/* + * Copyright (C) 2024 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.android.internal.widget.remotecompose.core.operations.layout.modifiers; + +import static com.android.internal.widget.remotecompose.core.documentation.DocumentedOperation.FLOAT; +import static com.android.internal.widget.remotecompose.core.documentation.DocumentedOperation.INT; + +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 float variable. */ +public class ValueFloatChangeActionOperation implements ActionOperation { + private static final int OP_CODE = Operations.VALUE_FLOAT_CHANGE_ACTION; + + int mTargetValueId = -1; + float mValue = -1; + + public ValueFloatChangeActionOperation(int id, float value) { + mTargetValueId = id; + mValue = value; + } + + @Override + public String toString() { + return "ValueFloatChangeActionOperation(" + mTargetValueId + ")"; + } + + public String serializedName() { + return "VALUE_FLOAT_CHANGE"; + } + + @Override + public void serializeToString(int indent, StringSerializer serializer) { + serializer.append(indent, serializedName() + " = " + mTargetValueId + " -> " + mValue); + } + + @Override + public void apply(RemoteContext context) {} + + @Override + public String deepToString(String indent) { + return (indent != null ? indent : "") + toString(); + } + + @Override + public void write(WireBuffer buffer) {} + + @Override + public void runAction( + RemoteContext context, CoreDocument document, Component component, float x, float y) { + System.out.println("OVERRIDE " + mTargetValueId + " TO " + mValue); + context.overrideFloat(mTargetValueId, mValue); + } + + public static void apply(WireBuffer buffer, int valueId, float value) { + buffer.start(OP_CODE); + buffer.writeInt(valueId); + buffer.writeFloat(value); + } + + public static void read(WireBuffer buffer, List operations) { + int valueId = buffer.readInt(); + float value = buffer.readFloat(); + operations.add(new ValueFloatChangeActionOperation(valueId, value)); + } + + public static void documentation(DocumentationBuilder doc) { + doc.operation("Layout Operations", OP_CODE, "ValueFloatChangeActionOperation") + .description( + "ValueIntegerChange action. " + + " This operation represents a value change for the given id") + .field(INT, "TARGET_VALUE_ID", "Value ID") + .field(FLOAT, "VALUE", "float 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 8876720c999034b3c49285a71f86f60ff60d51f0..d7ce8acc72bfdb8ff9f8b3eb4659b90ce10dd9d9 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 @@ -17,6 +17,9 @@ 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; import com.android.internal.widget.remotecompose.core.Operations; @@ -41,25 +44,28 @@ public class ValueIntegerChangeActionOperation implements ActionOperation { mValue = value; } + @NonNull @Override public String toString() { return "ValueChangeActionOperation(" + mTargetValueId + ")"; } + @NonNull public String serializedName() { return "VALUE_INTEGER_CHANGE"; } @Override - public void serializeToString(int indent, StringSerializer serializer) { + public void serializeToString(int indent, @NonNull StringSerializer serializer) { serializer.append(indent, serializedName() + " = " + mTargetValueId + " -> " + mValue); } @Override public void apply(RemoteContext context) {} + @NonNull @Override - public String deepToString(String indent) { + public String deepToString(@Nullable String indent) { return (indent != null ? indent : "") + toString(); } @@ -68,23 +74,27 @@ public class ValueIntegerChangeActionOperation implements ActionOperation { @Override public void runAction( - RemoteContext context, CoreDocument document, Component component, float x, float y) { + @NonNull RemoteContext context, + CoreDocument document, + Component component, + float x, + float y) { context.overrideInteger(mTargetValueId, mValue); } - public static void apply(WireBuffer buffer, int valueId, int value) { + 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(WireBuffer buffer, List operations) { + public static void read(@NonNull WireBuffer buffer, @NonNull List operations) { int valueId = buffer.readInt(); int value = buffer.readInt(); operations.add(new ValueIntegerChangeActionOperation(valueId, value)); } - public static void documentation(DocumentationBuilder doc) { + public static void documentation(@NonNull DocumentationBuilder doc) { doc.operation("Layout Operations", OP_CODE, "ValueIntegerChangeActionOperation") .description( "ValueIntegerChange action. " 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 fb5e911e8bc6b6923714fd7c2c692403852da5d1..75d13e785d4c49c4c5e644ccfbc1135666dce59a 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 @@ -17,6 +17,9 @@ 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; import com.android.internal.widget.remotecompose.core.Operations; @@ -41,17 +44,19 @@ public class ValueIntegerExpressionChangeActionOperation implements ActionOperat mValueExpressionId = value; } + @NonNull @Override public String toString() { return "ValueIntegerExpressionChangeActionOperation(" + mTargetValueId + ")"; } + @NonNull public String serializedName() { return "VALUE_INTEGER_EXPRESSION_CHANGE"; } @Override - public void serializeToString(int indent, StringSerializer serializer) { + public void serializeToString(int indent, @NonNull StringSerializer serializer) { serializer.append( indent, serializedName() + " = " + mTargetValueId + " -> " + mValueExpressionId); } @@ -59,8 +64,9 @@ public class ValueIntegerExpressionChangeActionOperation implements ActionOperat @Override public void apply(RemoteContext context) {} + @NonNull @Override - public String deepToString(String indent) { + public String deepToString(@Nullable String indent) { return (indent != null ? indent : "") + toString(); } @@ -69,23 +75,27 @@ public class ValueIntegerExpressionChangeActionOperation implements ActionOperat @Override public void runAction( - RemoteContext context, CoreDocument document, Component component, float x, float y) { + @NonNull RemoteContext context, + @NonNull CoreDocument document, + Component component, + float x, + float y) { document.evaluateIntExpression(mValueExpressionId, (int) mTargetValueId, context); } - public static void apply(WireBuffer buffer, long valueId, long value) { + public static void apply(@NonNull WireBuffer buffer, long valueId, long value) { buffer.start(OP_CODE); buffer.writeLong(valueId); buffer.writeLong(value); } - public static void read(WireBuffer buffer, List operations) { + public static void read(@NonNull WireBuffer buffer, @NonNull List operations) { long valueId = buffer.readLong(); long value = buffer.readLong(); operations.add(new ValueIntegerExpressionChangeActionOperation(valueId, value)); } - public static void documentation(DocumentationBuilder doc) { + public static void documentation(@NonNull DocumentationBuilder doc) { doc.operation("Layout Operations", OP_CODE, "ValueIntegerExpressionChangeActionOperation") .description( "ValueIntegerExpressionChange action. " 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 a64a492a8cc1f559d1ddd6c34bba56a1a982ddd2..26d7244eee8c95c5a76707a23e095b30357fc306 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 @@ -17,6 +17,9 @@ 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; import com.android.internal.widget.remotecompose.core.Operations; @@ -41,6 +44,7 @@ public class ValueStringChangeActionOperation implements ActionOperation { mValueId = value; } + @NonNull @Override public String toString() { return "ValueChangeActionOperation(" + mTargetValueId + ")"; @@ -50,20 +54,22 @@ public class ValueStringChangeActionOperation implements ActionOperation { return mTargetValueId; } + @NonNull public String serializedName() { return "VALUE_CHANGE"; } @Override - public void serializeToString(int indent, StringSerializer serializer) { + public void serializeToString(int indent, @NonNull StringSerializer serializer) { serializer.append(indent, serializedName() + " = " + mTargetValueId + " -> " + mValueId); } @Override public void apply(RemoteContext context) {} + @NonNull @Override - public String deepToString(String indent) { + public String deepToString(@Nullable String indent) { return (indent != null ? indent : "") + toString(); } @@ -72,23 +78,27 @@ public class ValueStringChangeActionOperation implements ActionOperation { @Override public void runAction( - RemoteContext context, CoreDocument document, Component component, float x, float y) { + @NonNull RemoteContext context, + CoreDocument document, + Component component, + float x, + float y) { context.overrideText(mTargetValueId, mValueId); } - public static void apply(WireBuffer buffer, int valueId, int value) { + 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(WireBuffer buffer, List operations) { + public static void read(@NonNull WireBuffer buffer, @NonNull List operations) { int valueId = buffer.readInt(); int value = buffer.readInt(); operations.add(new ValueStringChangeActionOperation(valueId, value)); } - public static void documentation(DocumentationBuilder doc) { + public static void documentation(@NonNull DocumentationBuilder doc) { doc.operation("Layout Operations", OP_CODE, "ValueStringChangeActionOperation") .description( "ValueStrin gChange action. " 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 62403b3e5e7e7511e013161b34f510eeaef4ab5f..e2f899ce2b462535eab01a063bb274544572228b 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 @@ -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.WireBuffer; @@ -30,6 +32,7 @@ public class WidthModifierOperation extends DimensionModifierOperation { private static final int OP_CODE = Operations.MODIFIER_WIDTH; public static final String CLASS_NAME = "WidthModifierOperation"; + @NonNull public static String name() { return CLASS_NAME; } @@ -38,13 +41,13 @@ public class WidthModifierOperation extends DimensionModifierOperation { return OP_CODE; } - public static void apply(WireBuffer buffer, int type, float value) { + public static void apply(@NonNull WireBuffer buffer, int type, float value) { buffer.start(OP_CODE); buffer.writeInt(type); buffer.writeFloat(value); } - public static void read(WireBuffer buffer, List operations) { + public static void read(@NonNull WireBuffer buffer, @NonNull List operations) { Type type = Type.fromInt(buffer.readInt()); float value = buffer.readFloat(); Operation op = new WidthModifierOperation(type, value); @@ -56,7 +59,7 @@ public class WidthModifierOperation extends DimensionModifierOperation { } @Override - public void write(WireBuffer buffer) { + public void write(@NonNull WireBuffer buffer) { apply(buffer, mType.ordinal(), mValue); } @@ -68,17 +71,19 @@ public class WidthModifierOperation extends DimensionModifierOperation { super(value); } + @NonNull @Override public String toString() { - return "Width(" + mValue + ")"; + return "Width(" + mType + ", " + mValue + ")"; } + @NonNull @Override public String serializedName() { return "WIDTH"; } - public static void documentation(DocumentationBuilder doc) { + public static void documentation(@NonNull DocumentationBuilder doc) { doc.operation("Modifier Operations", OP_CODE, CLASS_NAME) .description("define the animation") .field(INT, "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 new file mode 100644 index 0000000000000000000000000000000000000000..aa20e0388d31b305fcc88802022690ad649475c9 --- /dev/null +++ b/core/java/com/android/internal/widget/remotecompose/core/operations/layout/modifiers/ZIndexModifierOperation.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.FLOAT; + +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.utilities.StringSerializer; + +import java.util.List; + +/** Represents a ZIndex modifier, allowing to change the z-index of a component. */ +public class ZIndexModifierOperation extends DecoratorModifierOperation { + private static final int OP_CODE = Operations.MODIFIER_ZINDEX; + public static final String CLASS_NAME = "ZIndexModifierOperation"; + float mValue; + float mCurrentValue; + + public ZIndexModifierOperation(float value) { + this.mValue = value; + } + + public float getValue() { + return mCurrentValue; + } + + public void setmValue(float value) { + this.mValue = value; + } + + @Override + public void write(WireBuffer buffer) { + apply(buffer, mValue); + } + + // @Override + public void serializeToString(int indent, StringSerializer serializer) { + serializer.append(indent, "ZINDEX = [" + mValue + "]"); + } + + @Override + public String deepToString(String indent) { + return (indent != null ? indent : "") + toString(); + } + + @Override + public void paint(PaintContext context) { + mCurrentValue = mValue; + if (Utils.isVariable(mValue)) { + mCurrentValue = + context.getContext().mRemoteComposeState.getFloat(Utils.idFromNan(mValue)); + } + } + + @Override + public String toString() { + return "ZIndexModifierOperation(" + mValue + ")"; + } + + public static String name() { + return CLASS_NAME; + } + + public static int id() { + return OP_CODE; + } + + public static void apply(WireBuffer buffer, float value) { + buffer.start(OP_CODE); + buffer.writeFloat(value); + } + + public static void read(WireBuffer buffer, List operations) { + float value = buffer.readFloat(); + operations.add(new ZIndexModifierOperation(value)); + } + + public static void documentation(DocumentationBuilder doc) { + doc.operation("Modifier Operations", OP_CODE, CLASS_NAME) + .description("define the Z-Index Modifier") + .field(FLOAT, "value", ""); + } + + @Override + public void layout(RemoteContext context, float width, float height) {} +} 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 4849b12c65b101de930da96c3cf4fb6505a2c8c0..d8e49b0a9ccd3438107a97cc2291fca4dc08b6c3 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 @@ -15,6 +15,9 @@ */ package com.android.internal.widget.remotecompose.core.operations.layout.utils; +import android.annotation.NonNull; +import android.annotation.Nullable; + import java.util.ArrayList; /** Internal utility debug class */ @@ -23,12 +26,12 @@ public class DebugLog { public static final boolean DEBUG_LAYOUT_ON = false; public static class Node { - public Node parent; + @Nullable public Node parent; public String name; public String endString; - public ArrayList list = new ArrayList<>(); + @NonNull public ArrayList list = new ArrayList<>(); - public Node(Node parent, String name) { + public Node(@Nullable Node parent, String name) { this.parent = parent; this.name = name; this.endString = name + " DONE"; @@ -48,21 +51,21 @@ public class DebugLog { } } - public static Node node = new Node(null, "Root"); - public static Node currentNode = node; + @NonNull public static Node node = new Node(null, "Root"); + @NonNull public static Node currentNode = node; public static void clear() { node = new Node(null, "Root"); currentNode = node; } - public static void s(StringValueSupplier valueSupplier) { + public static void s(@NonNull StringValueSupplier valueSupplier) { if (DEBUG_LAYOUT_ON) { currentNode = new Node(currentNode, valueSupplier.getString()); } } - public static void log(StringValueSupplier valueSupplier) { + public static void log(@NonNull StringValueSupplier valueSupplier) { if (DEBUG_LAYOUT_ON) { new LogNode(currentNode, valueSupplier.getString()); } @@ -78,7 +81,7 @@ public class DebugLog { } } - public static void e(StringValueSupplier valueSupplier) { + public static void e(@NonNull StringValueSupplier valueSupplier) { if (DEBUG_LAYOUT_ON) { currentNode.endString = valueSupplier.getString(); if (currentNode.parent != null) { @@ -89,7 +92,7 @@ public class DebugLog { } } - public static void printNode(int indent, Node node, StringBuilder builder) { + public static void printNode(int indent, @NonNull Node node, @NonNull StringBuilder builder) { if (DEBUG_LAYOUT_ON) { StringBuilder indentationBuilder = new StringBuilder(); for (int i = 0; i < indent; i++) { 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 9a3cd54c3f851418535c2e1bdb5e57f6d553d608..a808cf0e17b360861944edb09972b6fcec25cf3b 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 @@ -15,6 +15,8 @@ */ package com.android.internal.widget.remotecompose.core.operations.paint; +import android.annotation.NonNull; + /** Provides a Builder pattern for a PaintBundle */ class Painter { PaintBundle mPaint; @@ -24,16 +26,19 @@ class Painter { return mPaint; } + @NonNull public Painter setAntiAlias(boolean aa) { mPaint.setAntiAlias(aa); return this; } + @NonNull public Painter setColor(int color) { mPaint.setColor(color); return this; } + @NonNull public Painter setColorId(int colorId) { mPaint.setColorId(colorId); return this; @@ -44,6 +49,7 @@ class Painter { * * @param join set the paint's Join, used whenever the paint's style is Stroke or StrokeAndFill. */ + @NonNull public Painter setStrokeJoin(int join) { mPaint.setStrokeJoin(join); return this; @@ -56,6 +62,7 @@ class Painter { * @param width set the paint's stroke width, used whenever the paint's style is Stroke or * StrokeAndFill. */ + @NonNull public Painter setStrokeWidth(float width) { mPaint.setStrokeWidth(width); return this; @@ -67,6 +74,7 @@ class Painter { * * @param style The new style to set in the paint */ + @NonNull public Painter setStyle(int style) { mPaint.setStyle(style); return this; @@ -78,6 +86,7 @@ class Painter { * @param cap set the paint's line cap style, used whenever the paint's style is Stroke or * StrokeAndFill. */ + @NonNull public Painter setStrokeCap(int cap) { mPaint.setStrokeCap(cap); return this; @@ -90,6 +99,7 @@ class Painter { * @param miter set the miter limit on the paint, used whenever the paint's style is Stroke or * StrokeAndFill. */ + @NonNull public Painter setStrokeMiter(float miter) { mPaint.setStrokeMiter(miter); return this; @@ -101,6 +111,7 @@ class Painter { * * @param alpha set the alpha component [0..1.0] of the paint's color. */ + @NonNull public Painter setAlpha(float alpha) { mPaint.setAlpha((alpha > 2) ? alpha / 255f : alpha); return this; @@ -112,6 +123,7 @@ class Painter { * @param color The ARGB source color used with the specified Porter-Duff mode * @param mode The porter-duff mode that is applied */ + @NonNull public Painter setPorterDuffColorFilter(int color, int mode) { mPaint.setColorFilter(color, mode); return this; @@ -130,6 +142,7 @@ class Painter { * line. * @param tileMode The Shader tiling mode */ + @NonNull public Painter setLinearGradient( float startX, float startY, @@ -155,6 +168,7 @@ class Painter { * circle. * @param tileMode The Shader tiling mode */ + @NonNull public Painter setRadialGradient( float centerX, float centerY, @@ -178,6 +192,7 @@ class Painter { * may produce unexpected results. If positions is NULL, then the colors are automatically * spaced evenly. */ + @NonNull public Painter setSweepGradient(float centerX, float centerY, int[] colors, float[] positions) { mPaint.setSweepGradient(colors, 0, positions, centerX, centerY); return this; @@ -188,6 +203,7 @@ class Painter { * * @param size set the paint's text size in pixel units. */ + @NonNull public Painter setTextSize(float size) { mPaint.setTextSize(size); return this; @@ -215,16 +231,19 @@ class Painter { * @param weight The desired weight to be drawn. * @param italic {@code true} if italic style is desired to be drawn. Otherwise, {@code false} */ + @NonNull public Painter setTypeface(int fontType, int weight, boolean italic) { mPaint.setTextStyle(fontType, weight, italic); return this; } + @NonNull public Painter setFilterBitmap(boolean filter) { mPaint.setFilterBitmap(filter); return this; } + @NonNull public Painter setShader(int id) { mPaint.setShader(id); return this; 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 1d673c4c5ab6b01435aa67a8201d555171a08206..b25f4cd3c5304c17dc85dfd732eeea09dee0c3e9 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 @@ -15,11 +15,12 @@ */ package com.android.internal.widget.remotecompose.core.operations.utilities; -/** - * high performance floating point expression evaluator used in animation - */ +import android.annotation.NonNull; +import android.annotation.Nullable; + +/** high performance floating point expression evaluator used in animation */ public class AnimatedFloatExpression { - static IntMap sNames = new IntMap<>(); + @NonNull static IntMap sNames = new IntMap<>(); public static final int OFFSET = 0x310_000; public static final float ADD = asNan(OFFSET + 1); public static final float SUB = asNan(OFFSET + 2); @@ -74,7 +75,7 @@ public class AnimatedFloatExpression { private static final float FP_TO_DEG = 0.017453292f; // 180/PI float[] mStack; - float[] mLocalStack = new float[128]; + @NonNull float[] mLocalStack = new float[128]; float[] mVar; CollectionsAccess mCollectionsAccess; @@ -201,7 +202,7 @@ public class AnimatedFloatExpression { * @param var * @return */ - public float eval(float[] exp, int len, float... var) { + public float eval(@NonNull float[] exp, int len, float... var) { System.arraycopy(exp, 0, mLocalStack, 0, len); mStack = mLocalStack; mVar = var; @@ -224,7 +225,7 @@ public class AnimatedFloatExpression { * @param var * @return */ - public float evalDB(float[] exp, float... var) { + public float evalDB(@NonNull float[] exp, float... var) { mStack = exp; mVar = var; int sp = -1; @@ -240,195 +241,281 @@ public class AnimatedFloatExpression { return mStack[sp]; } - Op[] mOps = { + @NonNull Op[] mOps; + + { + Op mADD = + (sp) -> { // ADD + mStack[sp - 1] = mStack[sp - 1] + mStack[sp]; + return sp - 1; + }; + Op mSUB = + (sp) -> { // SUB + mStack[sp - 1] = mStack[sp - 1] - mStack[sp]; + return sp - 1; + }; + Op mMUL = + (sp) -> { // MUL + mStack[sp - 1] = mStack[sp - 1] * mStack[sp]; + return sp - 1; + }; + Op mDIV = + (sp) -> { // DIV + mStack[sp - 1] = mStack[sp - 1] / mStack[sp]; + return sp - 1; + }; + Op mMOD = + (sp) -> { // MOD + mStack[sp - 1] = mStack[sp - 1] % mStack[sp]; + return sp - 1; + }; + Op mMIN = + (sp) -> { // MIN + mStack[sp - 1] = (float) Math.min(mStack[sp - 1], mStack[sp]); + return sp - 1; + }; + Op mMAX = + (sp) -> { // MAX + mStack[sp - 1] = (float) Math.max(mStack[sp - 1], mStack[sp]); + return sp - 1; + }; + Op mPOW = + (sp) -> { // POW + mStack[sp - 1] = (float) Math.pow(mStack[sp - 1], mStack[sp]); + return sp - 1; + }; + Op mSQRT = + (sp) -> { // SQRT + mStack[sp] = (float) Math.sqrt(mStack[sp]); + return sp; + }; + Op mABS = + (sp) -> { // ABS + mStack[sp] = (float) Math.abs(mStack[sp]); + return sp; + }; + Op mSIGN = + (sp) -> { // SIGN + mStack[sp] = (float) Math.signum(mStack[sp]); + return sp; + }; + Op mCOPY_SIGN = + (sp) -> { // copySign + mStack[sp - 1] = (float) Math.copySign(mStack[sp - 1], mStack[sp]); + return sp - 1; + }; + Op mEXP = + (sp) -> { // EXP + mStack[sp] = (float) Math.exp(mStack[sp]); + return sp; + }; + Op mFLOOR = + (sp) -> { // FLOOR + mStack[sp] = (float) Math.floor(mStack[sp]); + return sp; + }; + Op mLOG = + (sp) -> { // LOG + mStack[sp] = (float) Math.log10(mStack[sp]); + return sp; + }; + Op mLN = + (sp) -> { // LN + mStack[sp] = (float) Math.log(mStack[sp]); + return sp; + }; + Op mROUND = + (sp) -> { // ROUND + mStack[sp] = (float) Math.round(mStack[sp]); + return sp; + }; + Op mSIN = + (sp) -> { // SIN + mStack[sp] = (float) Math.sin(mStack[sp]); + return sp; + }; + Op mCOS = + (sp) -> { // COS + mStack[sp] = (float) Math.cos(mStack[sp]); + return sp; + }; + Op mTAN = + (sp) -> { // TAN + mStack[sp] = (float) Math.tan(mStack[sp]); + return sp; + }; + Op mASIN = + (sp) -> { // ASIN + mStack[sp] = (float) Math.asin(mStack[sp]); + return sp; + }; + Op mACOS = + (sp) -> { // ACOS + mStack[sp] = (float) Math.acos(mStack[sp]); + return sp; + }; + Op mATAN = + (sp) -> { // ATAN + mStack[sp] = (float) Math.atan(mStack[sp]); + return sp; + }; + Op mATAN2 = + (sp) -> { // ATAN2 + mStack[sp - 1] = (float) Math.atan2(mStack[sp - 1], mStack[sp]); + return sp - 1; + }; + Op mMAD = + (sp) -> { // MAD + mStack[sp - 2] = mStack[sp] + mStack[sp - 1] * mStack[sp - 2]; + return sp - 2; + }; + Op mTERNARY_CONDITIONAL = + (sp) -> { // TERNARY_CONDITIONAL + mStack[sp - 2] = (mStack[sp] > 0) ? mStack[sp - 1] : mStack[sp - 2]; + return sp - 2; + }; + Op mCLAMP = + (sp) -> { // CLAMP + mStack[sp - 2] = Math.min(Math.max(mStack[sp - 2], mStack[sp]), mStack[sp - 1]); + return sp - 2; + }; + Op mCBRT = + (sp) -> { // CBRT + mStack[sp] = (float) Math.pow(mStack[sp], 1 / 3.); + return sp; + }; + Op mDEG = + (sp) -> { // DEG + mStack[sp] = mStack[sp] * FP_TO_RAD; + return sp; + }; + Op mRAD = + (sp) -> { // RAD + mStack[sp] = mStack[sp] * FP_TO_DEG; + return sp; + }; + Op mCEIL = + (sp) -> { // CEIL + mStack[sp] = (float) Math.ceil(mStack[sp]); + return sp; + }; + Op mA_DEREF = + (sp) -> { // A_DEREF + int id = fromNaN(mStack[sp]); + mStack[sp - 1] = mCollectionsAccess.getFloatValue(id, (int) mStack[sp - 1]); + return sp - 1; + }; + Op mA_MAX = + (sp) -> { // A_MAX + int id = fromNaN(mStack[sp]); + float[] array = mCollectionsAccess.getFloats(id); + float max = array[0]; + for (int i = 1; i < array.length; i++) { + max = Math.max(max, array[i]); + } + mStack[sp] = max; + return sp; + }; + Op mA_MIN = + (sp) -> { // A_MIN + int id = fromNaN(mStack[sp]); + float[] array = mCollectionsAccess.getFloats(id); + float max = array[0]; + for (int i = 1; i < array.length; i++) { + max = Math.max(max, array[i]); + } + mStack[sp] = max; + return sp; + }; + Op mA_SUM = + (sp) -> { // A_SUM + int id = fromNaN(mStack[sp]); + float[] array = mCollectionsAccess.getFloats(id); + float sum = 0; + for (int i = 0; i < array.length; i++) { + sum += array[i]; + } + mStack[sp] = sum; + return sp; + }; + Op mA_AVG = + (sp) -> { // A_AVG + int id = fromNaN(mStack[sp]); + float[] array = mCollectionsAccess.getFloats(id); + float sum = 0; + for (int i = 0; i < array.length; i++) { + sum += array[i]; + } + mStack[sp] = sum / array.length; + return sp; + }; + Op mA_LEN = + (sp) -> { // A_LEN + int id = fromNaN(mStack[sp]); + mStack[sp] = mCollectionsAccess.getListLength(id); + return sp; + }; + Op mFIRST_VAR = + (sp) -> { // FIRST_VAR + mStack[sp] = mVar[0]; + return sp; + }; + Op mSECOND_VAR = + (sp) -> { // SECOND_VAR + mStack[sp] = mVar[1]; + return sp; + }; + Op mTHIRD_VAR = + (sp) -> { // THIRD_VAR + mStack[sp] = mVar[2]; + return sp; + }; + + Op[] ops = { null, - (sp) -> { // ADD - mStack[sp - 1] = mStack[sp - 1] + mStack[sp]; - return sp - 1; - }, - (sp) -> { // SUB - mStack[sp - 1] = mStack[sp - 1] - mStack[sp]; - return sp - 1; - }, - (sp) -> { // MUL - mStack[sp - 1] = mStack[sp - 1] * mStack[sp]; - return sp - 1; - }, - (sp) -> { // DIV - mStack[sp - 1] = mStack[sp - 1] / mStack[sp]; - return sp - 1; - }, - (sp) -> { // MOD - mStack[sp - 1] = mStack[sp - 1] % mStack[sp]; - return sp - 1; - }, - (sp) -> { // MIN - mStack[sp - 1] = (float) Math.min(mStack[sp - 1], mStack[sp]); - return sp - 1; - }, - (sp) -> { // MAX - mStack[sp - 1] = (float) Math.max(mStack[sp - 1], mStack[sp]); - return sp - 1; - }, - (sp) -> { // POW - mStack[sp - 1] = (float) Math.pow(mStack[sp - 1], mStack[sp]); - return sp - 1; - }, - (sp) -> { // SQRT - mStack[sp] = (float) Math.sqrt(mStack[sp]); - return sp; - }, - (sp) -> { // ABS - mStack[sp] = (float) Math.abs(mStack[sp]); - return sp; - }, - (sp) -> { // SIGN - mStack[sp] = (float) Math.signum(mStack[sp]); - return sp; - }, - (sp) -> { // copySign - mStack[sp - 1] = (float) Math.copySign(mStack[sp - 1], mStack[sp]); - return sp - 1; - }, - (sp) -> { // EXP - mStack[sp] = (float) Math.exp(mStack[sp]); - return sp; - }, - (sp) -> { // FLOOR - mStack[sp] = (float) Math.floor(mStack[sp]); - return sp; - }, - (sp) -> { // LOG - mStack[sp] = (float) Math.log10(mStack[sp]); - return sp; - }, - (sp) -> { // LN - mStack[sp] = (float) Math.log(mStack[sp]); - return sp; - }, - (sp) -> { // ROUND - mStack[sp] = (float) Math.round(mStack[sp]); - return sp; - }, - (sp) -> { // SIN - mStack[sp] = (float) Math.sin(mStack[sp]); - return sp; - }, - (sp) -> { // COS - mStack[sp] = (float) Math.cos(mStack[sp]); - return sp; - }, - (sp) -> { // TAN - mStack[sp] = (float) Math.tan(mStack[sp]); - return sp; - }, - (sp) -> { // ASIN - mStack[sp] = (float) Math.asin(mStack[sp]); - return sp; - }, - (sp) -> { // ACOS - mStack[sp] = (float) Math.acos(mStack[sp]); - return sp; - }, - (sp) -> { // ATAN - mStack[sp] = (float) Math.atan(mStack[sp]); - return sp; - }, - (sp) -> { // ATAN2 - mStack[sp - 1] = (float) Math.atan2(mStack[sp - 1], mStack[sp]); - return sp - 1; - }, - (sp) -> { // MAD - mStack[sp - 2] = mStack[sp] + mStack[sp - 1] * mStack[sp - 2]; - return sp - 2; - }, - (sp) -> { // Ternary conditional - mStack[sp - 2] = (mStack[sp] > 0) ? mStack[sp - 1] : mStack[sp - 2]; - return sp - 2; - }, - (sp) -> { // CLAMP(min,max, val) - mStack[sp - 2] = Math.min(Math.max(mStack[sp - 2], mStack[sp]), mStack[sp - 1]); - return sp - 2; - }, - (sp) -> { // CBRT cuberoot - mStack[sp] = (float) Math.pow(mStack[sp], 1 / 3.); - return sp; - }, - (sp) -> { // DEG - mStack[sp] = mStack[sp] * FP_TO_RAD; - return sp; - }, - (sp) -> { // RAD - mStack[sp] = mStack[sp] * FP_TO_DEG; - return sp; - }, - (sp) -> { // CEIL - mStack[sp] = (float) Math.ceil(mStack[sp]); - return sp; - }, - (sp) -> { // A_DEREF - int id = fromNaN(mStack[sp]); - mStack[sp] = mCollectionsAccess.getFloatValue(id, (int) mStack[sp - 1]); - return sp - 1; - }, - (sp) -> { // A_MAX - int id = fromNaN(mStack[sp]); - float[] array = mCollectionsAccess.getFloats(id); - float max = array[0]; - for (int i = 1; i < array.length; i++) { - max = Math.max(max, array[i]); - } - mStack[sp] = max; - return sp; - }, - (sp) -> { // A_MIN - int id = fromNaN(mStack[sp]); - float[] array = mCollectionsAccess.getFloats(id); - float max = array[0]; - for (int i = 1; i < array.length; i++) { - max = Math.max(max, array[i]); - } - mStack[sp] = max; - return sp; - }, - (sp) -> { // A_SUM - int id = fromNaN(mStack[sp]); - float[] array = mCollectionsAccess.getFloats(id); - float sum = 0; - for (int i = 0; i < array.length; i++) { - sum += array[i]; - } - mStack[sp] = sum; - return sp; - }, - (sp) -> { // A_AVG - int id = fromNaN(mStack[sp]); - float[] array = mCollectionsAccess.getFloats(id); - float sum = 0; - for (int i = 0; i < array.length; i++) { - sum += array[i]; - } - mStack[sp] = sum / array.length; - return sp; - }, - (sp) -> { // A_LEN - int id = fromNaN(mStack[sp]); - mStack[sp] = mCollectionsAccess.getListLength(id); - return sp; - }, - (sp) -> { // first var = - mStack[sp] = mVar[0]; - return sp; - }, - (sp) -> { // second var y? - mStack[sp] = mVar[1]; - return sp; - }, - (sp) -> { // 3rd var z? - mStack[sp] = mVar[2]; - return sp; - }, - }; + mADD, + mSUB, + mMUL, + mDIV, + mMOD, + mMIN, + mMAX, + mPOW, + mSQRT, + mABS, + mSIGN, + mCOPY_SIGN, + mEXP, + mFLOOR, + mLOG, + mLN, + mROUND, + mSIN, + mCOS, + mTAN, + mASIN, + mACOS, + mATAN, + mATAN2, + mMAD, + mTERNARY_CONDITIONAL, + mCLAMP, + mCBRT, + mDEG, + mRAD, + mCEIL, + mA_DEREF, + mA_MAX, + mA_MIN, + mA_SUM, + mA_AVG, + mA_LEN, + mFIRST_VAR, + mSECOND_VAR, + mTHIRD_VAR, + }; + mOps = ops; + } static { int k = 0; @@ -483,6 +570,7 @@ public class AnimatedFloatExpression { * @param f * @return */ + @Nullable public static String toMathName(float f) { int id = fromNaN(f) - OFFSET; return sNames.get(id); @@ -495,7 +583,8 @@ public class AnimatedFloatExpression { * @param labels * @return */ - public static String toString(float[] exp, String[] labels) { + @NonNull + public static String toString(@NonNull float[] exp, @Nullable String[] labels) { StringBuilder s = new StringBuilder(); for (int i = 0; i < exp.length; i++) { float v = exp[i]; @@ -525,7 +614,7 @@ public class AnimatedFloatExpression { return s.toString(); } - static String toString(float[] exp, int sp) { + static String toString(@NonNull float[] exp, int sp) { // String[] str = new String[exp.length]; if (Float.isNaN(exp[sp])) { int id = fromNaN(exp[sp]) - OFFSET; @@ -575,42 +664,42 @@ public class AnimatedFloatExpression { } static final int[] NO_OF_OPS = { - -1, // no op - 2, - 2, - 2, - 2, - 2, // + - * / % - 2, - 2, - 2, // min max, power - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, // sqrt,abs,CopySign,exp,floor,log,ln - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 2, // round,sin,cos,tan,asin,acos,atan,atan2 - 3, - 3, - 3, - 1, - 1, - 1, - 1, - 0, - 0, - 0 // mad, ?:, - // a[0],a[1],a[2] + -1, // no op + 2, + 2, + 2, + 2, + 2, // + - * / % + 2, + 2, + 2, // min max, power + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, // sqrt,abs,CopySign,exp,floor,log,ln + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 2, // round,sin,cos,tan,asin,acos,atan,atan2 + 3, + 3, + 3, + 1, + 1, + 1, + 1, + 0, + 0, + 0 // mad, ?:, + // a[0],a[1],a[2] }; /** 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 00c87c1f9c80034c1dbfb29a44e73711d6266b37..e74b3350f4278e713f5a9171d59a8d06c65a2a44 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 @@ -15,6 +15,8 @@ */ package com.android.internal.widget.remotecompose.core.operations.utilities; +import android.annotation.NonNull; + /** Implement the scaling logic for Compose Image or ImageView */ public class ImageScaling { @@ -97,6 +99,7 @@ public class ImageScaling { adjustDrawToType(); } + @NonNull static String str(float v) { String s = " " + (int) v; return s.substring(s.length() - 3); @@ -210,6 +213,7 @@ public class ImageScaling { } } + @NonNull public static String typeToString(int type) { String[] typeString = { "none", 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 84e78431790a3d573b9e1dd4fd75718ebafbff53..749c0fe0dcc3e45affa1f9570025359df5ac0aea 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,8 @@ */ package com.android.internal.widget.remotecompose.core.operations.utilities; +import android.annotation.Nullable; + import java.util.ArrayList; import java.util.Arrays; @@ -42,6 +44,7 @@ public class IntMap { mSize = 0; } + @Nullable public T put(int key, T value) { if (key == NOT_PRESENT) throw new IllegalArgumentException("Key cannot be NOT_PRESENT"); if (mSize > mKeys.length * LOAD_FACTOR) { @@ -50,6 +53,7 @@ public class IntMap { return insert(key, value); } + @Nullable public T get(int key) { int index = findKey(key); if (index == -1) { @@ -61,6 +65,7 @@ public class IntMap { return mSize; } + @Nullable private T insert(int key, T value) { int index = hash(key) % mKeys.length; while (mKeys[index] != NOT_PRESENT && mKeys[index] != key) { 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 baa144d6b28da5c861abeea20fe6fe48af457a2b..8905431d14d7955213a5f33c6775f322118ad2e3 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 @@ -15,6 +15,9 @@ */ package com.android.internal.widget.remotecompose.core.operations.utilities; +import android.annotation.NonNull; +import android.annotation.Nullable; + /** * High performance Integer expression evaluator * @@ -22,7 +25,7 @@ package com.android.internal.widget.remotecompose.core.operations.utilities; * 0) */ public class IntegerExpressionEvaluator { - static IntMap sNames = new IntMap<>(); + @NonNull static IntMap sNames = new IntMap<>(); public static final int OFFSET = 0x10000; // add, sub, mul,div,mod,min,max, shl, shr, ushr, OR, AND , XOR, COPY_SIGN public static final int I_ADD = OFFSET + 1; @@ -57,7 +60,7 @@ public class IntegerExpressionEvaluator { public static final int I_VAR2 = OFFSET + 25; int[] mStack; - int[] mLocalStack = new int[128]; + @NonNull int[] mLocalStack = new int[128]; int[] mVar; interface Op { @@ -68,8 +71,8 @@ public class IntegerExpressionEvaluator { * Evaluate an integer expression * * @param mask bits that are operators - * @param exp rpn sequence of values and operators - * @param var variables if the expression is a function + * @param exp rpn sequence of values and operators + * @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) { @@ -91,12 +94,12 @@ public class IntegerExpressionEvaluator { * Evaluate a integer expression * * @param mask bits that are operators - * @param exp rpn sequence of values and operators - * @param len the number of values in the expression - * @param var variables if the expression is a function + * @param exp rpn sequence of values and operators + * @param len the number of values in the expression + * @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 len, int... var) { + public int eval(int mask, @NonNull int[] exp, int len, int... var) { System.arraycopy(exp, 0, mLocalStack, 0, len); mStack = mLocalStack; mVar = var; @@ -116,11 +119,11 @@ public class IntegerExpressionEvaluator { * Evaluate a int expression * * @param opMask bits that are operators - * @param exp rpn sequence of values and operators - * @param var variables if the expression is a function + * @param exp rpn sequence of values and operators + * @param var variables if the expression is a function * @return return the results of evaluating the expression */ - public int evalDB(int opMask, int[] exp, int... var) { + public int evalDB(int opMask, @NonNull int[] exp, int... var) { mStack = exp; mVar = var; int sp = -1; @@ -137,113 +140,172 @@ public class IntegerExpressionEvaluator { return mStack[sp]; } - Op[] mOps = { + @NonNull Op[] mOps; + + { + Op mADD = + (sp) -> { // ADD + mStack[sp - 1] = mStack[sp - 1] + mStack[sp]; + return sp - 1; + }; + Op mSUB = + (sp) -> { // SUB + mStack[sp - 1] = mStack[sp - 1] - mStack[sp]; + return sp - 1; + }; + Op mMUL = + (sp) -> { // MUL + mStack[sp - 1] = mStack[sp - 1] * mStack[sp]; + return sp - 1; + }; + Op mDIV = + (sp) -> { // DIV + mStack[sp - 1] = mStack[sp - 1] / mStack[sp]; + return sp - 1; + }; + Op mMOD = + (sp) -> { // MOD + mStack[sp - 1] = mStack[sp - 1] % mStack[sp]; + return sp - 1; + }; + Op mSHL = + (sp) -> { // SHL + mStack[sp - 1] = mStack[sp - 1] << mStack[sp]; + return sp - 1; + }; + Op mSHR = + (sp) -> { // SHR + mStack[sp - 1] = mStack[sp - 1] >> mStack[sp]; + return sp - 1; + }; + Op mUSHR = + (sp) -> { // USHR + mStack[sp - 1] = mStack[sp - 1] >>> mStack[sp]; + return sp - 1; + }; + Op mOR = + (sp) -> { // OR + mStack[sp - 1] = mStack[sp - 1] | mStack[sp]; + return sp - 1; + }; + Op mAND = + (sp) -> { // AND + mStack[sp - 1] = mStack[sp - 1] & mStack[sp]; + return sp - 1; + }; + Op mXOR = + (sp) -> { // XOR + mStack[sp - 1] = mStack[sp - 1] ^ mStack[sp]; + return sp - 1; + }; + Op mCOPY_SIGN = + (sp) -> { // COPY_SIGN + mStack[sp - 1] = (mStack[sp - 1] ^ (mStack[sp] >> 31)) - (mStack[sp] >> 31); + return sp - 1; + }; + Op mMIN = + (sp) -> { // MIN + mStack[sp - 1] = Math.min(mStack[sp - 1], mStack[sp]); + return sp - 1; + }; + Op mMAX = + (sp) -> { // MAX + mStack[sp - 1] = Math.max(mStack[sp - 1], mStack[sp]); + return sp - 1; + }; + Op mNEG = + (sp) -> { // NEG + mStack[sp] = -mStack[sp]; + return sp; + }; + Op mABS = + (sp) -> { // ABS + mStack[sp] = Math.abs(mStack[sp]); + return sp; + }; + Op mINCR = + (sp) -> { // INCR + mStack[sp] = mStack[sp] + 1; + return sp; + }; + Op mDECR = + (sp) -> { // DECR + mStack[sp] = mStack[sp] - 1; + return sp; + }; + Op mNOT = + (sp) -> { // NOT + mStack[sp] = ~mStack[sp]; + return sp; + }; + Op mSIGN = + (sp) -> { // SIGN + mStack[sp] = (mStack[sp] >> 31) | (-mStack[sp] >>> 31); + return sp; + }; + Op mCLAMP = + (sp) -> { // CLAMP + mStack[sp - 2] = Math.min(Math.max(mStack[sp - 2], mStack[sp]), mStack[sp - 1]); + return sp - 2; + }; + Op mTERNARY_CONDITIONAL = + (sp) -> { // TERNARY_CONDITIONAL + mStack[sp - 2] = (mStack[sp] > 0) ? mStack[sp - 1] : mStack[sp - 2]; + return sp - 2; + }; + Op mMAD = + (sp) -> { // MAD + mStack[sp - 2] = mStack[sp] + mStack[sp - 1] * mStack[sp - 2]; + return sp - 2; + }; + Op mFIRST_VAR = + (sp) -> { // FIRST_VAR + mStack[sp] = mVar[0]; + return sp; + }; + Op mSECOND_VAR = + (sp) -> { // SECOND_VAR + mStack[sp] = mVar[1]; + return sp; + }; + Op mTHIRD_VAR = + (sp) -> { // THIRD_VAR + mStack[sp] = mVar[2]; + return sp; + }; + + Op[] ops = { null, - (sp) -> { // ADD - mStack[sp - 1] = mStack[sp - 1] + mStack[sp]; - return sp - 1; - }, - (sp) -> { // SUB - mStack[sp - 1] = mStack[sp - 1] - mStack[sp]; - return sp - 1; - }, - (sp) -> { // MUL - mStack[sp - 1] = mStack[sp - 1] * mStack[sp]; - return sp - 1; - }, - (sp) -> { // DIV - mStack[sp - 1] = mStack[sp - 1] / mStack[sp]; - return sp - 1; - }, - (sp) -> { // MOD - mStack[sp - 1] = mStack[sp - 1] % mStack[sp]; - return sp - 1; - }, - (sp) -> { // SHL shift left - mStack[sp - 1] = mStack[sp - 1] << mStack[sp]; - return sp - 1; - }, - (sp) -> { // SHR shift right - mStack[sp - 1] = mStack[sp - 1] >> mStack[sp]; - return sp - 1; - }, - (sp) -> { // USHR unsigned shift right - mStack[sp - 1] = mStack[sp - 1] >>> mStack[sp]; - return sp - 1; - }, - (sp) -> { // OR operator - mStack[sp - 1] = mStack[sp - 1] | mStack[sp]; - return sp - 1; - }, - (sp) -> { // AND operator - mStack[sp - 1] = mStack[sp - 1] & mStack[sp]; - return sp - 1; - }, - (sp) -> { // XOR xor operator - mStack[sp - 1] = mStack[sp - 1] ^ mStack[sp]; - return sp - 1; - }, - (sp) -> { // COPY_SIGN copy the sing of (using bit magic) - mStack[sp - 1] = (mStack[sp - 1] ^ (mStack[sp] >> 31)) - (mStack[sp] >> 31); - return sp - 1; - }, - (sp) -> { // MIN - mStack[sp - 1] = Math.min(mStack[sp - 1], mStack[sp]); - return sp - 1; - }, - (sp) -> { // MAX - mStack[sp - 1] = Math.max(mStack[sp - 1], mStack[sp]); - return sp - 1; - }, - (sp) -> { // NEG - mStack[sp] = -mStack[sp]; - return sp; - }, - (sp) -> { // ABS - mStack[sp] = Math.abs(mStack[sp]); - return sp; - }, - (sp) -> { // INCR increment - mStack[sp] = mStack[sp] + 1; - return sp; - }, - (sp) -> { // DECR decrement - mStack[sp] = mStack[sp] - 1; - return sp; - }, - (sp) -> { // NOT Bit invert - mStack[sp] = ~mStack[sp]; - return sp; - }, - (sp) -> { // SIGN x<0 = -1,x==0 = 0 , x>0 = 1 - mStack[sp] = (mStack[sp] >> 31) | (-mStack[sp] >>> 31); - return sp; - }, - (sp) -> { // CLAMP(min,max, val) - mStack[sp - 2] = Math.min(Math.max(mStack[sp - 2], mStack[sp]), mStack[sp - 1]); - return sp - 2; - }, - (sp) -> { // Ternary conditional - mStack[sp - 2] = (mStack[sp] > 0) ? mStack[sp - 1] : mStack[sp - 2]; - return sp - 2; - }, - (sp) -> { // MAD - mStack[sp - 2] = mStack[sp] + mStack[sp - 1] * mStack[sp - 2]; - return sp - 2; - }, - (sp) -> { // first var = - mStack[sp] = mVar[0]; - return sp; - }, - (sp) -> { // second var y? - mStack[sp] = mVar[1]; - return sp; - }, - (sp) -> { // 3rd var z? - mStack[sp] = mVar[2]; - return sp; - }, - }; + mADD, + mSUB, + mMUL, + mDIV, + mMOD, + mSHL, + mSHR, + mUSHR, + mOR, + mAND, + mXOR, + mCOPY_SIGN, + mMIN, + mMAX, + mNEG, + mABS, + mINCR, + mDECR, + mNOT, + mSIGN, + mCLAMP, + mTERNARY_CONDITIONAL, + mMAD, + mFIRST_VAR, + mSECOND_VAR, + mTHIRD_VAR, + }; + + mOps = ops; + } static { int k = 0; @@ -283,6 +345,7 @@ public class IntegerExpressionEvaluator { * @param f the numerical value of the function + offset * @return the math name of the function */ + @Nullable public static String toMathName(int f) { int id = f - OFFSET; return sNames.get(id); @@ -292,11 +355,12 @@ public class IntegerExpressionEvaluator { * Convert an expression encoded as an array of ints int to a string * * @param opMask bits that are operators - * @param exp rpn sequence of values and operators + * @param exp rpn sequence of values and operators * @param labels String that represent the variable names * @return */ - public static String toString(int opMask, int[] exp, String[] labels) { + @NonNull + public static String toString(int opMask, @NonNull int[] exp, String[] labels) { StringBuilder s = new StringBuilder(); for (int i = 0; i < exp.length; i++) { int v = exp[i]; @@ -324,10 +388,11 @@ public class IntegerExpressionEvaluator { * Convert an expression encoded as an array of ints int ot a string * * @param opMask bit mask of operators vs commands - * @param exp rpn sequence of values and operators + * @param exp rpn sequence of values and operators * @return string representation of the expression */ - public static String toString(int opMask, int[] exp) { + @NonNull + public static String toString(int opMask, @NonNull int[] exp) { StringBuilder s = new StringBuilder(); s.append(Integer.toBinaryString(opMask)); s.append(" : "); @@ -355,13 +420,15 @@ public class IntegerExpressionEvaluator { * This creates an infix string expression * * @param opMask The bits that are operators - * @param exp the array of expressions + * @param exp the array of expressions * @return infix string */ - public static String toStringInfix(int opMask, int[] exp) { + @NonNull + public static String toStringInfix(int opMask, @NonNull int[] exp) { return toString(opMask, exp, exp.length - 1); } + @NonNull static String toString(int mask, int[] exp, int sp) { if (((1 << sp) & mask) != 0) { int id = exp[sp] - OFFSET; @@ -412,34 +479,34 @@ public class IntegerExpressionEvaluator { } static final int[] NO_OF_OPS = { - -1, // no op - 2, - 2, - 2, - 2, - 2, // + - * / % - 2, - 2, - 2, - 2, - 2, - 2, - 2, - 2, - 2, // <<, >> , >>> , | , &, ^, min max - 1, - 1, - 1, - 1, - 1, - 1, // neg, abs, ++, -- , not , sign - 3, - 3, - 3, // clamp, ifElse, mad, - 0, - 0, - 0 // mad, ?:, - // a[0],a[1],a[2] + -1, // no op + 2, + 2, + 2, + 2, + 2, // + - * / % + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 2, // <<, >> , >>> , | , &, ^, min max + 1, + 1, + 1, + 1, + 1, + 1, // neg, abs, ++, -- , not , sign + 3, + 3, + 3, // clamp, ifElse, mad, + 0, + 0, + 0 // mad, ?:, + // a[0],a[1],a[2] }; /** @@ -456,7 +523,7 @@ public class IntegerExpressionEvaluator { * is it an id or operation * * @param opMask the bits that mark elements as an operation - * @param i the bit to check + * @param i the bit to check * @return true if the bit is 1 */ public static boolean isOperation(int opMask, int i) { diff --git a/core/java/com/android/internal/widget/remotecompose/core/operations/utilities/StringSerializer.java b/core/java/com/android/internal/widget/remotecompose/core/operations/utilities/StringSerializer.java index ab7576e12aa66f1b91e110d508bdafbca53ed395..92127c12f40160a51d9d56f624bfadd7ae73d257 100644 --- a/core/java/com/android/internal/widget/remotecompose/core/operations/utilities/StringSerializer.java +++ b/core/java/com/android/internal/widget/remotecompose/core/operations/utilities/StringSerializer.java @@ -15,9 +15,14 @@ */ package com.android.internal.widget.remotecompose.core.operations.utilities; +import android.annotation.NonNull; +import android.annotation.Nullable; + /** Utility serializer maintaining an indent buffer */ public class StringSerializer { - StringBuffer mBuffer = new StringBuffer(); + @NonNull StringBuffer mBuffer = new StringBuffer(); + + @NonNull String mIndentBuffer = " "; /** @@ -26,7 +31,7 @@ public class StringSerializer { * @param indent the indentation level to use * @param content content to append */ - public void append(int indent, String content) { + public void append(int indent, @Nullable String content) { String indentation = mIndentBuffer.substring(0, indent); mBuffer.append(indentation); mBuffer.append(indentation); @@ -44,6 +49,7 @@ public class StringSerializer { * * @return string representation */ + @NonNull @Override public String toString() { return mBuffer.toString(); diff --git a/core/java/com/android/internal/widget/remotecompose/core/operations/utilities/StringUtils.java b/core/java/com/android/internal/widget/remotecompose/core/operations/utilities/StringUtils.java index f2ccb401ea8f0c2e81dd35a94c07cad6c0f38d79..a95a175d0edd02a2a7e36209cdd2d58eec45eab3 100644 --- a/core/java/com/android/internal/widget/remotecompose/core/operations/utilities/StringUtils.java +++ b/core/java/com/android/internal/widget/remotecompose/core/operations/utilities/StringUtils.java @@ -15,6 +15,8 @@ */ package com.android.internal.widget.remotecompose.core.operations.utilities; +import android.annotation.NonNull; + import java.util.Arrays; /** Utilities for string manipulation */ @@ -30,6 +32,7 @@ public class StringUtils { * @param post character to pad width 0 = no pad typically ' ' or '0' * @return */ + @NonNull public static String floatToString( float value, int beforeDecimalPoint, int afterDecimalPoint, char pre, char post) { diff --git a/core/java/com/android/internal/widget/remotecompose/core/operations/utilities/easing/CubicEasing.java b/core/java/com/android/internal/widget/remotecompose/core/operations/utilities/easing/CubicEasing.java index 60a59cf464cd02ee8214a5c43a509068c04b734e..1343345df6e5a85afd80bba39a31c0917d706209 100644 --- a/core/java/com/android/internal/widget/remotecompose/core/operations/utilities/easing/CubicEasing.java +++ b/core/java/com/android/internal/widget/remotecompose/core/operations/utilities/easing/CubicEasing.java @@ -15,6 +15,8 @@ */ package com.android.internal.widget.remotecompose.core.operations.utilities.easing; +import android.annotation.NonNull; + class CubicEasing extends Easing { float mX1 = 0f; float mY1 = 0f; @@ -62,7 +64,7 @@ class CubicEasing extends Easing { mType = type; } - void setup(float[] values) { + void setup(@NonNull float[] values) { setup(values[0], values[1], values[2], values[3]); } 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 a29b8af5fbd1a8c221a836e1c2a02bea10e135dd..ebb22b6e98c5fb854739204dbfd9b731e988148a 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 @@ -15,6 +15,9 @@ */ package com.android.internal.widget.remotecompose.core.operations.utilities.easing; +import android.annotation.NonNull; +import android.annotation.Nullable; + /** Support Animation of the FloatExpression */ public class FloatAnimation extends Easing { float[] mSpec; @@ -31,6 +34,7 @@ public class FloatAnimation extends Easing { // private float mScale = 1; float mOffset = 0; + @NonNull @Override public String toString() { @@ -74,7 +78,7 @@ public class FloatAnimation extends Easing { * @return */ public static float[] packToFloatArray( - float duration, int type, float[] spec, float initialValue, float wrap) { + float duration, int type, @Nullable float[] spec, float initialValue, float wrap) { int count = 0; if (!Float.isNaN(initialValue)) { @@ -128,6 +132,90 @@ public class FloatAnimation extends Easing { return ret; } + /** + * Useful to debug the packed form of an animation string + * + * @param description + * @return + */ + public static String unpackAnimationToString(float[] description) { + float[] mSpec = description; + float mDuration = (mSpec.length == 0) ? 1 : mSpec[0]; + int len = 0; + int type = 0; + float wrapValue = Float.NaN; + float initialValue = Float.NaN; + if (mSpec.length > 1) { + int num_type = Float.floatToRawIntBits(mSpec[1]); + type = num_type & 0xFF; + boolean wrap = ((num_type >> 8) & 0x1) > 0; + boolean init = ((num_type >> 8) & 0x2) > 0; + len = (num_type >> 16) & 0xFFFF; + int off = 2 + len; + if (init) { + initialValue = mSpec[off++]; + } + if (wrap) { + wrapValue = mSpec[off]; + } + } + float[] params = description; + int offset = 2; + + String typeStr = ""; + switch (type) { + case CUBIC_STANDARD: + typeStr = "CUBIC_STANDARD"; + break; + case CUBIC_ACCELERATE: + typeStr = "CUBIC_ACCELERATE"; + break; + case CUBIC_DECELERATE: + typeStr = "CUBIC_DECELERATE"; + break; + case CUBIC_LINEAR: + typeStr = "CUBIC_LINEAR"; + break; + case CUBIC_ANTICIPATE: + typeStr = "CUBIC_ANTICIPATE"; + break; + case CUBIC_OVERSHOOT: + typeStr = "CUBIC_OVERSHOOT"; + + break; + case CUBIC_CUSTOM: + typeStr = "CUBIC_CUSTOM ("; + typeStr += params[offset + 0] + " "; + typeStr += params[offset + 1] + " "; + typeStr += params[offset + 2] + " "; + typeStr += params[offset + 3] + " )"; + break; + case EASE_OUT_BOUNCE: + typeStr = "EASE_OUT_BOUNCE"; + + break; + case EASE_OUT_ELASTIC: + typeStr = "EASE_OUT_ELASTIC"; + break; + case SPLINE_CUSTOM: + typeStr = "SPLINE_CUSTOM ("; + for (int i = offset; i < offset + len; i++) { + typeStr += params[i] + " "; + } + typeStr += ")"; + break; + } + + String str = mDuration + " " + typeStr; + if (!Float.isNaN(initialValue)) { + str += " init =" + initialValue; + } + if (!Float.isNaN(wrapValue)) { + str += " wrap =" + wrapValue; + } + return str; + } + /** * Create an animation based on a float encoding of the animation * @@ -208,21 +296,43 @@ public class FloatAnimation extends Easing { setScaleOffset(); } + private static float wrap(float wrap, float value) { + value = value % wrap; + if (value < 0) { + value += wrap; + } + return value; + } + + float wrapDistance(float wrap, float from, float to) { + float delta = (to - from) % 360; + if (delta < -wrap / 2) { + delta += wrap; + } else if (delta > wrap / 2) { + delta -= wrap; + } + return delta; + } + /** * Set the target value to interpolate to * * @param value */ public void setTargetValue(float value) { - if (Float.isNaN(mWrap)) { - mTargetValue = value; - } else { - if (Math.abs((value % mWrap) + mWrap - mInitialValue) - < Math.abs((value % mWrap) - mInitialValue)) { - mTargetValue = (value % mWrap) + mWrap; + mTargetValue = value; + if (!Float.isNaN(mWrap)) { + mInitialValue = wrap(mWrap, mInitialValue); + mTargetValue = wrap(mWrap, mTargetValue); + if (Float.isNaN(mInitialValue)) { + mInitialValue = mTargetValue; + } - } else { - mTargetValue = value % mWrap; + float dist = wrapDistance(mWrap, mInitialValue, mTargetValue); + if ((dist > 0) && (mTargetValue < mInitialValue)) { + mTargetValue += mWrap; + } else if ((dist < 0) && (mTargetValue > mInitialValue)) { + mTargetValue -= mWrap; } } setScaleOffset(); 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 75a60324aa3c7ef20614efdc5c5562cdb0e7e19d..90b65bf2353a043c64fb665270848231008a707d 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 @@ -15,10 +15,12 @@ */ package com.android.internal.widget.remotecompose.core.operations.utilities.easing; +import android.annotation.NonNull; + /** Provides and interface to create easing functions */ public class GeneralEasing extends Easing { float[] mEasingData = new float[0]; - Easing mEasingCurve = new CubicEasing(CUBIC_STANDARD); + @NonNull Easing mEasingCurve = new CubicEasing(CUBIC_STANDARD); /** * Set the curve based on the float encoding of it 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 9355cacde4addfecff9d660895acb4db07f9aaf5..f540e7008471107fd9b1708c46fa19c21401e23b 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 @@ -15,6 +15,8 @@ */ package com.android.internal.widget.remotecompose.core.operations.utilities.easing; +import android.annotation.NonNull; + import java.util.Arrays; /** This performs a spline interpolation in multiple dimensions */ @@ -32,7 +34,7 @@ public class MonotonicCurveFit { * @param time the point along the curve * @param y the parameter at those points */ - public MonotonicCurveFit(double[] time, double[][] y) { + public MonotonicCurveFit(@NonNull double[] time, @NonNull double[][] y) { final int n = time.length; final int dim = y[0].length; mSlopeTemp = new double[dim]; @@ -331,7 +333,8 @@ public class MonotonicCurveFit { } /** This builds a monotonic spline to be used as a wave function */ - public static MonotonicCurveFit buildWave(String configString) { + @NonNull + public static MonotonicCurveFit buildWave(@NonNull String configString) { // done this way for efficiency String str = configString; double[] values = new double[str.length() / 2]; @@ -350,7 +353,8 @@ public class MonotonicCurveFit { return buildWave(Arrays.copyOf(values, count)); } - private static MonotonicCurveFit buildWave(double[] values) { + @NonNull + private static MonotonicCurveFit buildWave(@NonNull double[] values) { int length = values.length * 3 - 2; int len = values.length - 1; double gap = 1.0 / len; 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 b4596897a44fc3cbf15fc1eb19c6b615fc7c40be..c7be3cab4c0b1ead09968b82317e8010cd3fcb9b 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 @@ -15,6 +15,8 @@ */ package com.android.internal.widget.remotecompose.core.operations.utilities.easing; +import android.annotation.NonNull; + /** * This class translates a series of floating point values into a continuous curve for use in an * easing function including quantize functions it is used with the "spline(0,0.3,0.3,0.5,...0.9,1)" @@ -28,6 +30,7 @@ public class StepCurve extends Easing { mCurveFit = genSpline(params, offset, len); } + @NonNull private static MonotonicCurveFit genSpline(float[] values, int off, int arrayLen) { int length = arrayLen * 3 - 2; int len = arrayLen - 1; 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 new file mode 100644 index 0000000000000000000000000000000000000000..3e24372f9b8cc9fd6cb74ada3c59dd50e2a950f2 --- /dev/null +++ b/core/java/com/android/internal/widget/remotecompose/core/operations/utilities/touch/VelocityEasing.java @@ -0,0 +1,341 @@ +/* + * 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.touch; + +/* + * 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. + */ + +public class VelocityEasing { + private float mStartPos = 0; + private float mStartV = 0; + private float mEndPos = 0; + private float mDuration = 0; + + private Stage[] mStage = {new Stage(1), new Stage(2), new Stage(3)}; + private int mNumberOfStages = 0; + private Easing mEasing; + private double mEasingAdapterDistance = 0; + private double mEasingAdapterA = 0; + private double mEasingAdapterB = 0; + private boolean mOneDimension = true; + private float mTotalEasingDuration = 0; + + public float getDuration() { + if (mEasing != null) { + return mTotalEasingDuration; + } + return mDuration; + } + + public float getV(float t) { + if (mEasing == null) { + for (int i = 0; i < mNumberOfStages; i++) { + if (mStage[i].mEndTime > t) { + return mStage[i].getVel(t); + } + } + return 0f; + } + int lastStages = mNumberOfStages - 1; + for (int i = 0; i < lastStages; i++) { + if (mStage[i].mEndTime > t) { + return mStage[i].getVel(t); + } + } + return (float) getEasingDiff((t - mStage[lastStages].mStartTime)); + } + + public float getPos(float t) { + if (mEasing == null) { + for (int i = 0; i < mNumberOfStages; i++) { + if (mStage[i].mEndTime > t) { + return mStage[i].getPos(t); + } + } + return mEndPos; + } + int lastStages = mNumberOfStages - 1; + for (int i = 0; i < lastStages; i++) { + if (mStage[i].mEndTime > t) { + return mStage[i].getPos(t); + } + } + var ret = (float) getEasing((t - mStage[lastStages].mStartTime)); + ret += mStage[lastStages].mStartPos; + return ret; + } + + public String toString() { + var s = " "; + for (int i = 0; i < mNumberOfStages; i++) { + Stage stage = mStage[i]; + s += " $i $stage"; + } + return s; + } + + public void config( + float currentPos, + float destination, + float currentVelocity, + float maxTime, + float maxAcceleration, + float maxVelocity, + Easing easing) { + float pos = currentPos; + float velocity = currentVelocity; + if (pos == destination) { + pos += 1f; + } + mStartPos = pos; + mEndPos = destination; + if (easing != null) { + this.mEasing = easing.clone(); + } + float dir = Math.signum(destination - pos); + float maxV = maxVelocity * dir; + float maxA = maxAcceleration * dir; + if (velocity == 0.0) { + velocity = 0.0001f * dir; + } + mStartV = velocity; + if (!rampDown(pos, destination, velocity, maxTime)) { + if (!(mOneDimension + && cruseThenRampDown(pos, destination, velocity, maxTime, maxA, maxV))) { + if (!rampUpRampDown(pos, destination, velocity, maxA, maxV, maxTime)) { + rampUpCruseRampDown(pos, destination, velocity, maxA, maxV, maxTime); + } + } + } + if (mOneDimension) { + configureEasingAdapter(); + } + } + + private boolean rampDown( + float currentPos, float destination, float currentVelocity, float maxTime) { + float timeToDestination = 2 * ((destination - currentPos) / currentVelocity); + if (timeToDestination > 0 && timeToDestination <= maxTime) { // hit the brakes + mNumberOfStages = 1; + mStage[0].setUp(currentVelocity, currentPos, 0f, 0f, destination, timeToDestination); + mDuration = timeToDestination; + return true; + } + return false; + } + + private boolean cruseThenRampDown( + float currentPos, + float destination, + float currentVelocity, + float maxTime, + float maxA, + float maxV) { + float timeToBreak = currentVelocity / maxA; + float brakeDist = currentVelocity * timeToBreak / 2; + float cruseDist = destination - currentPos - brakeDist; + float cruseTime = cruseDist / currentVelocity; + float totalTime = cruseTime + timeToBreak; + if (totalTime > 0 && totalTime < maxTime) { + mNumberOfStages = 2; + mStage[0].setUp(currentVelocity, currentPos, 0f, currentVelocity, cruseDist, cruseTime); + mStage[1].setUp( + currentVelocity, + currentPos + cruseDist, + cruseTime, + 0f, + destination, + cruseTime + timeToBreak); + mDuration = cruseTime + timeToBreak; + return true; + } + return false; + } + + private boolean rampUpRampDown( + float currentPos, + float destination, + float currentVelocity, + float maxA, + float maxVelocity, + float maxTime) { + float peak_v = + Math.signum(maxA) + * (float) + Math.sqrt( + (maxA * (destination - currentPos) + + currentVelocity * currentVelocity / 2)); + if (maxVelocity / peak_v > 1) { + float t1 = (peak_v - currentVelocity) / maxA; + float d1 = (peak_v + currentVelocity) * t1 / 2 + currentPos; + float t2 = peak_v / maxA; + mNumberOfStages = 2; + mStage[0].setUp(currentVelocity, currentPos, 0f, peak_v, d1, t1); + mStage[1].setUp(peak_v, d1, t1, 0f, destination, t2 + t1); + mDuration = t2 + t1; + if (mDuration > maxTime) { + return false; + } + if (mDuration < maxTime / 2) { + t1 = mDuration / 2; + t2 = t1; + peak_v = (2 * (destination - currentPos) / t1 - currentVelocity) / 2; + d1 = (peak_v + currentVelocity) * t1 / 2 + currentPos; + mNumberOfStages = 2; + mStage[0].setUp(currentVelocity, currentPos, 0f, peak_v, d1, t1); + mStage[1].setUp(peak_v, d1, t1, 0f, destination, t2 + t1); + mDuration = t2 + t1; + if (mDuration > maxTime) { + System.out.println(" fail "); + return false; + } + } + return true; + } + return false; + } + + private void rampUpCruseRampDown( + float currentPos, + float destination, + float currentVelocity, + float maxA, + float maxV, + float maxTime) { + float t1 = maxTime / 3; + float t2 = t1 * 2; + float distance = destination - currentPos; + float dt2 = t2 - t1; + float dt3 = maxTime - t2; + float v1 = (2 * distance - currentVelocity * t1) / (t1 + 2 * dt2 + dt3); + mDuration = maxTime; + float d1 = (currentVelocity + v1) * t1 / 2; + float d2 = (v1 + v1) * (t2 - t1) / 2; + mNumberOfStages = 3; + float acc = (v1 - currentVelocity) / t1; + float dec = v1 / dt3; + mStage[0].setUp(currentVelocity, currentPos, 0f, v1, currentPos + d1, t1); + mStage[1].setUp(v1, currentPos + d1, t1, v1, currentPos + d1 + d2, t2); + mStage[2].setUp(v1, currentPos + d1 + d2, t2, 0f, destination, maxTime); + mDuration = maxTime; + } + + double getEasing(double t) { + double gx = t * t * mEasingAdapterA + t * mEasingAdapterB; + if (gx > 1) { + return mEasingAdapterDistance; + } else { + return mEasing.get(gx) * mEasingAdapterDistance; + } + } + + private double getEasingDiff(double t) { + double gx = t * t * mEasingAdapterA + t * mEasingAdapterB; + if (gx > 1) { + return 0.0; + } else { + return mEasing.getDiff(gx) + * mEasingAdapterDistance + * (t * mEasingAdapterA + mEasingAdapterB); + } + } + + protected void configureEasingAdapter() { + if (mEasing == null) { + return; + } + int last = mNumberOfStages - 1; + float initialVelocity = mStage[last].mStartV; + float distance = mStage[last].mEndPos - mStage[last].mStartPos; + float duration = mStage[last].mEndTime - mStage[last].mStartTime; + double baseVel = mEasing.getDiff(0.0); + mEasingAdapterB = initialVelocity / (baseVel * distance); + mEasingAdapterA = 1 - mEasingAdapterB; + mEasingAdapterDistance = distance; + double easingDuration = + (Math.sqrt(4 * mEasingAdapterA + mEasingAdapterB * mEasingAdapterB) + - mEasingAdapterB) + / (2 * mEasingAdapterA); + mTotalEasingDuration = (float) (easingDuration + mStage[last].mStartTime); + } + + interface Easing { + double get(double t); + + double getDiff(double t); + + Easing clone(); + } + + class Stage { + private float mStartV = 0; + private float mStartPos = 0; + private float mStartTime = 0; + private float mEndV = 0; + private float mEndPos = 0; + private float mEndTime = 0; + private float mDeltaV = 0; + private float mDeltaT = 0; + final int mStage; + + Stage(int n) { + mStage = n; + } + + void setUp( + float startV, + float startPos, + float startTime, + float endV, + float endPos, + float endTime) { + this.mStartV = startV; + this.mStartPos = startPos; + this.mStartTime = startTime; + this.mEndV = endV; + this.mEndTime = endTime; + this.mEndPos = endPos; + mDeltaV = this.mEndV - this.mStartV; + mDeltaT = this.mEndTime - this.mStartTime; + } + + float getPos(float t) { + float dt = t - mStartTime; + float pt = dt / mDeltaT; + float v = mStartV + mDeltaV * pt; + return dt * (mStartV + v) / 2 + mStartPos; + } + + float getVel(float t) { + float dt = t - mStartTime; + float pt = dt / (mEndTime - mStartTime); + return mStartV + mDeltaV * pt; + } + } +} 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 57a804284f0d59f82ff88493c8a572e7214c5f35..3fba8acf8bca2a632b227649d0a0bf1fca4a7280 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 @@ -17,6 +17,8 @@ package com.android.internal.widget.remotecompose.core.types; import static com.android.internal.widget.remotecompose.core.documentation.DocumentedOperation.BYTE; +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; @@ -47,23 +49,26 @@ public class BooleanConstant implements Operation { } @Override - public void write(WireBuffer buffer) { + public void write(@NonNull WireBuffer buffer) { apply(buffer, mId, mValue); } @Override public void apply(RemoteContext context) {} + @NonNull @Override public String deepToString(String indent) { return toString(); } + @NonNull @Override public String toString() { return "BooleanConstant[" + mId + "] = " + mValue + ""; } + @NonNull public static String name() { return "OrigamiBoolean"; } @@ -79,20 +84,20 @@ public class BooleanConstant implements Operation { * @param id * @param value */ - public static void apply(WireBuffer buffer, int id, boolean value) { + public static void apply(@NonNull WireBuffer buffer, int id, boolean value) { buffer.start(OP_CODE); buffer.writeInt(id); buffer.writeBoolean(value); } - public static void read(WireBuffer buffer, List operations) { + public static void read(@NonNull WireBuffer buffer, @NonNull List operations) { int id = buffer.readInt(); boolean value = buffer.readBoolean(); operations.add(new BooleanConstant(id, value)); } - public static void documentation(DocumentationBuilder doc) { + public static void documentation(@NonNull DocumentationBuilder doc) { doc.operation("Expressions Operations", OP_CODE, "BooleanConstant") .description("A boolean and its associated id") .field(DocumentedOperation.INT, "id", "id of Int") 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 3ef9db9de9155c3401a8d29a8f3cb6b22b7614b4..79f2a8d8dec52053f622bc4e4aff91c4a76d3386 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 @@ -17,6 +17,8 @@ package com.android.internal.widget.remotecompose.core.types; 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; @@ -37,25 +39,28 @@ public class IntegerConstant implements Operation { } @Override - public void write(WireBuffer buffer) { + public void write(@NonNull WireBuffer buffer) { apply(buffer, mId, mValue); } @Override - public void apply(RemoteContext context) { + public void apply(@NonNull RemoteContext context) { context.loadInteger(mId, mValue); } + @NonNull @Override public String deepToString(String indent) { return toString(); } + @NonNull @Override public String toString() { return "IntegerConstant[" + mId + "] = " + mValue + ""; } + @NonNull public static String name() { return "IntegerConstant"; } @@ -71,20 +76,20 @@ public class IntegerConstant implements Operation { * @param textId * @param value */ - public static void apply(WireBuffer buffer, int textId, int value) { + public static void apply(@NonNull WireBuffer buffer, int textId, int value) { buffer.start(Operations.DATA_INT); buffer.writeInt(textId); buffer.writeInt(value); } - public static void read(WireBuffer buffer, List operations) { + public static void read(@NonNull WireBuffer buffer, @NonNull List operations) { int id = buffer.readInt(); int value = buffer.readInt(); operations.add(new IntegerConstant(id, value)); } - public static void documentation(DocumentationBuilder doc) { + public static void documentation(@NonNull DocumentationBuilder doc) { doc.operation("Expressions Operations", id(), "IntegerConstant") .description("A integer and its associated id") .field(DocumentedOperation.INT, "id", "id of Int") 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 6d51d194708fe52c1305057b274a1c3f5e60a9da..01672b469728bc740898b4ed3d73d341ace737f7 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 @@ -17,6 +17,8 @@ package com.android.internal.widget.remotecompose.core.types; import static com.android.internal.widget.remotecompose.core.documentation.DocumentedOperation.LONG; +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; @@ -47,7 +49,7 @@ public class LongConstant implements Operation { } @Override - public void write(WireBuffer buffer) { + public void write(@NonNull WireBuffer buffer) { apply(buffer, mId, mValue); } @@ -56,11 +58,13 @@ public class LongConstant implements Operation { context.putObject(mId, this); } + @NonNull @Override public String deepToString(String indent) { return toString(); } + @NonNull @Override public String toString() { return "LongConstant[" + mId + "] = " + mValue + ""; @@ -73,20 +77,20 @@ public class LongConstant implements Operation { * @param id * @param value */ - public static void apply(WireBuffer buffer, int id, long value) { + public static void apply(@NonNull WireBuffer buffer, int id, long value) { buffer.start(OP_CODE); buffer.writeInt(id); buffer.writeLong(value); } - public static void read(WireBuffer buffer, List operations) { + public static void read(@NonNull WireBuffer buffer, @NonNull List operations) { int id = buffer.readInt(); long value = buffer.readLong(); operations.add(new LongConstant(id, value)); } - public static void documentation(DocumentationBuilder doc) { + public static void documentation(@NonNull DocumentationBuilder doc) { doc.operation("Expressions Operations", OP_CODE, "LongConstant") .description("A boolean and its associated id") .field(DocumentedOperation.INT, "id", "id of Int") 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 906282c1dde3646ea1fa3a3b4e0777ccdaf0a7b4..aaee9c565fbbde204f7443bc97c1874ec06fccf3 100644 --- a/core/java/com/android/internal/widget/remotecompose/player/RemoteComposeDocument.java +++ b/core/java/com/android/internal/widget/remotecompose/player/RemoteComposeDocument.java @@ -111,6 +111,16 @@ public class RemoteComposeDocument { return mDocument.getNamedColors(); } + /** + * Gets a array of Names of the named variables of a specific type defined in the doc. + * + * @param type the type of variable NamedVariable.COLOR_TYPE, STRING_TYPE, etc + * @return array of name or null + */ + public String[] getNamedVariables(int type) { + return mDocument.getNamedVariables(type); + } + /** * Return a component associated with id * diff --git a/core/java/com/android/internal/widget/remotecompose/player/RemoteComposePlayer.java b/core/java/com/android/internal/widget/remotecompose/player/RemoteComposePlayer.java index 06bf4cdb0a0dbda6305bd28ea558eed4ce90a74a..cc74b119866de097d6f21f4a04911cb9539ce55d 100644 --- a/core/java/com/android/internal/widget/remotecompose/player/RemoteComposePlayer.java +++ b/core/java/com/android/internal/widget/remotecompose/player/RemoteComposePlayer.java @@ -21,11 +21,14 @@ import android.graphics.Color; import android.util.AttributeSet; import android.util.Log; import android.util.TypedValue; +import android.view.HapticFeedbackConstants; import android.view.ViewGroup; import android.widget.FrameLayout; import android.widget.HorizontalScrollView; import android.widget.ScrollView; +import com.android.internal.widget.remotecompose.core.CoreDocument; +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; @@ -57,11 +60,7 @@ public class RemoteComposePlayer extends FrameLayout { * @param debugFlags 1 to set debug on */ public void setDebug(int debugFlags) { - if (debugFlags == 1) { - mInner.setDebug(true); - } else { - mInner.setDebug(false); - } + mInner.setDebug(debugFlags); } public RemoteComposeDocument getDocument() { @@ -82,6 +81,14 @@ public class RemoteComposePlayer extends FrameLayout { mInner.setDocument(null); } mapColors(); + mInner.setHapticEngine( + new CoreDocument.HapticEngine() { + + @Override + public void haptic(int type) { + provideHapticFeedback(type); + } + }); } /** @@ -259,12 +266,39 @@ public class RemoteComposePlayer extends FrameLayout { /** * This returns a list of colors that have names in the Document. * - * @return + * @return the names of named Strings or null */ public String[] getNamedColors() { return mInner.getNamedColors(); } + /** + * This returns a list of floats that have names in the Document. + * + * @return return the names of named floats in the document + */ + public String[] getNamedFloats() { + return mInner.getNamedVariables(NamedVariable.FLOAT_TYPE); + } + + /** + * This returns a list of string name that have names in the Document. + * + * @return the name of named string (not the string itself) + */ + public String[] getNamedStrings() { + return mInner.getNamedVariables(NamedVariable.STRING_TYPE); + } + + /** + * This returns a list of images that have names in the Document. + * + * @return + */ + public String[] getNamedImages() { + return mInner.getNamedVariables(NamedVariable.IMAGE_TYPE); + } + /** * This sets a color based on its name. Overriding the color set in the document. * @@ -481,4 +515,32 @@ public class RemoteComposePlayer extends FrameLayout { return color; } } + + private static int[] sHapticTable = { + HapticFeedbackConstants.NO_HAPTICS, + HapticFeedbackConstants.LONG_PRESS, + HapticFeedbackConstants.VIRTUAL_KEY, + HapticFeedbackConstants.KEYBOARD_TAP, + HapticFeedbackConstants.CLOCK_TICK, + HapticFeedbackConstants.CONTEXT_CLICK, + HapticFeedbackConstants.KEYBOARD_PRESS, + HapticFeedbackConstants.KEYBOARD_RELEASE, + HapticFeedbackConstants.VIRTUAL_KEY_RELEASE, + HapticFeedbackConstants.TEXT_HANDLE_MOVE, + HapticFeedbackConstants.GESTURE_START, + HapticFeedbackConstants.GESTURE_END, + HapticFeedbackConstants.CONFIRM, + HapticFeedbackConstants.REJECT, + HapticFeedbackConstants.TOGGLE_ON, + HapticFeedbackConstants.TOGGLE_OFF, + HapticFeedbackConstants.GESTURE_THRESHOLD_ACTIVATE, + HapticFeedbackConstants.GESTURE_THRESHOLD_DEACTIVATE, + HapticFeedbackConstants.DRAG_START, + HapticFeedbackConstants.SEGMENT_TICK, + HapticFeedbackConstants.SEGMENT_FREQUENT_TICK, + }; + + private void provideHapticFeedback(int type) { + performHapticFeedback(sHapticTable[type % sHapticTable.length]); + } } 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 f59a0d3fa015a2b33d47e6e812a20897661a162e..0b650a93c9dba5b452ce29bb64188a4f7f5af6d5 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 @@ -26,6 +26,8 @@ import android.graphics.PorterDuffColorFilter; import android.graphics.RadialGradient; import android.graphics.Rect; import android.graphics.RectF; +import android.graphics.RenderEffect; +import android.graphics.RenderNode; import android.graphics.RuntimeShader; import android.graphics.Shader; import android.graphics.SweepGradient; @@ -51,6 +53,8 @@ public class AndroidPaintContext extends PaintContext { List mPaintList = new ArrayList<>(); Canvas mCanvas; Rect mTmpRect = new Rect(); // use in calculation of bounds + RenderNode mNode = null; + Canvas mPreviousCanvas = null; public AndroidPaintContext(RemoteContext context, Canvas canvas) { super(context); @@ -121,6 +125,53 @@ public class AndroidPaintContext extends PaintContext { mCanvas.scale(scaleX, scaleY); } + @Override + public void startGraphicsLayer(int w, int h) { + mNode = new RenderNode("layer"); + mNode.setPosition(0, 0, w, h); + mPreviousCanvas = mCanvas; + mCanvas = mNode.beginRecording(); + } + + @Override + public void setGraphicsLayer( + float scaleX, + float scaleY, + float rotationX, + float rotationY, + float rotationZ, + float shadowElevation, + float transformOriginX, + float transformOriginY, + float alpha, + int renderEffectId) { + if (mNode == null) { + return; + } + mNode.setScaleX(scaleX); + mNode.setScaleY(scaleY); + mNode.setRotationX(rotationX); + mNode.setRotationY(rotationY); + mNode.setRotationZ(rotationZ); + mNode.setPivotX(transformOriginX * mNode.getWidth()); + mNode.setPivotY(transformOriginY * mNode.getHeight()); + mNode.setAlpha(alpha); + if (renderEffectId == 1) { + + RenderEffect effect = RenderEffect.createBlurEffect(8f, 8f, Shader.TileMode.CLAMP); + mNode.setRenderEffect(effect); + } + } + + @Override + public void endGraphicsLayer() { + mNode.endRecording(); + mCanvas = mPreviousCanvas; + mCanvas.drawRenderNode(mNode); + // node.discardDisplayList(); + mNode = null; + } + @Override public void translate(float translateX, float translateY) { mCanvas.translate(translateX, translateY); @@ -241,6 +292,8 @@ public class AndroidPaintContext extends PaintContext { if (start != 0) { textToPaint = textToPaint.substring(start); } + } else if (end > textToPaint.length()) { + textToPaint = textToPaint.substring(start); } else { textToPaint = textToPaint.substring(start, end); } 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 f9b22a25ceabf53a2e8d702faf8ac0e0dbeaf4b8..f28e85a44c1bdaa4919a6847f705958aa37a0a72 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 @@ -18,6 +18,7 @@ package com.android.internal.widget.remotecompose.player.platform; import android.graphics.Bitmap; import android.graphics.Path; import android.graphics.PathIterator; +import android.util.Log; import com.android.internal.widget.remotecompose.core.Platform; import com.android.internal.widget.remotecompose.core.operations.PathData; @@ -27,6 +28,8 @@ import java.util.Arrays; /** Services that are needed to be provided by the platform during encoding. */ public class AndroidPlatformServices implements Platform { + private static final String LOG_TAG = "RemoteCompose"; + @Override public byte[] imageToByteArray(Object image) { if (image instanceof Bitmap) { @@ -67,6 +70,24 @@ public class AndroidPlatformServices implements Platform { return null; } + @Override + public void log(LogCategory category, String message) { + switch (category) { + case DEBUG: + Log.d(LOG_TAG, message); + break; + case INFO: + Log.i(LOG_TAG, message); + break; + case WARN: + Log.w(LOG_TAG, message); + break; + default: + Log.e(LOG_TAG, message); + break; + } + } + private float[] androidPathToFloatArray(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 e7c0cc8a915d8fbfd8a4a68d3cd523e954c93d72..7a7edba160c8abaf6b77b3d0300298c54b4ee9f5 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 @@ -20,6 +20,7 @@ import android.graphics.BitmapFactory; 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.FloatExpression; import com.android.internal.widget.remotecompose.core.operations.ShaderData; @@ -143,9 +144,9 @@ class AndroidRemoteContext extends RemoteContext { } @Override - public void runNamedAction(int id) { + public void runNamedAction(int id, Object value) { String text = getText(id); - mDocument.runNamedAction(text); + mDocument.runNamedAction(text, value); } /** @@ -199,6 +200,11 @@ class AndroidRemoteContext extends RemoteContext { mRemoteComposeState.updateFloat(id, value); } + @Override + public void overrideFloat(int id, float value) { + mRemoteComposeState.overrideFloat(id, value); + } + @Override public void loadInteger(int id, int value) { mRemoteComposeState.updateInteger(id, value); @@ -268,6 +274,11 @@ class AndroidRemoteContext extends RemoteContext { return (ShaderData) mRemoteComposeState.getFromId(id); } + @Override + public void addTouchListener(TouchListener touchExpression) { + mDocument.addTouchListener(touchExpression); + } + /////////////////////////////////////////////////////////////////////////////////////////////// // Click handling /////////////////////////////////////////////////////////////////////////////////////////////// @@ -285,4 +296,8 @@ class AndroidRemoteContext extends RemoteContext { String metadata = (String) mRemoteComposeState.getFromId(metadataId); mDocument.addClickArea(id, contentDescription, left, top, right, bottom, metadata); } + + public void hapticEffect(int type) { + mDocument.haptic(type); + } } 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 7de6988157b7bb5669cbcd9f6006eba4827342ca..b54ed8a77ec5bc88b4f7f45f38495075325fef80 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 @@ -21,6 +21,7 @@ import android.graphics.Color; import android.graphics.Point; import android.util.AttributeSet; import android.view.MotionEvent; +import android.view.VelocityTracker; import android.view.View; import android.widget.FrameLayout; @@ -38,7 +39,7 @@ public class RemoteComposeCanvas extends FrameLayout implements View.OnAttachSta RemoteComposeDocument mDocument = null; int mTheme = Theme.LIGHT; boolean mInActionDown = false; - boolean mDebug = false; + int mDebug = 0; boolean mHasClickAreas = false; Point mActionDownPoint = new Point(0, 0); AndroidRemoteContext mARContext = new AndroidRemoteContext(); @@ -65,14 +66,14 @@ public class RemoteComposeCanvas extends FrameLayout implements View.OnAttachSta } } - public void setDebug(boolean value) { + public void setDebug(int value) { if (mDebug != value) { mDebug = value; if (USE_VIEW_AREA_CLICK) { for (int i = 0; i < getChildCount(); i++) { View child = getChildAt(i); if (child instanceof ClickAreaView) { - ((ClickAreaView) child).setDebug(mDebug); + ((ClickAreaView) child).setDebug(mDebug == 1); } } } @@ -107,7 +108,7 @@ public class RemoteComposeCanvas extends FrameLayout implements View.OnAttachSta ClickAreaView viewArea = new ClickAreaView( getContext(), - mDebug, + mDebug == 1, area.getId(), area.getContentDescription(), area.getMetadata()); @@ -128,6 +129,10 @@ public class RemoteComposeCanvas extends FrameLayout implements View.OnAttachSta } } + public void setHapticEngine(CoreDocument.HapticEngine engine) { + mDocument.getDocument().setHapticEngine(engine); + } + @Override public void onViewDetachedFromWindow(View view) { removeAllViews(); @@ -137,6 +142,16 @@ public class RemoteComposeCanvas extends FrameLayout implements View.OnAttachSta return mDocument.getNamedColors(); } + /** + * Gets a array of Names of the named variables of a specific type defined in the loaded doc. + * + * @param type the type of variable NamedVariable.COLOR_TYPE, STRING_TYPE, etc + * @return array of name or null + */ + public String[] getNamedVariables(int type) { + return mDocument.getNamedVariables(type); + } + /** * set the color associated with this name. * @@ -198,7 +213,12 @@ public class RemoteComposeCanvas extends FrameLayout implements View.OnAttachSta this.mTheme = theme; } + private VelocityTracker mVelocityTracker = null; + public boolean onTouchEvent(MotionEvent event) { + int index = event.getActionIndex(); + int action = event.getActionMasked(); + int pointerId = event.getPointerId(index); if (USE_VIEW_AREA_CLICK && mHasClickAreas) { return super.onTouchEvent(event); } @@ -207,15 +227,51 @@ public class RemoteComposeCanvas extends FrameLayout implements View.OnAttachSta mActionDownPoint.x = (int) event.getX(); mActionDownPoint.y = (int) event.getY(); mInActionDown = true; + CoreDocument doc = mDocument.getDocument(); + if (doc.hasTouchListener()) { + if (mVelocityTracker == null) { + mVelocityTracker = VelocityTracker.obtain(); + } else { + mVelocityTracker.clear(); + } + mVelocityTracker.addMovement(event); + doc.touchDown(mARContext, event.getX(), event.getY()); + } return true; + case MotionEvent.ACTION_CANCEL: mInActionDown = false; + doc = mDocument.getDocument(); + if (doc.hasTouchListener()) { + mVelocityTracker.computeCurrentVelocity(1000); + float dx = mVelocityTracker.getXVelocity(pointerId); + float dy = mVelocityTracker.getYVelocity(pointerId); + doc.touchCancel(mARContext, event.getX(), event.getY(), dx, dy); + } return true; case MotionEvent.ACTION_UP: mInActionDown = false; performClick(); + doc = mDocument.getDocument(); + if (doc.hasTouchListener()) { + mVelocityTracker.computeCurrentVelocity(1000); + float dx = mVelocityTracker.getXVelocity(pointerId); + float dy = mVelocityTracker.getYVelocity(pointerId); + doc.touchUp(mARContext, event.getX(), event.getY(), dx, dy); + } return true; + case MotionEvent.ACTION_MOVE: + if (mInActionDown) { + if (mVelocityTracker != null) { + mVelocityTracker.addMovement(event); + doc = mDocument.getDocument(); + boolean repaint = doc.touchDrag(mARContext, event.getX(), event.getY()); + if (repaint) { + invalidate(); + } + } + } } return false; } @@ -292,7 +348,7 @@ public class RemoteComposeCanvas extends FrameLayout implements View.OnAttachSta mARContext.mWidth = getWidth(); mARContext.mHeight = getHeight(); mDocument.paint(mARContext, mTheme); - if (mDebug) { + if (mDebug == 1) { mCount++; if (System.nanoTime() - mTime > 1000000000L) { System.out.println(" count " + mCount + " fps"); diff --git a/core/jni/Android.bp b/core/jni/Android.bp index 2bb6e71e9000b70167e0fe18cbc02a5fd88e2b1e..25412581303c848a831c1ae2e2ebd2e10662b0ed 100644 --- a/core/jni/Android.bp +++ b/core/jni/Android.bp @@ -76,7 +76,6 @@ cc_library_shared_for_libandroid_runtime { "android_content_res_ApkAssets.cpp", "android_os_SystemClock.cpp", "android_os_SystemProperties.cpp", - "android_os_Trace.cpp", "android_text_AndroidCharacter.cpp", "android_util_AssetManager.cpp", "android_util_EventLog.cpp", @@ -104,10 +103,6 @@ cc_library_shared_for_libandroid_runtime { "system/media/private/camera/include", ], - shared_libs: [ - "libtracing_perfetto", - ], - static_libs: [ "libziparchive_for_incfs", "libguiflags", @@ -190,6 +185,7 @@ cc_library_shared_for_libandroid_runtime { "android_os_ServiceManagerNative.cpp", "android_os_SharedMemory.cpp", "android_os_storage_StorageManager.cpp", + "android_os_Trace.cpp", "android_os_UEventObserver.cpp", "android_os_incremental_IncrementalManager.cpp", "android_net_LocalSocketImpl.cpp", diff --git a/core/jni/android_hardware_input_InputWindowHandle.cpp b/core/jni/android_hardware_input_InputWindowHandle.cpp index 69f633420a0dda5cac5ae2fcb7ba736f73e4ab14..f1c4913fe00647da86c5d9938eca17487d3a1f8d 100644 --- a/core/jni/android_hardware_input_InputWindowHandle.cpp +++ b/core/jni/android_hardware_input_InputWindowHandle.cpp @@ -83,68 +83,53 @@ static struct { jmethodID ctor; } gRegionClassInfo; -static Mutex gHandleMutex; - - -// --- NativeInputWindowHandle --- - -NativeInputWindowHandle::NativeInputWindowHandle(jweak objWeak) : - mObjWeak(objWeak) { -} - -NativeInputWindowHandle::~NativeInputWindowHandle() { - JNIEnv* env = AndroidRuntime::getJNIEnv(); - env->DeleteWeakGlobalRef(mObjWeak); +// --- Global functions --- - // Clear the weak reference to the layer handle and flush any binder ref count operations so we - // do not hold on to any binder references. - // TODO(b/139697085) remove this after it can be flushed automatically - mInfo.touchableRegionCropHandle.clear(); - IPCThreadState::self()->flushCommands(); -} +sp android_view_InputWindowHandle_getHandle(JNIEnv* env, jobject obj) { + sp handle = [&]() { + jlong cachedHandle = env->GetLongField(obj, gInputWindowHandleClassInfo.ptr); + if (cachedHandle) { + return sp::fromExisting( + reinterpret_cast(cachedHandle)); + } -jobject NativeInputWindowHandle::getInputWindowHandleObjLocalRef(JNIEnv* env) { - return env->NewLocalRef(mObjWeak); -} + auto newHandle = sp::make(); + newHandle->incStrong((void*)android_view_InputWindowHandle_getHandle); + env->SetLongField(obj, gInputWindowHandleClassInfo.ptr, + reinterpret_cast(newHandle.get())); + return newHandle; + }(); -bool NativeInputWindowHandle::updateInfo() { - JNIEnv* env = AndroidRuntime::getJNIEnv(); - jobject obj = env->NewLocalRef(mObjWeak); - if (!obj) { - releaseChannel(); - return false; - } + gui::WindowInfo* windowInfo = handle->editInfo(); - mInfo.touchableRegion.clear(); + windowInfo->touchableRegion.clear(); jobject tokenObj = env->GetObjectField(obj, gInputWindowHandleClassInfo.token); if (tokenObj) { - mInfo.token = ibinderForJavaObject(env, tokenObj); + windowInfo->token = ibinderForJavaObject(env, tokenObj); env->DeleteLocalRef(tokenObj); } else { - mInfo.token.clear(); + windowInfo->token.clear(); } - mInfo.name = getStringField(env, obj, gInputWindowHandleClassInfo.name, ""); + windowInfo->name = getStringField(env, obj, gInputWindowHandleClassInfo.name, ""); - mInfo.dispatchingTimeout = std::chrono::milliseconds( + windowInfo->dispatchingTimeout = std::chrono::milliseconds( env->GetLongField(obj, gInputWindowHandleClassInfo.dispatchingTimeoutMillis)); ScopedLocalRef frameObj(env, env->GetObjectField(obj, gInputWindowHandleClassInfo.frame)); - mInfo.frame = JNICommon::rectFromObj(env, frameObj.get()); + windowInfo->frame = JNICommon::rectFromObj(env, frameObj.get()); - mInfo.surfaceInset = env->GetIntField(obj, - gInputWindowHandleClassInfo.surfaceInset); - mInfo.globalScaleFactor = env->GetFloatField(obj, - gInputWindowHandleClassInfo.scaleFactor); + windowInfo->surfaceInset = env->GetIntField(obj, gInputWindowHandleClassInfo.surfaceInset); + windowInfo->globalScaleFactor = + env->GetFloatField(obj, gInputWindowHandleClassInfo.scaleFactor); - jobject regionObj = env->GetObjectField(obj, - gInputWindowHandleClassInfo.touchableRegion); + jobject regionObj = env->GetObjectField(obj, gInputWindowHandleClassInfo.touchableRegion); if (regionObj) { for (graphics::RegionIterator it(env, regionObj); !it.isDone(); it.next()) { ARect rect = it.getRect(); - mInfo.addTouchableRegion(Rect(rect.left, rect.top, rect.right, rect.bottom)); + windowInfo->addTouchableRegion(Rect(rect.left, rect.top, rect.right, rect.bottom)); } env->DeleteLocalRef(regionObj); } @@ -153,49 +138,55 @@ bool NativeInputWindowHandle::updateInfo() { env->GetIntField(obj, gInputWindowHandleClassInfo.layoutParamsFlags)); const auto type = static_cast( env->GetIntField(obj, gInputWindowHandleClassInfo.layoutParamsType)); - mInfo.layoutParamsFlags = flags; - mInfo.layoutParamsType = type; + windowInfo->layoutParamsFlags = flags; + windowInfo->layoutParamsType = type; - mInfo.inputConfig = static_cast( + windowInfo->inputConfig = static_cast( env->GetIntField(obj, gInputWindowHandleClassInfo.inputConfig)); - mInfo.touchOcclusionMode = static_cast( + windowInfo->touchOcclusionMode = static_cast( env->GetIntField(obj, gInputWindowHandleClassInfo.touchOcclusionMode)); - mInfo.ownerPid = gui::Pid{env->GetIntField(obj, gInputWindowHandleClassInfo.ownerPid)}; - mInfo.ownerUid = gui::Uid{ + windowInfo->ownerPid = gui::Pid{env->GetIntField(obj, gInputWindowHandleClassInfo.ownerPid)}; + windowInfo->ownerUid = gui::Uid{ static_cast(env->GetIntField(obj, gInputWindowHandleClassInfo.ownerUid))}; - mInfo.packageName = getStringField(env, obj, gInputWindowHandleClassInfo.packageName, ""); - mInfo.displayId = + windowInfo->packageName = + getStringField(env, obj, gInputWindowHandleClassInfo.packageName, ""); + windowInfo->displayId = ui::LogicalDisplayId{env->GetIntField(obj, gInputWindowHandleClassInfo.displayId)}; - jobject inputApplicationHandleObj = env->GetObjectField(obj, - gInputWindowHandleClassInfo.inputApplicationHandle); + jobject inputApplicationHandleObj = + env->GetObjectField(obj, gInputWindowHandleClassInfo.inputApplicationHandle); if (inputApplicationHandleObj) { std::shared_ptr inputApplicationHandle = android_view_InputApplicationHandle_getHandle(env, inputApplicationHandleObj); if (inputApplicationHandle != nullptr) { inputApplicationHandle->updateInfo(); - mInfo.applicationInfo = *(inputApplicationHandle->getInfo()); + windowInfo->applicationInfo = *(inputApplicationHandle->getInfo()); } env->DeleteLocalRef(inputApplicationHandleObj); } - mInfo.replaceTouchableRegionWithCrop = env->GetBooleanField(obj, - gInputWindowHandleClassInfo.replaceTouchableRegionWithCrop); + windowInfo->replaceTouchableRegionWithCrop = + env->GetBooleanField(obj, gInputWindowHandleClassInfo.replaceTouchableRegionWithCrop); - jobject weakSurfaceCtrl = env->GetObjectField(obj, - gInputWindowHandleClassInfo.touchableRegionSurfaceControl.ctrl); + jobject weakSurfaceCtrl = + env->GetObjectField(obj, + gInputWindowHandleClassInfo.touchableRegionSurfaceControl.ctrl); bool touchableRegionCropHandleSet = false; if (weakSurfaceCtrl) { // Promote java weak reference. - jobject strongSurfaceCtrl = env->CallObjectMethod(weakSurfaceCtrl, - gInputWindowHandleClassInfo.touchableRegionSurfaceControl.get); + jobject strongSurfaceCtrl = + env->CallObjectMethod(weakSurfaceCtrl, + gInputWindowHandleClassInfo.touchableRegionSurfaceControl + .get); if (strongSurfaceCtrl) { - jlong mNativeObject = env->GetLongField(strongSurfaceCtrl, - gInputWindowHandleClassInfo.touchableRegionSurfaceControl.mNativeObject); + jlong mNativeObject = + env->GetLongField(strongSurfaceCtrl, + gInputWindowHandleClassInfo.touchableRegionSurfaceControl + .mNativeObject); if (mNativeObject) { auto ctrl = reinterpret_cast(mNativeObject); - mInfo.touchableRegionCropHandle = ctrl->getHandle(); + windowInfo->touchableRegionCropHandle = ctrl->getHandle(); touchableRegionCropHandleSet = true; } env->DeleteLocalRef(strongSurfaceCtrl); @@ -203,15 +194,15 @@ bool NativeInputWindowHandle::updateInfo() { env->DeleteLocalRef(weakSurfaceCtrl); } if (!touchableRegionCropHandleSet) { - mInfo.touchableRegionCropHandle.clear(); + windowInfo->touchableRegionCropHandle.clear(); } jobject windowTokenObj = env->GetObjectField(obj, gInputWindowHandleClassInfo.windowToken); if (windowTokenObj) { - mInfo.windowToken = ibinderForJavaObject(env, windowTokenObj); + windowInfo->windowToken = ibinderForJavaObject(env, windowTokenObj); env->DeleteLocalRef(windowTokenObj); } else { - mInfo.windowToken.clear(); + windowInfo->windowToken.clear(); } ScopedLocalRef @@ -220,41 +211,16 @@ bool NativeInputWindowHandle::updateInfo() { gInputWindowHandleClassInfo .focusTransferTarget)); if (focusTransferTargetObj.get()) { - mInfo.focusTransferTarget = ibinderForJavaObject(env, focusTransferTargetObj.get()); + windowInfo->focusTransferTarget = ibinderForJavaObject(env, focusTransferTargetObj.get()); } else { - mInfo.focusTransferTarget.clear(); + windowInfo->focusTransferTarget.clear(); } - env->DeleteLocalRef(obj); - return true; -} - - -// --- Global functions --- - -sp android_view_InputWindowHandle_getHandle( - JNIEnv* env, jobject inputWindowHandleObj) { - if (!inputWindowHandleObj) { - return NULL; - } - - AutoMutex _l(gHandleMutex); - - jlong ptr = env->GetLongField(inputWindowHandleObj, gInputWindowHandleClassInfo.ptr); - NativeInputWindowHandle* handle; - if (ptr) { - handle = reinterpret_cast(ptr); - } else { - jweak objWeak = env->NewWeakGlobalRef(inputWindowHandleObj); - handle = new NativeInputWindowHandle(objWeak); - handle->incStrong((void*)android_view_InputWindowHandle_getHandle); - env->SetLongField(inputWindowHandleObj, gInputWindowHandleClassInfo.ptr, - reinterpret_cast(handle)); - } return handle; } -jobject android_view_InputWindowHandle_fromWindowInfo(JNIEnv* env, gui::WindowInfo windowInfo) { +jobject android_view_InputWindowHandle_fromWindowInfo(JNIEnv* env, + const gui::WindowInfo& windowInfo) { ScopedLocalRef applicationHandle(env, android_view_InputApplicationHandle_fromInputApplicationInfo( @@ -337,18 +303,15 @@ jobject android_view_InputWindowHandle_fromWindowInfo(JNIEnv* env, gui::WindowIn // --- JNI --- static void android_view_InputWindowHandle_nativeDispose(JNIEnv* env, jobject obj) { - AutoMutex _l(gHandleMutex); - jlong ptr = env->GetLongField(obj, gInputWindowHandleClassInfo.ptr); - if (ptr) { - env->SetLongField(obj, gInputWindowHandleClassInfo.ptr, 0); - - NativeInputWindowHandle* handle = reinterpret_cast(ptr); - handle->decStrong((void*)android_view_InputWindowHandle_getHandle); + if (!ptr) { + return; } + env->SetLongField(obj, gInputWindowHandleClassInfo.ptr, 0); + auto handle = reinterpret_cast(ptr); + handle->decStrong((void*)android_view_InputWindowHandle_getHandle); } - static const JNINativeMethod gInputWindowHandleMethods[] = { /* name, signature, funcPtr */ { "nativeDispose", "()V", diff --git a/core/jni/android_hardware_input_InputWindowHandle.h b/core/jni/android_hardware_input_InputWindowHandle.h index 408e0f1bfa367bc73150e63598d36ce64292d50e..aa375e9ef47738a6807e8eedfdc685b45f27578c 100644 --- a/core/jni/android_hardware_input_InputWindowHandle.h +++ b/core/jni/android_hardware_input_InputWindowHandle.h @@ -24,24 +24,11 @@ namespace android { -class NativeInputWindowHandle : public gui::WindowInfoHandle { -public: - NativeInputWindowHandle(jweak objWeak); - virtual ~NativeInputWindowHandle(); +sp android_view_InputWindowHandle_getHandle(JNIEnv* env, + jobject inputWindowHandleObj); - jobject getInputWindowHandleObjLocalRef(JNIEnv* env); - - virtual bool updateInfo(); - -private: - jweak mObjWeak; -}; - -extern sp android_view_InputWindowHandle_getHandle( - JNIEnv* env, jobject inputWindowHandleObj); - -extern jobject android_view_InputWindowHandle_fromWindowInfo(JNIEnv* env, - gui::WindowInfo windowInfo); +jobject android_view_InputWindowHandle_fromWindowInfo(JNIEnv* env, + const gui::WindowInfo& windowInfo); } // namespace android diff --git a/core/jni/android_view_SurfaceControl.cpp b/core/jni/android_view_SurfaceControl.cpp index df87a69f02cedd76b77c987c23238f7b1556b7dc..d3bf36e60345a6e646c5b35c80f195b9434dd585 100644 --- a/core/jni/android_view_SurfaceControl.cpp +++ b/core/jni/android_view_SurfaceControl.cpp @@ -979,14 +979,16 @@ static void nativeSetAlpha(JNIEnv* env, jclass clazz, jlong transactionObj, static void nativeSetInputWindowInfo(JNIEnv* env, jclass clazz, jlong transactionObj, jlong nativeObject, jobject inputWindow) { - auto transaction = reinterpret_cast(transactionObj); + if (!inputWindow) { + jniThrowNullPointerException(env, "InputWindowHandle is null"); + return; + } - sp handle = android_view_InputWindowHandle_getHandle( - env, inputWindow); - handle->updateInfo(); + auto transaction = reinterpret_cast(transactionObj); + sp info = android_view_InputWindowHandle_getHandle(env, inputWindow); auto ctrl = reinterpret_cast(nativeObject); - transaction->setInputWindowInfo(ctrl, *handle->getInfo()); + transaction->setInputWindowInfo(ctrl, std::move(info)); } static void nativeAddWindowInfosReportedListener(JNIEnv* env, jclass clazz, jlong transactionObj, @@ -2403,6 +2405,11 @@ SurfaceComposerClient::Transaction* android_view_SurfaceTransaction_getNativeSur } } +static void nativeEnableDebugLogCallPoints(JNIEnv* env, jclass clazz, jlong transactionObj) { + auto transaction = reinterpret_cast(transactionObj); + transaction->enableDebugLogCallPoints(); +} + static const JNINativeMethod sSurfaceControlMethods[] = { // clang-format off {"nativeCreate", "(Landroid/view/SurfaceSession;Ljava/lang/String;IIIIJLandroid/os/Parcel;)J", @@ -2649,6 +2656,7 @@ static const JNINativeMethod sSurfaceControlMethods[] = { {"nativeNotifyShutdown", "()V", (void*)nativeNotifyShutdown }, {"nativeSetLuts", "(JJ[F[I[I[I[I)V", (void*)nativeSetLuts }, + {"nativeEnableDebugLogCallPoints", "(J)V", (void*)nativeEnableDebugLogCallPoints }, // clang-format on }; diff --git a/core/jni/com_android_internal_os_KernelSingleUidTimeReader.cpp b/core/jni/com_android_internal_os_KernelSingleUidTimeReader.cpp index bea5ffe31da07aa4d0f89661512de296aed7489d..a5b5057ecbacfacc5292e11a61c6123d2fa30224 100644 --- a/core/jni/com_android_internal_os_KernelSingleUidTimeReader.cpp +++ b/core/jni/com_android_internal_os_KernelSingleUidTimeReader.cpp @@ -49,27 +49,26 @@ static jlongArray getUidCpuFreqTimeMs(JNIEnv *env, jclass, jint uid) { * to the supplied multi-state counter in accordance with the counter's state. */ static jboolean addCpuTimeInFreqDelta( - jint uid, jlong counterNativePtr, jlong timestampMs, + JNIEnv *env, jint uid, jlong counterNativePtr, jlong timestampMs, std::optional>> timeInFreqDataNanos, - jlong deltaOutContainerNativePtr) { + jlongArray deltaOut) { if (!timeInFreqDataNanos) { return false; } - battery::LongArrayMultiStateCounter *counter = - reinterpret_cast(counterNativePtr); + auto counter = reinterpret_cast(counterNativePtr); size_t s = 0; for (const auto &cluster : *timeInFreqDataNanos) s += cluster.size(); - std::vector flattened; - flattened.reserve(s); - auto offset = flattened.begin(); + battery::Uint64ArrayRW flattened(s); + uint64_t *out = flattened.dataRW(); + auto offset = out; for (const auto &cluster : *timeInFreqDataNanos) { - flattened.insert(offset, cluster.begin(), cluster.end()); + memcpy(offset, cluster.data(), cluster.size() * sizeof(uint64_t)); offset += cluster.size(); } for (size_t i = 0; i < s; ++i) { - flattened[i] /= NSEC_PER_MSEC; + out[i] /= NSEC_PER_MSEC; } if (s != counter->getCount(0).size()) { // Counter has at least one state ALOGE("Mismatch between eBPF data size (%d) and the counter size (%d)", (int)s, @@ -77,29 +76,32 @@ static jboolean addCpuTimeInFreqDelta( return false; } - const std::vector &delta = counter->updateValue(flattened, timestampMs); - if (deltaOutContainerNativePtr) { - std::vector *vector = - reinterpret_cast *>(deltaOutContainerNativePtr); - *vector = delta; + const battery::Uint64Array &delta = counter->updateValue(flattened, timestampMs); + if (deltaOut) { + ScopedLongArrayRW scopedArray(env, deltaOut); + uint64_t *array = reinterpret_cast(scopedArray.get()); + if (delta.data() != nullptr) { + memcpy(array, delta.data(), s * sizeof(uint64_t)); + } else { + memset(array, 0, s * sizeof(uint64_t)); + } } return true; } -static jboolean addDeltaFromBpf(jint uid, jlong counterNativePtr, jlong timestampMs, - jlong deltaOutContainerNativePtr) { - return addCpuTimeInFreqDelta(uid, counterNativePtr, timestampMs, - android::bpf::getUidCpuFreqTimes(uid), deltaOutContainerNativePtr); +static jboolean addDeltaFromBpf(JNIEnv *env, jlong self, jint uid, jlong counterNativePtr, + jlong timestampMs, jlongArray deltaOut) { + return addCpuTimeInFreqDelta(env, uid, counterNativePtr, timestampMs, + android::bpf::getUidCpuFreqTimes(uid), deltaOut); } static jboolean addDeltaForTest(JNIEnv *env, jclass, jint uid, jlong counterNativePtr, jlong timestampMs, jobjectArray timeInFreqDataNanos, - jlong deltaOutContainerNativePtr) { + jlongArray deltaOut) { if (!timeInFreqDataNanos) { - return addCpuTimeInFreqDelta(uid, counterNativePtr, timestampMs, - std::optional>>(), - deltaOutContainerNativePtr); + return addCpuTimeInFreqDelta(env, uid, counterNativePtr, timestampMs, + std::optional>>(), deltaOut); } std::vector> timeInFreqData; @@ -113,18 +115,16 @@ static jboolean addDeltaForTest(JNIEnv *env, jclass, jint uid, jlong counterNati } timeInFreqData.push_back(cluster); } - return addCpuTimeInFreqDelta(uid, counterNativePtr, timestampMs, std::optional(timeInFreqData), - deltaOutContainerNativePtr); + return addCpuTimeInFreqDelta(env, uid, counterNativePtr, timestampMs, + std::optional(timeInFreqData), deltaOut); } static const JNINativeMethod g_single_methods[] = { {"readBpfData", "(I)[J", (void *)getUidCpuFreqTimeMs}, - - // @CriticalNative - {"addDeltaFromBpf", "(IJJJ)Z", (void *)addDeltaFromBpf}, + {"addDeltaFromBpf", "(IJJ[J)Z", (void *)addDeltaFromBpf}, // Used for testing - {"addDeltaForTest", "(IJJ[[JJ)Z", (void *)addDeltaForTest}, + {"addDeltaForTest", "(IJJ[[J[J)Z", (void *)addDeltaForTest}, }; int register_com_android_internal_os_KernelSingleUidTimeReader(JNIEnv *env) { diff --git a/core/jni/com_android_internal_os_LongArrayMultiStateCounter.cpp b/core/jni/com_android_internal_os_LongArrayMultiStateCounter.cpp index b3c41dfe81a108fcf68fca05227d1bd7005d3d72..7ffe0ed7c6cd2e322f9ab5ba182137f3806c9910 100644 --- a/core/jni/com_android_internal_os_LongArrayMultiStateCounter.cpp +++ b/core/jni/com_android_internal_os_LongArrayMultiStateCounter.cpp @@ -26,16 +26,40 @@ #include "core_jni_helpers.h" namespace android { +namespace battery { + +/** + * Implementation of Uint64Array that wraps a Java long[]. Since it uses the "critical" + * version of JNI array access (halting GC), any usage of this class must be extra quick. + */ +class JavaUint64Array : public Uint64Array { + JNIEnv *mEnv; + jlongArray mJavaArray; + uint64_t *mData; + +public: + JavaUint64Array(JNIEnv *env, jlongArray values) : Uint64Array(env->GetArrayLength(values)) { + mEnv = env; + mJavaArray = values; + mData = reinterpret_cast(mEnv->GetPrimitiveArrayCritical(mJavaArray, nullptr)); + } + + ~JavaUint64Array() override { + mEnv->ReleasePrimitiveArrayCritical(mJavaArray, mData, 0); + } + + const uint64_t *data() const override { + return mData; + } +}; static jlong native_init(jint stateCount, jint arrayLength) { - battery::LongArrayMultiStateCounter *counter = - new battery::LongArrayMultiStateCounter(stateCount, std::vector(arrayLength)); + auto *counter = new LongArrayMultiStateCounter(stateCount, Uint64Array(arrayLength)); return reinterpret_cast(counter); } static void native_dispose(void *nativePtr) { - battery::LongArrayMultiStateCounter *counter = - reinterpret_cast(nativePtr); + auto *counter = reinterpret_cast(nativePtr); delete counter; } @@ -44,80 +68,63 @@ static jlong native_getReleaseFunc() { } static void native_setEnabled(jlong nativePtr, jboolean enabled, jlong timestamp) { - battery::LongArrayMultiStateCounter *counter = - reinterpret_cast(nativePtr); + auto *counter = reinterpret_cast(nativePtr); counter->setEnabled(enabled, timestamp); } static void native_setState(jlong nativePtr, jint state, jlong timestamp) { - battery::LongArrayMultiStateCounter *counter = - reinterpret_cast(nativePtr); + auto *counter = reinterpret_cast(nativePtr); counter->setState(state, timestamp); } static void native_copyStatesFrom(jlong nativePtrTarget, jlong nativePtrSource) { - battery::LongArrayMultiStateCounter *counterTarget = - reinterpret_cast(nativePtrTarget); - battery::LongArrayMultiStateCounter *counterSource = - reinterpret_cast(nativePtrSource); + auto *counterTarget = reinterpret_cast(nativePtrTarget); + auto *counterSource = reinterpret_cast(nativePtrSource); counterTarget->copyStatesFrom(*counterSource); } -static void native_setValues(jlong nativePtr, jint state, jlong longArrayContainerNativePtr) { - battery::LongArrayMultiStateCounter *counter = - reinterpret_cast(nativePtr); - std::vector *vector = - reinterpret_cast *>(longArrayContainerNativePtr); - - counter->setValue(state, *vector); +static void native_setValues(JNIEnv *env, jclass, jlong nativePtr, jint state, jlongArray values) { + auto *counter = reinterpret_cast(nativePtr); + counter->setValue(state, JavaUint64Array(env, values)); } -static void native_updateValues(jlong nativePtr, jlong longArrayContainerNativePtr, +static void native_updateValues(JNIEnv *env, jclass, jlong nativePtr, jlongArray values, jlong timestamp) { - battery::LongArrayMultiStateCounter *counter = - reinterpret_cast(nativePtr); - std::vector *vector = - reinterpret_cast *>(longArrayContainerNativePtr); - - counter->updateValue(*vector, timestamp); + auto *counter = reinterpret_cast(nativePtr); + counter->updateValue(JavaUint64Array(env, values), timestamp); } -static void native_incrementValues(jlong nativePtr, jlong longArrayContainerNativePtr, +static void native_incrementValues(JNIEnv *env, jclass, jlong nativePtr, jlongArray values, jlong timestamp) { - battery::LongArrayMultiStateCounter *counter = - reinterpret_cast(nativePtr); - std::vector *vector = - reinterpret_cast *>(longArrayContainerNativePtr); - - counter->incrementValue(*vector, timestamp); + auto *counter = reinterpret_cast(nativePtr); + counter->incrementValue(JavaUint64Array(env, values), timestamp); } -static void native_addCounts(jlong nativePtr, jlong longArrayContainerNativePtr) { - battery::LongArrayMultiStateCounter *counter = - reinterpret_cast(nativePtr); - std::vector *vector = - reinterpret_cast *>(longArrayContainerNativePtr); - counter->addValue(*vector); +static void native_addCounts(JNIEnv *env, jclass, jlong nativePtr, jlongArray values) { + auto *counter = reinterpret_cast(nativePtr); + counter->addValue(JavaUint64Array(env, values)); } static void native_reset(jlong nativePtr) { - battery::LongArrayMultiStateCounter *counter = - reinterpret_cast(nativePtr); + auto *counter = reinterpret_cast(nativePtr); counter->reset(); } -static void native_getCounts(jlong nativePtr, jlong longArrayContainerNativePtr, jint state) { - battery::LongArrayMultiStateCounter *counter = - reinterpret_cast(nativePtr); - std::vector *vector = - reinterpret_cast *>(longArrayContainerNativePtr); - - *vector = counter->getCount(state); +static void native_getCounts(JNIEnv *env, jclass, jlong nativePtr, jlongArray values, jint state) { + auto *counter = reinterpret_cast(nativePtr); + ScopedLongArrayRW scopedArray(env, values); + auto *data = counter->getCount(state).data(); + auto size = env->GetArrayLength(values); + auto *outData = scopedArray.get(); + if (data == nullptr) { + memset(outData, 0, size * sizeof(uint64_t)); + } else { + memcpy(outData, data, size * sizeof(uint64_t)); + } } static jobject native_toString(JNIEnv *env, jclass, jlong nativePtr) { - battery::LongArrayMultiStateCounter *counter = - reinterpret_cast(nativePtr); + auto *counter = reinterpret_cast(nativePtr); return env->NewStringUTF(counter->toString().c_str()); } @@ -137,20 +144,26 @@ static void throwWriteRE(JNIEnv *env, binder_status_t status) { static void native_writeToParcel(JNIEnv *env, jclass, jlong nativePtr, jobject jParcel, jint flags) { - battery::LongArrayMultiStateCounter *counter = - reinterpret_cast(nativePtr); + auto *counter = reinterpret_cast(nativePtr); ndk::ScopedAParcel parcel(AParcel_fromJavaParcel(env, jParcel)); uint16_t stateCount = counter->getStateCount(); THROW_AND_RETURN_ON_WRITE_ERROR(AParcel_writeInt32(parcel.get(), stateCount)); // LongArrayMultiStateCounter has at least state 0 - const std::vector &anyState = counter->getCount(0); + const Uint64Array &anyState = counter->getCount(0); THROW_AND_RETURN_ON_WRITE_ERROR(AParcel_writeInt32(parcel.get(), anyState.size())); for (battery::state_t state = 0; state < stateCount; state++) { - THROW_AND_RETURN_ON_WRITE_ERROR( - ndk::AParcel_writeVector(parcel.get(), counter->getCount(state))); + const Uint64Array &value = counter->getCount(state); + if (value.data() == nullptr) { + THROW_AND_RETURN_ON_WRITE_ERROR(AParcel_writeBool(parcel.get(), false)); + } else { + THROW_AND_RETURN_ON_WRITE_ERROR(AParcel_writeBool(parcel.get(), true)); + for (size_t i = 0; i < anyState.size(); i++) { + THROW_AND_RETURN_ON_WRITE_ERROR(AParcel_writeUint64(parcel.get(), value.data()[i])); + } + } } } @@ -183,40 +196,37 @@ static jlong native_initFromParcel(JNIEnv *env, jclass, jobject jParcel) { int32_t arrayLength; THROW_AND_RETURN_ON_READ_ERROR(AParcel_readInt32(parcel.get(), &arrayLength)); - auto counter = std::make_unique(stateCount, - std::vector( - arrayLength)); - - std::vector value; - value.reserve(arrayLength); - + auto counter = + std::make_unique(stateCount, Uint64Array(arrayLength)); + Uint64ArrayRW array(arrayLength); for (battery::state_t state = 0; state < stateCount; state++) { - THROW_AND_RETURN_ON_READ_ERROR(ndk::AParcel_readVector(parcel.get(), &value)); - counter->setValue(state, value); + bool hasValues; + THROW_AND_RETURN_ON_READ_ERROR(AParcel_readBool(parcel.get(), &hasValues)); + if (hasValues) { + for (int i = 0; i < arrayLength; i++) { + THROW_AND_RETURN_ON_READ_ERROR( + AParcel_readUint64(parcel.get(), &(array.dataRW()[i]))); + } + counter->setValue(state, array); + } } return reinterpret_cast(counter.release()); } static jint native_getStateCount(jlong nativePtr) { - battery::LongArrayMultiStateCounter *counter = - reinterpret_cast(nativePtr); + auto *counter = reinterpret_cast(nativePtr); return counter->getStateCount(); } static jint native_getArrayLength(jlong nativePtr) { - battery::LongArrayMultiStateCounter *counter = - reinterpret_cast(nativePtr); + auto *counter = reinterpret_cast(nativePtr); // LongArrayMultiStateCounter has at least state 0 - const std::vector &anyState = counter->getCount(0); + const Uint64Array &anyState = counter->getCount(0); return anyState.size(); } -static jlong native_init_LongArrayContainer(jint length) { - return reinterpret_cast(new std::vector(length)); -} - static const JNINativeMethod g_LongArrayMultiStateCounter_methods[] = { // @CriticalNative {"native_init", "(II)J", (void *)native_init}, @@ -228,18 +238,18 @@ static const JNINativeMethod g_LongArrayMultiStateCounter_methods[] = { {"native_setState", "(JIJ)V", (void *)native_setState}, // @CriticalNative {"native_copyStatesFrom", "(JJ)V", (void *)native_copyStatesFrom}, - // @CriticalNative - {"native_setValues", "(JIJ)V", (void *)native_setValues}, - // @CriticalNative - {"native_updateValues", "(JJJ)V", (void *)native_updateValues}, - // @CriticalNative - {"native_incrementValues", "(JJJ)V", (void *)native_incrementValues}, - // @CriticalNative - {"native_addCounts", "(JJ)V", (void *)native_addCounts}, + // @FastNative + {"native_setValues", "(JI[J)V", (void *)native_setValues}, + // @FastNative + {"native_updateValues", "(J[JJ)V", (void *)native_updateValues}, + // @FastNative + {"native_incrementValues", "(J[JJ)V", (void *)native_incrementValues}, + // @FastNative + {"native_addCounts", "(J[J)V", (void *)native_addCounts}, // @CriticalNative {"native_reset", "(J)V", (void *)native_reset}, - // @CriticalNative - {"native_getCounts", "(JJI)V", (void *)native_getCounts}, + // @FastNative + {"native_getCounts", "(J[JI)V", (void *)native_getCounts}, // @FastNative {"native_toString", "(J)Ljava/lang/String;", (void *)native_toString}, // @FastNative @@ -252,91 +262,12 @@ static const JNINativeMethod g_LongArrayMultiStateCounter_methods[] = { {"native_getArrayLength", "(J)I", (void *)native_getArrayLength}, }; -/////////////////////// LongArrayMultiStateCounter.LongArrayContainer //////////////////////// - -static void native_dispose_LongArrayContainer(jlong nativePtr) { - std::vector *vector = reinterpret_cast *>(nativePtr); - delete vector; -} - -static jlong native_getReleaseFunc_LongArrayContainer() { - return reinterpret_cast(native_dispose_LongArrayContainer); -} - -static void native_setValues_LongArrayContainer(JNIEnv *env, jclass, jlong nativePtr, - jlongArray jarray) { - std::vector *vector = reinterpret_cast *>(nativePtr); - ScopedLongArrayRO scopedArray(env, jarray); - const uint64_t *array = reinterpret_cast(scopedArray.get()); - uint8_t size = scopedArray.size(); - - // Boundary checks are performed in the Java layer - std::copy(array, array + size, vector->data()); -} - -static void native_getValues_LongArrayContainer(JNIEnv *env, jclass, jlong nativePtr, - jlongArray jarray) { - std::vector *vector = reinterpret_cast *>(nativePtr); - ScopedLongArrayRW scopedArray(env, jarray); - - // Boundary checks are performed in the Java layer - std::copy(vector->data(), vector->data() + vector->size(), scopedArray.get()); -} - -static jboolean native_combineValues_LongArrayContainer(JNIEnv *env, jclass, jlong nativePtr, - jlongArray jarray, jintArray jindexMap) { - std::vector *vector = reinterpret_cast *>(nativePtr); - ScopedLongArrayRW scopedArray(env, jarray); - ScopedIntArrayRO scopedIndexMap(env, jindexMap); - - const uint64_t *data = vector->data(); - uint64_t *array = reinterpret_cast(scopedArray.get()); - const uint8_t size = scopedArray.size(); - - for (int i = 0; i < size; i++) { - array[i] = 0; - } - - bool nonZero = false; - for (size_t i = 0; i < vector->size(); i++) { - jint index = scopedIndexMap[i]; - if (index < 0 || index >= size) { - jniThrowExceptionFmt(env, "java/lang/IndexOutOfBoundsException", - "Index %d is out of bounds: [0, %d]", index, size - 1); - return false; - } - - if (data[i] != 0L) { - array[index] += data[i]; - nonZero = true; - } - } - - return nonZero; -} - -static const JNINativeMethod g_LongArrayContainer_methods[] = { - // @CriticalNative - {"native_init", "(I)J", (void *)native_init_LongArrayContainer}, - // @CriticalNative - {"native_getReleaseFunc", "()J", (void *)native_getReleaseFunc_LongArrayContainer}, - // @FastNative - {"native_setValues", "(J[J)V", (void *)native_setValues_LongArrayContainer}, - // @FastNative - {"native_getValues", "(J[J)V", (void *)native_getValues_LongArrayContainer}, - // @FastNative - {"native_combineValues", "(J[J[I)Z", (void *)native_combineValues_LongArrayContainer}, -}; +} // namespace battery int register_com_android_internal_os_LongArrayMultiStateCounter(JNIEnv *env) { // 0 represents success, thus "|" and not "&" return RegisterMethodsOrDie(env, "com/android/internal/os/LongArrayMultiStateCounter", - g_LongArrayMultiStateCounter_methods, - NELEM(g_LongArrayMultiStateCounter_methods)) | - RegisterMethodsOrDie(env, - "com/android/internal/os/LongArrayMultiStateCounter" - "$LongArrayContainer", - g_LongArrayContainer_methods, NELEM(g_LongArrayContainer_methods)); + battery::g_LongArrayMultiStateCounter_methods, + NELEM(battery::g_LongArrayMultiStateCounter_methods)); } - } // namespace android diff --git a/core/jni/com_android_internal_os_LongMultiStateCounter.cpp b/core/jni/com_android_internal_os_LongMultiStateCounter.cpp index 56d3fbba945865d03909aa95df117257c6f2da6f..b3bfd0bc5e0964ee99da58da6f379e6765f49d1b 100644 --- a/core/jni/com_android_internal_os_LongMultiStateCounter.cpp +++ b/core/jni/com_android_internal_os_LongMultiStateCounter.cpp @@ -28,7 +28,7 @@ namespace android { namespace battery { -typedef battery::MultiStateCounter LongMultiStateCounter; +typedef battery::MultiStateCounter LongMultiStateCounter; template <> bool LongMultiStateCounter::delta(const int64_t &previousValue, const int64_t &newValue, @@ -47,12 +47,6 @@ void LongMultiStateCounter::add(int64_t *value1, const int64_t &value2, const ui *value1 += value2; } } - -template <> -std::string LongMultiStateCounter::valueToString(const int64_t &v) const { - return std::to_string(v); -} - } // namespace battery static inline battery::LongMultiStateCounter *asLongMultiStateCounter(const jlong nativePtr) { diff --git a/core/jni/platform/host/HostRuntime.cpp b/core/jni/platform/host/HostRuntime.cpp index 3747299ccab6c894e203113558448491622da8cc..7fca1175f3d4e62ae8694f2b364aee2945fefd1c 100644 --- a/core/jni/platform/host/HostRuntime.cpp +++ b/core/jni/platform/host/HostRuntime.cpp @@ -87,7 +87,6 @@ extern int register_android_os_MessageQueue(JNIEnv* env); extern int register_android_os_Parcel(JNIEnv* env); extern int register_android_os_SystemClock(JNIEnv* env); extern int register_android_os_SystemProperties(JNIEnv* env); -extern int register_android_os_Trace(JNIEnv* env); extern int register_android_text_AndroidCharacter(JNIEnv* env); extern int register_android_util_EventLog(JNIEnv* env); extern int register_android_util_Log(JNIEnv* env); @@ -133,7 +132,6 @@ static const std::unordered_map gRegJNIMap = { #endif {"android.os.SystemClock", REG_JNI(register_android_os_SystemClock)}, {"android.os.SystemProperties", REG_JNI(register_android_os_SystemProperties)}, - {"android.os.Trace", REG_JNI(register_android_os_Trace)}, {"android.text.AndroidCharacter", REG_JNI(register_android_text_AndroidCharacter)}, {"android.util.EventLog", REG_JNI(register_android_util_EventLog)}, {"android.util.Log", REG_JNI(register_android_util_Log)}, diff --git a/core/proto/android/providers/settings/secure.proto b/core/proto/android/providers/settings/secure.proto index 606e829c41fa60596f6ed4d1c0164d036b42b22c..6af742fb23f4adf43e5d68a0bd6a1e15134b7d78 100644 --- a/core/proto/android/providers/settings/secure.proto +++ b/core/proto/android/providers/settings/secure.proto @@ -104,6 +104,7 @@ message SecureSettingsProto { optional SettingProto accessibility_single_finger_panning_enabled = 56 [ (android.privacy).dest = DEST_AUTOMATIC ]; optional SettingProto accessibility_gesture_targets = 57 [ (android.privacy).dest = DEST_AUTOMATIC ]; optional SettingProto display_daltonizer_saturation_level = 58 [ (android.privacy).dest = DEST_AUTOMATIC ]; + optional SettingProto accessibility_key_gesture_targets = 59 [ (android.privacy).dest = DEST_AUTOMATIC ]; } optional Accessibility accessibility = 2; diff --git a/core/proto/android/server/windowmanagerservice.proto b/core/proto/android/server/windowmanagerservice.proto index 654d83c827c910b94c43294c33abf7165037c364..407790c89202821ad2f4e3be51f9aea8aa149a81 100644 --- a/core/proto/android/server/windowmanagerservice.proto +++ b/core/proto/android/server/windowmanagerservice.proto @@ -465,6 +465,7 @@ message WindowStateProto { repeated .android.graphics.RectProto unrestricted_keep_clear_areas = 46; repeated .android.view.InsetsSourceProto mergedLocalInsetsSources = 47; optional int32 requested_visible_types = 48; + optional .android.graphics.RectProto dim_bounds = 49; } message IdentifierProto { diff --git a/core/proto/android/service/appwidget.proto b/core/proto/android/service/appwidget.proto index 97350ef90eec07114371616421fe844ce32cb02c..fb907196bfc7afd08ae50f95e1232ae5c30aea15 100644 --- a/core/proto/android/service/appwidget.proto +++ b/core/proto/android/service/appwidget.proto @@ -20,6 +20,8 @@ package android.service.appwidget; option java_multiple_files = true; option java_outer_classname = "AppWidgetServiceProto"; +import "frameworks/base/core/proto/android/widget/remoteviews.proto"; + // represents the object holding the dump info of the app widget service message AppWidgetServiceDumpProto { repeated WidgetProto widgets = 1; // the array of bound widgets @@ -38,3 +40,14 @@ message WidgetProto { optional int32 maxHeight = 9; optional bool restoreCompleted = 10; } + +// represents a set of widget previews for a particular provider +message GeneratedPreviewsProto { + repeated Preview previews = 1; + + // represents a particular RemoteViews preview, which may be set for multiple categories + message Preview { + repeated int32 widget_categories = 1; + optional android.widget.RemoteViewsProto views = 2; + } +} \ No newline at end of file diff --git a/core/res/Android.bp b/core/res/Android.bp index f6ca8218926c19d4ad4e8b004b885bee962ca9db..0e4e22b09e24bee1a65df5fb0be1d55313b7fa11 100644 --- a/core/res/Android.bp +++ b/core/res/Android.bp @@ -158,6 +158,7 @@ android_app { flags_packages: [ "android.app.appfunctions.flags-aconfig", "android.app.contextualsearch.flags-aconfig", + "android.app.flags-aconfig", "android.appwidget.flags-aconfig", "android.content.pm.flags-aconfig", "android.provider.flags-aconfig", @@ -171,6 +172,9 @@ android_app { "android.security.flags-aconfig", "com.android.hardware.input.input-aconfig", "aconfig_trade_in_mode_flags", + "art-aconfig-flags", + "ranging_aconfig_flags", + "aconfig_settingslib_flags", ], } diff --git a/core/res/AndroidManifest.xml b/core/res/AndroidManifest.xml index 0479318ad9edd83a262f10f6e377aba4999bd2bb..d09802a91edc6eb6686e9f364d997016af32f40a 100644 --- a/core/res/AndroidManifest.xml +++ b/core/res/AndroidManifest.xml @@ -2412,6 +2412,16 @@ android:label="@string/permlab_nearby_wifi_devices" android:protectionLevel="dangerous" /> + + + + + + + + @@ -4950,6 +4981,27 @@ + + + + + + @@ -8472,6 +8524,16 @@ android:protectionLevel="signature|privileged" android:featureFlag="com.android.tradeinmode.flags.enable_trade_in_mode" /> + + + - - - - + + diff --git a/core/res/res/drawable-watch/ic_lock_power_off.xml b/core/res/res/drawable-watch/ic_lock_power_off.xml index b437a4b70cca123a96fac15e77e92eba59e44cb2..c42d7d2e0293a2355db907228a5d0f9e056d2154 100644 --- a/core/res/res/drawable-watch/ic_lock_power_off.xml +++ b/core/res/res/drawable-watch/ic_lock_power_off.xml @@ -14,13 +14,6 @@ ~ limitations under the License. --> - - - + + + \ No newline at end of file diff --git a/core/res/res/drawable-watch/ic_restart.xml b/core/res/res/drawable-watch/ic_restart.xml index 52933aae8fe0cf6855b0c77cb7270a0e245390a0..ddcfd259d7b30c72d89b632c5b18258c60f61ef3 100644 --- a/core/res/res/drawable-watch/ic_restart.xml +++ b/core/res/res/drawable-watch/ic_restart.xml @@ -14,13 +14,6 @@ ~ limitations under the License. --> - - - + + + \ No newline at end of file diff --git a/core/res/res/drawable-watch/ic_settings.xml b/core/res/res/drawable-watch/ic_settings.xml new file mode 100644 index 0000000000000000000000000000000000000000..cef10e9eed7134bd99c3541e76c462fb06e62062 --- /dev/null +++ b/core/res/res/drawable-watch/ic_settings.xml @@ -0,0 +1,19 @@ + + + + + \ No newline at end of file diff --git a/core/res/res/drawable/ic_zen_mode_type_unknown.xml b/core/res/res/drawable/ic_zen_mode_icon_star_badge.xml similarity index 100% rename from core/res/res/drawable/ic_zen_mode_type_unknown.xml rename to core/res/res/drawable/ic_zen_mode_icon_star_badge.xml diff --git a/core/res/res/layout/input_method_switch_item_new.xml b/core/res/res/layout/input_method_switch_item_new.xml index f8710cc45358cadb7b70ce207f3cc6f8705a4344..7b241aff3fb196d033bd3dfb0976685560affd4e 100644 --- a/core/res/res/layout/input_method_switch_item_new.xml +++ b/core/res/res/layout/input_method_switch_item_new.xml @@ -18,18 +18,20 @@ + android:paddingEnd="24dp" + android:paddingVertical="8dp"> @@ -39,11 +41,26 @@ android:layout_width="wrap_content" android:layout_height="wrap_content" android:ellipsize="marquee" + android:marqueeRepeatLimit="1" android:singleLine="true" android:fontFamily="google-sans-text" android:textColor="@color/input_method_switch_on_item" android:textAppearance="?attr/textAppearanceListItem"/> + + "Naweek" "Geleentheid" "Slaap" + "Moenie Steur Nie (%1$s)" "Bestuur deur %1$s" "Aan" "Af" ", " "%1$s-%2$s" - - + "%1$s tot %2$s" "Enige kalender" "%1$s demp sekere klanke" "Daar is \'n interne probleem met jou toestel en dit sal dalk onstabiel wees totdat jy \'n fabriekterugstelling doen." @@ -2426,15 +2426,59 @@ "Stuur en ontvang boodskappe sonder ’n selfoon- of wi-fi-netwerk" "Maak Boodskappe oop" "Hoe dit werk" - + "Skakel “Kies netwerk outomaties” aan" + "Skakel “Kies netwerk outomaties” in Instellings aan sodat jou foon ’n netwerk kan vind wat met satelliet werk" + "Skakel aan" + "Gaan terug" + "Hangend …" + - + - + - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - "Hangend …" "Stel Vingerafdrukslot weer op" "%s kan nie meer herken word nie." "%1$s en %2$s kan nie meer herken word nie." diff --git a/core/res/res/values-am/strings.xml b/core/res/res/values-am/strings.xml index 22dc49ca7fb8b41e47022adc78264ed7f645aa9b..91b4ef01701443b5ac5d2154234c803818cfee1e 100644 --- a/core/res/res/values-am/strings.xml +++ b/core/res/res/values-am/strings.xml @@ -1938,13 +1938,13 @@ "የሳምንት እረፍት ቀናት" "ክስተት" "መተኛት" + "አትረብሽ (%1$s)" "በ%1$s የሚተዳደር" "በርቷል" "ጠፍቷል" "፣ " "%1$s - %2$s" - - + "ከ%1$s እስከ %2$s" "ማንኛውም ቀን መቁጠሪያ" "%1$s አንዳንድ ድምጾችን እየዘጋ ነው" "መሣሪያዎ ላይ የውስጣዊ ችግር አለ፣ የፋብሪካ ውሂብ ዳግም እስኪያስጀምሩት ድረስ ላይረጋጋ ይችላል።" @@ -2426,15 +2426,59 @@ "ያለ ሞባይል ወይም የWi-Fi አውታረ መረብ መልዕክቶችን ይላኩ እና ይቀበሉ" "መልዕክቶች ይክፈቱ" "እንዴት እንደሚሠራ" - + "«አውታረ መረብን በራስ-ሰር ምረጥ» የሚለውን ያብሩ" + "ስልክዎ ከሳተላይት ጋር የሚሠራ አውታረ መረብ እንዲያገኝ በቅንብሮች ውስጥ «አውታረ መረብን በራስ-ሰር ምረጥ» የሚለውን ያብሩ" + "አብራ" + "ወደኋላ ተመለስ" + "በመጠባበቅ ላይ..." + - + - + - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - "በመጠባበቅ ላይ..." "በጣት አሻራ መክፈቻን እንደገና ያዋቅሩ" "%s ከእንግዲህ መለየት አይችልም።" "%1$s እና %2$s ከእንግዲህ መለየት አይችሉም።" diff --git a/core/res/res/values-ar/strings.xml b/core/res/res/values-ar/strings.xml index 1aaad07761e15ef5856e9427aabe8f4e4f98f13b..6e5dcd36fd3184b42e8f35c72fa8999edb0e851b 100644 --- a/core/res/res/values-ar/strings.xml +++ b/core/res/res/values-ar/strings.xml @@ -1942,13 +1942,13 @@ "نهاية الأسبوع" "حدث" "النوم" + "عدم الإزعاج (%1$s)" "تحت إدارة \"%1$s\"" "مفعَّل" "غير مفعَّل" "، " "من %1$s إلى %2$s" - - + "من %1$s إلى %2$s" "أي تقويم" "يعمل %1$s على كتم بعض الأصوات." "حدثت مشكلة داخلية في جهازك، وقد لا يستقر وضعه حتى إجراء إعادة الضبط على الإعدادات الأصلية." @@ -2430,15 +2430,59 @@ "‏يمكنك إرسال الرسائل واستلامها بدون شبكة الجوّال أو شبكة Wi-Fi" "فتح تطبيق \"الرسائل\"" "طريقة العمل" - + "تفعيل الإعداد \"اختيار الشبكة تلقائيًا\"" + "يمكنك تفعيل الإعداد \"اختيار الشبكة تلقائيًا\" من خلال \"الإعدادات\" لكي يتمكّن هاتفك من العثور على شبكة تعمل مع القمر الصناعي" + "تفعيل" + "رجوع" + "بانتظار الإزالة من الأرشيف…" + - + - + - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - "بانتظار الإزالة من الأرشيف…" "إعادة إعداد ميزة \"فتح الجهاز ببصمة الإصبع\"" "لا يمكن بعد الآن التعرّف على \"%s\"." "لا يمكن بعد الآن التعرّف على \"%1$s\" و\"%2$s\"." diff --git a/core/res/res/values-as/strings.xml b/core/res/res/values-as/strings.xml index 74d8ed67543d574e19d852f8411796ded68b14f5..1af7810acfeb21b038ed08746ac0ad8ef709b9a0 100644 --- a/core/res/res/values-as/strings.xml +++ b/core/res/res/values-as/strings.xml @@ -1938,13 +1938,13 @@ "সপ্তাহ অন্ত" "অনুষ্ঠান" "নিদ্ৰাৰত" + "অসুবিধা নিদিব (%1$s)" "%1$sএ পৰিচালনা কৰা" "অন আছে" "অফ আছে" ", " "%1$s - %2$s" - - + "%1$sৰ পৰা %2$sলৈ" "যিকোনো কেলেণ্ডাৰ" "%1$sএ কিছুমান ধ্বনি মিউট কৰি আছে" "আপোনাৰ ডিভাইচত এটা আভ্যন্তৰীণ সমস্যা আছে আৰু আপুনি ফেক্টৰী ডেটা ৰিছেট নকৰালৈকে ই সুস্থিৰভাৱে কাম নকৰিব পাৰে।" @@ -2426,15 +2426,59 @@ "আপুনি কোনো ম’বাইল বা ৱাই-ফাই নেটৱৰ্ক নোহোৱাকৈ বাৰ্তা পঠিয়াওক আৰু লাভ কৰক" "Messages খোলক" "ই কেনেকৈ কাম কৰে" - + "\"স্বয়ংক্ৰিয়ভাৱে নেটৱৰ্ক বাছনি কৰক\" অন কৰক" + "ছেটিঙত \"স্বয়ংক্ৰিয়ভাৱে নেটৱৰ্ক বাছনি কৰক\" অন কৰক, যাতে আপোনাৰ ফ’নটোৱে উপগ্ৰহৰ সৈতে কাম কৰা এটা নেটৱৰ্ক বিচাৰি পাব পাৰে" + "অন কৰক" + "উভতি যাওক" + "বিবেচনাধীন হৈ আছে..." + - + - + - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - "বিবেচনাধীন হৈ আছে..." "ফিংগাৰপ্ৰিণ্ট আনলক পুনৰ ছেট আপ কৰক" "%s আৰু চিনাক্ত কৰিব নোৱাৰি।" "%1$s আৰু %2$s আৰু চিনাক্ত কৰিব নোৱাৰি।" diff --git a/core/res/res/values-az/strings.xml b/core/res/res/values-az/strings.xml index 22e86dfc089f0a05df40862d6920dc79c7cb6dd1..1ba96fea7a197e93851caf9a43c2ecb080219ad0 100644 --- a/core/res/res/values-az/strings.xml +++ b/core/res/res/values-az/strings.xml @@ -1938,13 +1938,13 @@ "Həftə sonu" "Tədbir" "Yuxu vaxtı" + "Narahat Etməyin (%1$s)" "%1$s idarə edir" "Aktiv" "Deaktiv" ", " "%1$s - %2$s" - - + "%1$s - %2$s" "İstənilən təqvim" "%1$s bəzi səsləri səssiz rejimə salır" "Cihazınızın daxili problemi var və istehsalçı sıfırlanması olmayana qədər qeyri-stabil ola bilər." @@ -2426,15 +2426,59 @@ "Mobil və ya Wi-Fi şəbəkəsi olmadan mesajlar göndərin və qəbul edin" "Mesajı açın" "Haqqında" - + "\"Avtomatik şəbəkə seçin\" funksiyasını aktiv edin" + "Telefonunuzun peyklə işləyən şəbəkə tapa bilməsi üçün Ayarlarda \"Avtomatik şəbəkə seçin\" funksiyasını aktiv edin" + "Aktiv edin" + "Geri qayıdın" + "Gözləmədə..." + - + - + - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - "Gözləmədə..." "Barmaqla Kilidaçmanı yenidən ayarlayın" "%s artıq tanınmır." "%1$s%2$s artıq tanınmır." diff --git a/core/res/res/values-b+sr+Latn/strings.xml b/core/res/res/values-b+sr+Latn/strings.xml index b9f909f74ca2bf48e0805f69872b28ac73016699..4c78d30c874e0e78478749075381a6fd0c36cdaa 100644 --- a/core/res/res/values-b+sr+Latn/strings.xml +++ b/core/res/res/values-b+sr+Latn/strings.xml @@ -1939,13 +1939,13 @@ "Vikend" "Događaj" "Spavanje" + "Ne uznemiravaj (%1$s)" "Upravlja: %1$s" "Uključeno" "Isključeno" ", " "%1$s%2$s" - - + "%1$s%2$s" "Bilo koji kalendar" "%1$s isključuje neke zvuke" "Došlo je do internog problema u vezi sa uređajem i možda će biti nestabilan dok ne obavite resetovanje na fabrička podešavanja." @@ -2427,15 +2427,59 @@ "Šaljite i primajte poruke bez mobilne ili WiFi mreže" "Otvori Messages" "Princip rada" - + "Uključite opciju Automatski izaberi mrežu" + "Uključite opciju Automatski izaberi mrežu u Podešavanjima da bi telefon mogao da pronađe mrežu koja radi sa satelitom" + "Uključi" + "Nazad" + "Na čekanju..." + - + - + - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - "Na čekanju..." "Ponovo podesite otključavanje otiskom prsta" "%s više ne može da se prepozna." "%1$s i %2$s više ne mogu da se prepoznaju." diff --git a/core/res/res/values-be/strings.xml b/core/res/res/values-be/strings.xml index b2520944e3ff70e50de793d6ed8673acfdc74ca3..549ec78cc7d802055f135d1d38e89bc3dec214fd 100644 --- a/core/res/res/values-be/strings.xml +++ b/core/res/res/values-be/strings.xml @@ -1940,13 +1940,13 @@ "Выхадныя" "Падзея" "Рэжым сну" + "Не турбаваць (%1$s)" "Пад кіраваннем праграмы \"%1$s\"" "Уключана" "Выключана" ", " "%1$s-%2$s" - - + "%1$s – %2$s" "Любы каляндар" "%1$s выключае некаторыя гукі" "На вашай прыладзе ўзнікла ўнутраная праблема, і яна можа працаваць нестабільна, пакуль вы не зробіце скід да заводскіх налад." @@ -2428,15 +2428,59 @@ "Вы можаце адпраўляць і атрымліваць паведамленні, калі падключэнне да мабільнай сеткі або сеткі Wi-Fi адсутнічае" "Адкрыць Паведамленні" "Як гэта працуе" - + "Уключыце параметр \"Выбіраць сетку аўтаматычна\"" + "Уключыце ў наладах параметр \"Выбіраць сетку аўтаматычна\", каб ваш тэлефон мог знаходзіць сетку, якая працуе са спадарожнікам" + "Уключыць" + "Назад" + "У чаканні..." + - + - + - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - "У чаканні..." "Наладзіць разблакіроўку адбіткам пальца паўторна" "Адбітак пальца \"%s\" больш не можа быць распазнаны." "Адбіткі пальцаў \"%1$s\" і \"%2$s\" больш не могуць быць распазнаны." diff --git a/core/res/res/values-bg/strings.xml b/core/res/res/values-bg/strings.xml index e5a08bb8c1fb7f82755c7eb093b70f73361e3925..40aae5144448102140bcf5cb5098f6579799a5aa 100644 --- a/core/res/res/values-bg/strings.xml +++ b/core/res/res/values-bg/strings.xml @@ -1938,13 +1938,13 @@ "Събота и неделя" "Събитие" "Време за сън" + "Не безпокойте (%1$s)" "Управлява се от %1$s" "Вкл." "Изкл." ", " "%1$s – %2$s" - - + "От %1$s до %2$s" "Всички календари" "%1$s заглушава някои звуци" "Възникна вътрешен проблем с устройството ви. То може да е нестабилно, докато не възстановите фабричните настройки." @@ -2426,15 +2426,59 @@ "Изпращайте и получавайте съобщения без мобилна или Wi-Fi мрежа" "Отваряне на Messages" "Начин на работа" - + "Включване на „Автоматично избиране на мрежа“" + "Включете „Автоматично избиране на мрежа“ в „Настройки“, за да може телефонът ви да намери мрежа, която работи със сателит" + "Включване" + "Назад" + "Изчаква..." + - + - + - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - "Изчаква..." "Повторно настройване на „Отключване с отпечатък“" "%s вече не може да се разпознае." "%1$s и %2$s вече не могат да бъдат разпознати." diff --git a/core/res/res/values-bn/strings.xml b/core/res/res/values-bn/strings.xml index df8a9084121591622f5497e603fb62ca28e093b0..32077d8a43744c47cdd0f81f73ebea8ab7b9fd3a 100644 --- a/core/res/res/values-bn/strings.xml +++ b/core/res/res/values-bn/strings.xml @@ -1938,13 +1938,13 @@ "সপ্তাহান্ত" "ইভেন্ট" "ঘুমানোর সময়" + "বিরক্ত করবে না (%1$s)" "%1$s ম্যানেজ করে" "চালু আছে" "বন্ধ আছে" ", " "%1$s - %2$s" - - + "%1$s থেকে %2$s" "যেকোনও ক্যালেন্ডার" "%1$s কিছু সাউন্ডকে মিউট করে দিচ্ছে" "আপনার ডিভাইসে একটি অভ্যন্তরীন সমস্যা হয়েছে, এবং আপনি যতক্ষণ না পর্যন্ত এটিকে ফ্যাক্টরি ডেটা রিসেট করছেন ততক্ষণ এটি ঠিকভাবে কাজ নাও করতে পারে৷" @@ -2426,15 +2426,59 @@ "কোনও মেবাইল বা ওয়াই-ফাই নেটওয়ার্ক ছাড়াই মেসেজ পাঠান ও রিসিভ করুন" "Messages খুলুন" "এটি কীভাবে কাজ করে" - + "\"নেটওয়ার্ক অটোমেটিক বেছে নিন\" বিকল্প চালু করুন" + "সেটিংসে \"নেটওয়ার্ক অটোমেটিক বেছে নিন\" বিকল্পটি চালু করলে আপনার ফোন এমন নেটওয়ার্ক বেছে নিতে পারবে যা স্যাটেলাইটের মাধ্যমে কাজ করে" + "চালু করুন" + "ফিরে যান" + "বাকি আছে…" + - + - + - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - "বাকি আছে…" "\'ফিঙ্গারপ্রিন্ট আনলক\' আবার সেট-আপ করুন" "%s আর শনাক্ত করা যাবে না।" "%1$s%2$s আর শনাক্ত করা যাবে না।" diff --git a/core/res/res/values-bs/strings.xml b/core/res/res/values-bs/strings.xml index 35e30ba16e4c68779237a559dc3f91b21def2b8c..266dee2b984a5a7ea5ab06538817914053e05aef 100644 --- a/core/res/res/values-bs/strings.xml +++ b/core/res/res/values-bs/strings.xml @@ -76,7 +76,7 @@ "Ne možete promijeniti postavke ID-a pozivaoca." "Prijenos podataka usmjeravanjem na %s" "Ove postavke možete uvijek promijeniti u Postavkama" - "Nema usluge prijenosa podataka na mobilnoj mreži" + "Nema usluge prenosa podataka na mobilnoj mreži" "Hitni pozivi su nedostupni" "Nema usluge govornih poziva" "Nema glasovne usluge ili hitnih poziva" @@ -89,7 +89,7 @@ "Upozorenja" "Prosljeđivanje poziva" "Način rada za hitni povratni poziv" - "Status prijenosa podataka na mobilnoj mreži" + "Status prenosa podataka na mobilnoj mreži" "SMS poruke" "Poruke govorne pošte" "Pozivanje putem WiFi-ja" @@ -310,7 +310,7 @@ "Ekran" "Aplikacija %1$s troši bateriju" "Broj aplikacija koje troše bateriju: %1$d" - "Dodirnite za detalje o potrošnji baterije i prijenosa podataka" + "Dodirnite za detalje o potrošnji baterije i prenosa podataka" "%1$s, %2$s" "Siguran način rada" "Sistem Android" @@ -812,7 +812,7 @@ "pristupi DRM certifikatima" "Dozvoljava aplikaciji da obezbijedi i koristi DRM certifikate. Nije potrebno za obične aplikacije." "prijem statusa prebacivanja preko Android prebacivanja" - "Dozvoljava aplikaciji prijem informacija o trenutnim prijenosima putem funkcije Android Beam" + "Dozvoljava aplikaciji prijem informacija o trenutnim prenosima putem funkcije Android Beam" "ukloni DRM certifikate" "Dozvoljava aplikaciji da ukloni DRM certifikate. Nije potrebno za obične aplikacije." "poveži sa servisom za poruke operatera" @@ -1163,7 +1163,7 @@ "{count,plural, =1{# dan}one{# dan}few{# dana}other{# dana}}" "{count,plural, =1{# godina}one{# godina}few{# godine}other{# godina}}" "Problem sa prikazom video sadržaja" - "Prijenos ovog video sadržaja ne može se izvršiti na ovom uređaju." + "Prenos ovog video sadržaja ne može se izvršiti na ovom uređaju." "Greška prilikom reproduciranja video sadržaja." "Uredu" "%1$s, %2$s" @@ -1478,7 +1478,7 @@ "Ponovo umetnite uređaj" "Premješta se %s" "Premještanje podataka" - "Prijenos sadržaja je završen" + "Prenos sadržaja je završen" "Sadržaj je premješten na uređaj %s" "Nije moguće premjestiti sadržaj" "Pokušajte ponovo premjestiti sadržaj" @@ -1620,9 +1620,9 @@ "%s USB disk" "USB pohrana" "Uredi" - "Upozorenje o prijenosu podataka" + "Upozorenje o prenosu podataka" "Potrošili ste %s podataka" - "Dostignuto ograničenje za prijenos podataka" + "Dostignuto ograničenje za prenos podataka" "Dostignut limit WiFi podataka" "Prijenos podataka je pauziran do kraja ciklusa" "Pređen limit mobilnih podataka" @@ -1915,7 +1915,7 @@ "Uredu" "Ušteda baterije uključuje tamnu temu i ograničava ili isključuje aktivnost u pozadini, određene vizuelne efekte i funkcije te neke mrežne veze." "Ušteda baterije uključuje tamnu temu i ograničava ili isključuje aktivnost u pozadini, određene vizuelne efekte i funkcije te neke mrežne veze." - "Radi smanjenja prijenosa podataka, Ušteda podataka sprečava da neke aplikacije šalju ili primaju podatke u pozadini. Aplikacija koju trenutno koristite može pristupati podacima, ali će to činiti rjeđe. Naprimjer, to može značiti da se slike ne prikazuju dok ih ne dodirnete." + "Radi smanjenja prenosa podataka, Ušteda podataka sprečava da neke aplikacije šalju ili primaju podatke u pozadini. Aplikacija koju trenutno koristite može pristupati podacima, ali će to činiti rjeđe. Naprimjer, to može značiti da se slike ne prikazuju dok ih ne dodirnete." "Uključiti Uštedu podataka?" "Uključi" "{count,plural, =1{Traje jednu minutu (do {formattedTime})}one{Traje # min (do {formattedTime})}few{Traje # min (do {formattedTime})}other{Traje # min (do {formattedTime})}}" @@ -1939,13 +1939,13 @@ "Vikend" "Događaj" "Spavanje" + "Ne ometaj (%1$s)" "Upravlja %1$s" "Uključeno" "Isključeno" ", " "%1$s%2$s" - - + "%1$s%2$s" "Bilo koji kalendar" "%1$s isključuje neke zvukove" "Postoji problem u vašem uređaju i može biti nestabilan dok ga ne vratite na fabričke postavke." @@ -2028,9 +2028,9 @@ "Trenutno ne možete pristupiti ovoj aplikaciji na uređaju %1$s. Umjesto toga pokušajte na uređaju Android TV." "Trenutno ne možete pristupiti ovoj aplikaciji na uređaju %1$s. Umjesto toga pokušajte na tabletu." "Trenutno ne možete pristupiti ovoj aplikaciji na uređaju %1$s. Umjesto toga pokušajte na telefonu." - "Aplikacija traži dodatna odobrenja, ali se ona ne mogu dati u sesiji prijenosa. Prvo dajte odobrenje na Android TV uređaju." - "Aplikacija traži dodatna odobrenja, ali se ona ne mogu dati u sesiji prijenosa. Prvo dajte odobrenje na tabletu." - "Aplikacija traži dodatna odobrenja, ali se ona ne mogu dati u sesiji prijenosa. Prvo dodajte odobrenje na telefonu." + "Aplikacija traži dodatna odobrenja, ali se ona ne mogu dati u sesiji prenosa. Prvo dajte odobrenje na Android TV uređaju." + "Aplikacija traži dodatna odobrenja, ali se ona ne mogu dati u sesiji prenosa. Prvo dajte odobrenje na tabletu." + "Aplikacija traži dodatna odobrenja, ali se ona ne mogu dati u sesiji prenosa. Prvo dodajte odobrenje na telefonu." "Ova aplikacija zahtijeva dodatnu sigurnost. Umjesto toga pokušajte na uređaju Android TV." "Ova aplikacija zahtijeva dodatnu sigurnost. Umjesto toga pokušajte na tabletu." "Ova aplikacija zahtijeva dodatnu sigurnost. Umjesto toga pokušajte na telefonu." @@ -2373,8 +2373,8 @@ "Provjerite aktivne aplikacije" "Nije moguće pristupiti kameri telefona s uređaja %1$s" "Nije moguće pristupiti kameri tableta s uređaja %1$s" - "Ovom ne možete pristupiti tokom prijenosa. Umjesto toga pokušajte na telefonu." - "Tokom prijenosa nije moguće gledati sliku u slici" + "Ovom ne možete pristupiti tokom prenosa. Umjesto toga pokušajte na telefonu." + "Tokom prenosa nije moguće gledati sliku u slici" "Sistemski zadano" "KARTICA %d" "Odobrenje za profil pratećeg sata da upravlja satovima" @@ -2427,15 +2427,59 @@ "Šaljite i primajte poruke bez mobilne ili WiFi mreže" "Otvorite Messages" "Kako ovo funkcionira" - + "Uključite \"Automatski odaberi mrežu\"" + "Uključite \"Automatski odaberi mrežu\" u Postavkama da telefon može pronaći mrežu koja funkcionira sa satelitom" + "Uključi" + "Nazad" + "Na čekanju…" + - + - + - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - "Na čekanju…" "Ponovo postavite otključavanje otiskom prsta" "%s se više ne može prepoznati." "%1$s i %2$s se više ne mogu prepoznati." diff --git a/core/res/res/values-ca/strings.xml b/core/res/res/values-ca/strings.xml index 7c817b9c39650755b5d2e8b44d08f541f8091720..691126bb58ba1e6b0375892eab7beb8402363666 100644 --- a/core/res/res/values-ca/strings.xml +++ b/core/res/res/values-ca/strings.xml @@ -1929,7 +1929,7 @@ "Finalitza: %1$s" "Finalitza: %1$s" "Finalitza: %1$s (propera alarma)" - "Fins que no el desactivis" + "Fins que no ho desactivis" "Fins que desactivis el mode No molestis" "%1$s / %2$s" "Replega" @@ -1939,13 +1939,13 @@ "Cap de setmana" "Esdeveniment" "Mentre dormo" + "No molestis (%1$s)" "Gestionat per %1$s" "Activat" "Desactivat" ", " "%1$s-%2$s" - - + "De %1$s a %2$s" "Qualsevol calendari" "%1$s està silenciant alguns sons" "S\'ha produït un error intern al dispositiu i és possible que funcioni de manera inestable fins que restableixis les dades de fàbrica." @@ -2427,15 +2427,59 @@ "Envia i rep missatges sense una xarxa mòbil o Wi‑Fi" "Obre Missatges" "Com funciona" - + "Activa l\'opció Selecciona la xarxa automàticament" + "Activa l\'opció Selecciona la xarxa automàticament a Configuració perquè el telèfon pugui trobar una xarxa que funcioni per satèl·lit" + "Activa" + "Torna" + "Pendent..." + - + - + - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - "Pendent..." "Torna a configurar Desbloqueig amb empremta digital" "%s ja no es pot reconèixer." "%1$s i %2$s ja no es poden reconèixer." diff --git a/core/res/res/values-cs/strings.xml b/core/res/res/values-cs/strings.xml index a9766bf1fdebba7f2df07d2a11fb4813c0200fce..f6ee489802a9fd75e3c1deaceea57c04d4716d30 100644 --- a/core/res/res/values-cs/strings.xml +++ b/core/res/res/values-cs/strings.xml @@ -1940,13 +1940,13 @@ "Víkend" "Událost" "Spánek" + "Nerušit (%1$s)" "Spravováno aplikací %1$s" "Zapnuto" "Vypnuto" ", " "%1$s%2$s" - - + "%1$s – %2$s" "V libovolném kalendáři" "%1$s vypíná určité zvuky" "V zařízení došlo k internímu problému. Dokud neprovedete obnovení továrních dat, může být nestabilní." @@ -2428,15 +2428,59 @@ "Odesílejte a přijímejte zprávy bez mobilní sítě nebo Wi-Fi" "Otevřít Zprávy" "Jak to funguje" - + "Zapněte Vybírat síť automaticky" + "Zapněte v Nastavení možnost Vybírat síť automaticky, aby telefon našel síť, která používá satelit" + "Zapnout" + "Zpět" + "Čeká na vyřízení…" + - + - + - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - "Čeká na vyřízení…" "Opětovné nastavení odemknutí otiskem prstu" "%s se nedaří rozpoznat." "%1$s%2$s se nedaří rozpoznat." diff --git a/core/res/res/values-da/strings.xml b/core/res/res/values-da/strings.xml index 58e9e6f3efd75ec23ded1aa6b8f92337ea0fc6f0..a861e3acfb231da475dbe2078517c5c0b8241945 100644 --- a/core/res/res/values-da/strings.xml +++ b/core/res/res/values-da/strings.xml @@ -563,7 +563,7 @@ "Adgang til skjulte profiler" "Giver appen adgang til skjulte profiler." "ændre størrelsen på din baggrund" - "Tillader, at appen giver tips til systembaggrundens størrelse." + "Tillader, at appen giver tip til systembaggrundens størrelse." "angive tidszone" "Tillader, at appen kan ændre tidszonen på din tablet." "Tillader, at appen kan ændre tidszonen på din Android TV-enhed." @@ -1938,13 +1938,13 @@ "Weekend" "Begivenhed" "Sover" + "Forstyr ikke (%1$s)" "Administreres af %1$s" "Til" "Fra" ", " "%1$s-%2$s" - - + "%1$s til %2$s" "Alle kalendere" "%1$s slår nogle lyde fra" "Der er et internt problem med enheden, og den vil muligvis være ustabil, indtil du gendanner fabriksdataene." @@ -2426,15 +2426,59 @@ "Send og modtag beskeder uden et mobil- eller Wi-Fi-netværk" "Åbn Beskeder" "Sådan fungerer det" - + "Aktivér \"Vælg netværk automatisk\"" + "Aktivér \"Vælg netværk automatisk\" under Indstillinger, så din telefon kan finde et netværk, der fungerer sammen med satellit" + "Aktivér" + "Gå tilbage" + "Afventer…" + - + - + - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - "Afventer…" "Konfigurer fingeroplåsning igen" "%s kan ikke længere genkendes." "%1$s og %2$s kan ikke længere genkendes." @@ -2454,7 +2498,7 @@ "Sms" "Musik" "Kalender" - "Lommeregner" + "Lomme­regner" "Kort" "Apps" "Dine fingeraftryk kan ikke længere genkendes. Konfigurer fingeroplåsning igen." diff --git a/core/res/res/values-de/strings.xml b/core/res/res/values-de/strings.xml index fa2c9cf73911d5b078900dee29c6b650b7e166bc..58c4c5e93ef123b8687a307ff1ef0fef8d75b358 100644 --- a/core/res/res/values-de/strings.xml +++ b/core/res/res/values-de/strings.xml @@ -1938,13 +1938,13 @@ "Wochenende" "Termin" "Schlafen" + "Bitte nicht stören (%1$s)" "Verwaltet von %1$s" "An" "Aus" ", " "%1$s%2$s" - - + "%1$s bis %2$s" "Alle Kalender" "Einige Töne werden von %1$s stummgeschaltet" "Es liegt ein internes Problem mit deinem Gerät vor. Möglicherweise verhält es sich instabil, bis du es auf die Werkseinstellungen zurücksetzt." @@ -2426,15 +2426,59 @@ "Du kannst ohne Mobilgerät oder WLAN Nachrichten senden und empfangen" "Messages öffnen" "So funktionierts" - + "„Netz automatisch auswählen“ aktivieren" + "Aktiviere in den Einstellungen die Option „Netz automatisch auswählen“, damit dein Smartphone ein Netzwerk finden kann, das mit dem Satelliten funktioniert" + "Aktivieren" + "Zurück" + "Ausstehend…" + - + - + - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - "Ausstehend…" "Entsperrung per Fingerabdruck neu einrichten" "%s wird nicht mehr erkannt." "%1$s und %2$s werden nicht mehr erkannt." diff --git a/core/res/res/values-el/strings.xml b/core/res/res/values-el/strings.xml index 9e360e8cc905ebfcb26da185226d4fc95e2010e1..3a32c528d72fb236a6eb93ac4c60e9c8816f4c8e 100644 --- a/core/res/res/values-el/strings.xml +++ b/core/res/res/values-el/strings.xml @@ -1938,13 +1938,13 @@ "Σαββατοκύριακο" "Συμβάν" "Ύπνος" + "Μην ενοχλείτε (%1$s)" "Διαχείριση από %1$s" "Ενεργός" "Ανενεργός" ", " "%1$s - %2$s" - - + "%1$s έως %2$s" "Οποιοδήποτε ημερολόγιο" "Το τρίτο μέρος %1$s θέτει ορισμένους ήχους σε σίγαση" "Υπάρχει ένα εσωτερικό πρόβλημα με τη συσκευή σας και ενδέχεται να είναι ασταθής μέχρι την επαναφορά των εργοστασιακών ρυθμίσεων." @@ -2426,15 +2426,59 @@ "Αποστολή και λήψη μηνυμάτων χωρίς δίκτυο κινητής τηλεφωνίας ή Wi-Fi" "Άνοιγμα Messages" "Πώς λειτουργεί" - + "Ενεργοποίηση της λειτουργίας Αυτόματη επιλογή δικτύου" + "Ενεργοποιήστε τη λειτουργία Αυτόματη επιλογή δικτύου στις Ρυθμίσεις, ώστε το τηλέφωνό σας να μπορεί να βρει ένα δίκτυο που λειτουργεί με δορυφόρο" + "Ενεργοποίηση" + "Επιστροφή" + "Σε εκκρεμότητα…" + - + - + - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - "Σε εκκρεμότητα…" "Επαναρρύθμιση λειτουργίας Ξεκλείδωμα με δακτυλικό αποτύπωμα" "Δεν είναι πλέον δυνατή η αναγνώριση του %s." "Δεν είναι πλέον δυνατή η αναγνώριση του %1$s και του %2$s." diff --git a/core/res/res/values-en-rAU/strings.xml b/core/res/res/values-en-rAU/strings.xml index d36ccf5a69a1bb79ff5cc0b197abcadd26321c17..84cc4095457dcf99e5c463fba38d44531a6349fd 100644 --- a/core/res/res/values-en-rAU/strings.xml +++ b/core/res/res/values-en-rAU/strings.xml @@ -1938,13 +1938,13 @@ "Weekend" "Event" "Sleeping" + "Do Not Disturb (%1$s)" "Managed by %1$s" "On" "Off" ", " "%1$s%2$s" - - + "%1$s to %2$s" "Any calendar" "%1$s is muting some sounds" "There\'s an internal problem with your device, and it may be unstable until you factory data reset." @@ -2426,15 +2426,59 @@ "Send and receive messages without a mobile or Wi-Fi network" "Open Messages" "How it works" - + "Turn on \'Automatically select network\'" + "Turn on \'Automatically select network\' in Settings so your phone can find a network that works with satellite" + "Turn on" + "Go back" + "Pending…" + - + - + - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - "Pending…" "Set up Fingerprint Unlock again" "%s can no longer be recognised." "%1$s and %2$s can no longer be recognised." diff --git a/core/res/res/values-en-rCA/strings.xml b/core/res/res/values-en-rCA/strings.xml index 3fac7360c8f22a1c91d917e4e650c015bfd692c4..42250049636a96da3694c6a7dae0621c3368d35d 100644 --- a/core/res/res/values-en-rCA/strings.xml +++ b/core/res/res/values-en-rCA/strings.xml @@ -1938,6 +1938,7 @@ "Weekend" "Event" "Sleeping" + "Do Not Disturb (%1$s)" "Managed by %1$s" "On" "Off" @@ -2430,6 +2431,30 @@ "Turn on" "Go back" "Pending..." + "Satellite SOS is now available" + "You can message emergency services if there\'s no mobile or Wi-Fi network. Google Messages must be your default messaging app." + "Satellite SOS isn\'t supported" + "Satellite SOS isn\'t supported on this device" + "Satellite SOS isn\'t set up" + "Make sure you\'re connected to the internet and try setup again" + "Satellite SOS isn\'t available" + "Satellite SOS isn\'t available in this country or region" + "Satellite SOS not set up" + "To message by satellite, set Google Messages as your default messaging app" + "Satellite SOS isn\'t available" + "To check if satellite SOS is available in this country or region, turn on location settings" + "Satellite messaging available" + "You can message by satellite if there\'s no mobile or Wi-Fi network. Google Messages must be your default messaging app." + "Satellite messaging not supported" + "Satellite messaging isn\'t supported on this device" + "Satellite messaging not set up" + "Make sure you\'re connected to the internet and try setup again" + "Satellite messaging not available" + "Satellite messaging isn\'t available in this country or region" + "Satellite messaging not set up" + "To message by satellite, set Google Messages as your default messaging app" + "Satellite messaging not available" + "To check if satellite messaging is available in this country or region, turn on location settings" "Set up Fingerprint Unlock again" "%s can no longer be recognized." "%1$s and %2$s can no longer be recognized." diff --git a/core/res/res/values-en-rGB/strings.xml b/core/res/res/values-en-rGB/strings.xml index 48f0e1aea91a50cd312d2c61f9d81e9c057a7db6..a80d0674d2651fcce7e96d77d472b71a3145b489 100644 --- a/core/res/res/values-en-rGB/strings.xml +++ b/core/res/res/values-en-rGB/strings.xml @@ -1938,13 +1938,13 @@ "Weekend" "Event" "Sleeping" + "Do Not Disturb (%1$s)" "Managed by %1$s" "On" "Off" ", " "%1$s%2$s" - - + "%1$s to %2$s" "Any calendar" "%1$s is muting some sounds" "There\'s an internal problem with your device, and it may be unstable until you factory data reset." @@ -2426,15 +2426,59 @@ "Send and receive messages without a mobile or Wi-Fi network" "Open Messages" "How it works" - + "Turn on \'Automatically select network\'" + "Turn on \'Automatically select network\' in Settings so your phone can find a network that works with satellite" + "Turn on" + "Go back" + "Pending…" + - + - + - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - "Pending…" "Set up Fingerprint Unlock again" "%s can no longer be recognised." "%1$s and %2$s can no longer be recognised." diff --git a/core/res/res/values-en-rIN/strings.xml b/core/res/res/values-en-rIN/strings.xml index 190e8abcff80d5bbff832443a0a55456059f7012..c123499b6883a2fdc3eace72762bda5f8f152681 100644 --- a/core/res/res/values-en-rIN/strings.xml +++ b/core/res/res/values-en-rIN/strings.xml @@ -1938,13 +1938,13 @@ "Weekend" "Event" "Sleeping" + "Do Not Disturb (%1$s)" "Managed by %1$s" "On" "Off" ", " "%1$s%2$s" - - + "%1$s to %2$s" "Any calendar" "%1$s is muting some sounds" "There\'s an internal problem with your device, and it may be unstable until you factory data reset." @@ -2426,15 +2426,59 @@ "Send and receive messages without a mobile or Wi-Fi network" "Open Messages" "How it works" - + "Turn on \'Automatically select network\'" + "Turn on \'Automatically select network\' in Settings so your phone can find a network that works with satellite" + "Turn on" + "Go back" + "Pending…" + - + - + - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - "Pending…" "Set up Fingerprint Unlock again" "%s can no longer be recognised." "%1$s and %2$s can no longer be recognised." diff --git a/core/res/res/values-es-rUS/strings.xml b/core/res/res/values-es-rUS/strings.xml index a48f5fa984b83599682291052a751a05fce4f1eb..26b4dfa4f2f4be96d31d39feeea47a8252100d53 100644 --- a/core/res/res/values-es-rUS/strings.xml +++ b/core/res/res/values-es-rUS/strings.xml @@ -1938,14 +1938,14 @@ "Noche, en la semana" "Fin de semana" "Evento" - "Dormir" + "Sueño" + "No interrumpir (%1$s)" "Administradas por %1$s" "Activado" "Desactivado" ", " "%1$s - %2$s" - - + "De %1$s a %2$s" "Cualquier calendario" "%1$s silencia algunos sonidos" "Existe un problema interno con el dispositivo, de modo que el dispositivo puede estar inestable hasta que restablezcas la configuración de fábrica." @@ -2427,15 +2427,59 @@ "Envía y recibe mensajes sin una red móvil ni Wi-Fi" "Abrir Mensajes" "Cómo funciona" - + "Activa \"Seleccionar red de forma automática\"" + "Activa \"Seleccionar red de forma automática\" en la configuración para que tu teléfono pueda encontrar una red que funcione con satélite" + "Activar" + "Atrás" + "Pendiente…" + - + - + - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - "Pendiente…" "Vuelve a configurar el Desbloqueo con huellas dactilares" "Ya no se puede reconocer %s." "Ya no se pueden reconocer %1$s y %2$s." diff --git a/core/res/res/values-es/strings.xml b/core/res/res/values-es/strings.xml index a573e9d42b1eed06f81334fab918214808db37df..166e2dac1366d45382fe30e9411b1fb145294bfc 100644 --- a/core/res/res/values-es/strings.xml +++ b/core/res/res/values-es/strings.xml @@ -1939,13 +1939,13 @@ "Fin de semana" "Evento" "Durmiendo" + "No molestar (%1$s)" "Gestionado por %1$s" "Activada" "Desactivado" ", " "%1$s-%2$s" - - + "De %1$s a %2$s" "Cualquier calendario" "%1$s silencia algunos sonidos" "Se ha producido un problema interno en el dispositivo y es posible que este no sea estable hasta que restablezcas el estado de fábrica." @@ -2427,15 +2427,59 @@ "Envía y recibe mensajes sin una red móvil ni Wi-Fi" "Abre Mensajes" "Cómo funciona" - + "Activa la opción Seleccionar red automáticamente" + "Activa la opción Seleccionar red automáticamente en Ajustes para que tu teléfono pueda encontrar una red que funcione con satélite" + "Activar" + "Volver" + "Pendiente..." + - + - + - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - "Pendiente..." "Configura Desbloqueo con huella digital de nuevo" "%s ya no puede reconocerse." "%1$s y %2$s ya no pueden reconocerse." diff --git a/core/res/res/values-et/strings.xml b/core/res/res/values-et/strings.xml index 22c777707dee4372de7fdf50a5ecb24998870cb3..fed97a191c87aca3e79b5ec422afd507d22c2602 100644 --- a/core/res/res/values-et/strings.xml +++ b/core/res/res/values-et/strings.xml @@ -1938,13 +1938,13 @@ "Nädalavahetus" "Sündmus" "Magamine" + "Mitte segada (%1$s)" "Haldab %1$s" "Sees" "Väljas" ", " "%1$s%2$s" - - + "%1$s kuni %2$s" "Mis tahes kalender" "%1$s vaigistab teatud helid" "Seadmes ilmnes sisemine probleem ja seade võib olla ebastabiilne seni, kuni lähtestate seadme tehase andmetele." @@ -2426,15 +2426,59 @@ "Sõnumite saatmine ja vastuvõtmine ilma mobiilside- või WiFi-võrguta" "Ava rakendus Messages" "Tööpõhimõtted" - + "Valiku „Vali võrk automaatselt“ sisselülitamine" + "Lülitage seadetes sisse valik „Vali võrk automaatselt“, et telefon leiaks satelliidi abil töötava võrgu" + "Lülita sisse" + "Mine tagasi" + "Ootel …" + - + - + - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - "Ootel …" "Seadistage sõrmejäljega avamine uuesti" "Sõrmejälge %s ei saa enam tuvastada." "Sõrmejälgi %1$s ja %2$s ei saa enam tuvastada." diff --git a/core/res/res/values-eu/strings.xml b/core/res/res/values-eu/strings.xml index 8d8ed8fb369ba4b80a1f7fd7468ebcdf6188c6ee..26e41140f3915e9befd4e87ff97ca5c64e9b6ea9 100644 --- a/core/res/res/values-eu/strings.xml +++ b/core/res/res/values-eu/strings.xml @@ -1532,7 +1532,7 @@ "Horma-papera" "Aldatu horma-papera" "Jakinarazpen-hautemailea" - "Errealitate birtualeko hautemailea" + "EBko hautemailea" "Baldintza-hornitzailea" "Jakinarazpenen sailkapen-zerbitzua" "VPN eginbidea aktibatuta" @@ -1938,13 +1938,13 @@ "Asteburua" "Gertaera" "Lo egiteko" + "Ez molestatzeko modua (%1$s)" "Kudeatzailea: %1$s" "Aktibatuta" "Desaktibatuta" ", " "%1$s-%2$s" - - + "%1$s-%2$s" "Edozein egutegi" "%1$s soinu batzuk isilarazten ari da" "Barneko arazo bat dago zure gailuan eta agian ezegonkor egongo da jatorrizko datuak berrezartzen dituzun arte." @@ -2426,15 +2426,59 @@ "Bidali eta jaso mezuak sare mugikorrik edo wifi-sarerik gabe" "Ireki Mezuak" "Nola funtzionatzen du?" - + "Aktibatu \"Hautatu sarea automatikoki\"" + "Aktibatu \"Hautatu sarea automatikoki\" ezarpenetan, telefonoak satelitearekin bateragarria den sare bat bilatu ahal izan dezan" + "Aktibatu" + "Egin atzera" + "Zain…" + - + - + - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - "Zain…" "Konfiguratu berriro hatz-marka bidez desblokeatzeko eginbidea" "%s ez da ezagutzen jada." "%1$s eta %2$s ez dira ezagutzen jada." diff --git a/core/res/res/values-fa/strings.xml b/core/res/res/values-fa/strings.xml index d6d950c0f12ae9197e8a5a5d9d30b62c90b8e343..a8659eb289de453d55e4cfa0491f5c2af3077342 100644 --- a/core/res/res/values-fa/strings.xml +++ b/core/res/res/values-fa/strings.xml @@ -1568,7 +1568,7 @@ "درخواست‌کننده %1$s (%2$s)" "بله" "نه" - "از حد مجاز حذف فراتر رفت" + "از حد حذف کردن فراتر رفتید" "‏%1$d مورد حذف‌شده برای %2$s، حساب %3$s وجود دارد. می‎خواهید چه کار بکنید؟" "حذف موارد" "واگرد موارد حذف شده" @@ -1938,13 +1938,13 @@ "آخر هفته" "رویداد" "خوابیدن" + "مزاحم نشوید (%1$s)" "تحت‌مدیریت %1$s" "روشن" "خاموش" "، " "%1$s - %2$s" - - + "‫%1$s تا %2$s" "هر تقویمی" "%1$s درحال قطع کردن بعضی از صداهاست" "دستگاهتان یک مشکل داخلی دارد، و ممکن است تا زمانی که بازنشانی داده‌های کارخانه انجام نگیرد، بی‌ثبات بماند." @@ -2426,15 +2426,59 @@ "‏ارسال و دریافت پیام بدون شبکه تلفن همراه یا Wi-Fi" "باز کردن «پیام‌نگار»" "روش کار" - + "روشن کردن «انتخاب خودکار شبکه»" + "برای اینکه تلفنتان بتواند شبکه‌ای که با ماهواره کار می‌کند پیدا کند، «انتخاب خودکار شبکه» را در «تنظیمات» روشن کنید" + "روشن کردن" + "برگشتن" + "درحال تعلیق…" + - + - + - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - "درحال تعلیق…" "راه‌اندازی مجدد «قفل‌گشایی با اثر انگشت»" "‫%s دیگر قابل‌شناسایی نیست." "‫%1$s و %2$s دیگر قابل‌شناسایی نیستند." diff --git a/core/res/res/values-fi/strings.xml b/core/res/res/values-fi/strings.xml index afc20f6c0fcdffaa907c5c2947a7401479cf5a79..1f4372abb677de0cc6285369067937dfcf003f34 100644 --- a/core/res/res/values-fi/strings.xml +++ b/core/res/res/values-fi/strings.xml @@ -1938,13 +1938,13 @@ "Viikonloppuna" "Tapahtuma" "Nukkuminen" + "Älä häiritse (%1$s)" "Ylläpitäjä: %1$s" "Päällä" "Pois päältä" ", " "%1$s%2$s" - - + "%1$s%2$s" "Kaikki kalenterit" "%1$s mykistää joitakin ääniä" "Laitteellasi on sisäinen ongelma, joka aiheuttaa epävakautta. Voit korjata tilanteen palauttamalla tehdasasetukset." @@ -2426,15 +2426,59 @@ "Lähetä ja vastaanota viestejä ilman mobiili- tai Wi-Fi-verkkoa" "Avaa Messages" "Näin se toimii" - + "Laita \"Valitse verkko automaattisesti\" päälle" + "Laita \"Valitse verkko automaattisesti\" päälle asetuksista, jotta puhelin voi löytää satelliitin kanssa toimivan verkon." + "Laita päälle" + "Takaisin" + "Odottaa…" + - + - + - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - "Odottaa…" "Ota sormenjälkiavaus uudelleen käyttöön" "%s ei enää ole tunnistettavissa." "%1$s ja %2$s eivät enää ole tunnistettavissa." diff --git a/core/res/res/values-fr-rCA/strings.xml b/core/res/res/values-fr-rCA/strings.xml index 6add38ad671ad562a4b525f0c6e687a3c1e9c680..f7f1474fca7b17a12f8c395029750abdfc1bf7da 100644 --- a/core/res/res/values-fr-rCA/strings.xml +++ b/core/res/res/values-fr-rCA/strings.xml @@ -1939,13 +1939,13 @@ "Fin de semaine" "Événement" "Sommeil" + "Ne pas déranger (%1$s)" "Géré par %1$s" "Activé" "Désactivée" ", " "%1$s%2$s" - - + "De %1$s à %2$s" "N\'importe quel agenda" "%1$s désactive certains sons" "Un problème interne est survenu avec votre appareil. Il se peut qu\'il soit instable jusqu\'à ce que vous le réinitialisiez à ses paramètres par défaut." @@ -2427,15 +2427,59 @@ "Envoyez et recevez des messages sans réseau cellulaire ou Wi-Fi" "Ouvrir Messages" "Fonctionnement" - + "Activer « Sélectionner automatiquement le réseau »" + "Activez « Sélectionner automatiquement le réseau » dans les paramètres pour que votre téléphone puisse trouver un réseau qui fonctionne par satellite" + "Activer" + "Retour" + "En attente…" + - + - + - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - "En attente…" "Configurer le Déverrouillage par empreinte digitale à nouveau" "L\'empreinte digitale %s ne peut plus être reconnue." "Les empreintes digitales %1$s et %2$s ne peuvent plus être reconnues." diff --git a/core/res/res/values-fr/strings.xml b/core/res/res/values-fr/strings.xml index 9de43343ded80c92b65109e4e521a28984192b3c..bed2927867c4b26e57ec4c552cdf9f975c186763 100644 --- a/core/res/res/values-fr/strings.xml +++ b/core/res/res/values-fr/strings.xml @@ -1939,13 +1939,13 @@ "Week-end" "Événement" "Sommeil" + "Ne pas déranger (%1$s)" "Géré par %1$s" "Activé" "Désactivé" ", " "%1$s – %2$s" - - + "De %1$s à %2$s" "Tous les agendas" "%1$s coupe certains sons" "Un problème interne lié à votre appareil est survenu. Ce dernier risque d\'être instable jusqu\'à ce que vous rétablissiez la configuration d\'usine." @@ -2427,15 +2427,59 @@ "Envoyer et recevoir des messages sans réseau mobile ou Wi-Fi" "Ouvrir Messages" "Fonctionnement" - + "Activer \"Sélectionner automatiquement le réseau\"" + "Activez \"Sélectionner automatiquement le réseau\" dans Paramètres pour que votre téléphone puisse trouver un réseau compatible avec un satellite" + "Activer" + "Retour" + "En attente…" + - + - + - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - "En attente…" "Reconfigurer le déverrouillage par empreinte digitale" "%s ne peut plus être reconnue." "%1$s et %2$s ne peuvent plus être reconnues." diff --git a/core/res/res/values-gl/strings.xml b/core/res/res/values-gl/strings.xml index 06c63ecd02acbbff3d5d28de69e4334c2e92ee9c..532c078801001708bb2baa21900e8c1a657d2330 100644 --- a/core/res/res/values-gl/strings.xml +++ b/core/res/res/values-gl/strings.xml @@ -612,8 +612,8 @@ "Permite que a aplicación determine a posición relativa entre os dispositivos próximos que usen banda ultralarga" "interactuar con dispositivos wifi próximos" "Permítelle á aplicación enviar anuncios e conectarse a dispositivos wifi próximos, e determinar a súa posición relativa" - "Información do servizo de pago de NFC preferido" - "Permite que a aplicación obteña información do servizo de pago de NFC preferido, como as axudas rexistradas e o destino da ruta." + "Información do servizo de pagos de NFC preferido" + "Permite que a aplicación obteña información do servizo de pagos de NFC preferido, como as axudas rexistradas e o destino da ruta." "controlar Near Field Communication" "Permite á aplicación comunicarse con etiquetas, tarxetas e lectores Near Field Communication (NFC)." "Evento de transacción no elemento seguro" @@ -1938,13 +1938,13 @@ "Fin de semana" "Evento" "Mentres durmo" + "Modo Non molestar (%1$s)" "Xestionada por %1$s" "Activada" "Desactivada" ", " "%1$s - %2$s" - - + "De %1$s a %2$s" "Calquera calendario" "%1$s está silenciando algúns sons" "Produciuse un erro interno no teu dispositivo e quizais funcione de maneira inestable ata o restablecemento dos datos de fábrica." @@ -2426,15 +2426,59 @@ "Envía e recibe mensaxes sen ter acceso a redes de telefonía móbil ou wifi" "Abrir Mensaxes" "Como funciona?" - + "Activar Seleccionar rede automaticamente" + "Activa a opción Seleccionar rede automaticamente en Configuración para que o teléfono busque unha rede que funcione co satélite" + "Activar" + "Volver" + "Pendente..." + - + - + - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - "Pendente..." "Configura de novo o desbloqueo dactilar" "%s xa non se recoñece." "%1$s e %2$s xa non se recoñecen." diff --git a/core/res/res/values-gu/strings.xml b/core/res/res/values-gu/strings.xml index b0194ca804003e241cc7919bfa60674bb1f2b00d..7e36c616e81602d70ee0137d8d0c00dcd54f1669 100644 --- a/core/res/res/values-gu/strings.xml +++ b/core/res/res/values-gu/strings.xml @@ -1938,13 +1938,13 @@ "સપ્તાહાંત" "ઇવેન્ટ" "નિષ્ક્રિય" + "ખલેલ પાડશો નહીં (%1$s)" "%1$s દ્વારા મેનેજ કરવામાં આવે છે" "ચાલુ છે" "બંધ છે" ", " "%1$s - %2$s" - - + "%1$sથી %2$s" "કોઈપણ કૅલેન્ડર" "%1$s અમુક અવાજોને મ્યૂટ કરે છે" "તમારા ઉપકરણમાં આંતરિક સમસ્યા છે અને જ્યાં સુધી તમે ફેક્ટરી ડેટા ફરીથી સેટ કરશો નહીં ત્યાં સુધી તે અસ્થિર રહી શકે છે." @@ -2426,15 +2426,59 @@ "મોબાઇલ કે વાઇ-ફાઇ નેટવર્ક વિના મેસેજ મોકલો અને મેળવો" "Messages ખોલો" "તેની કામ કરવાની રીત" - + "\"ઑટોમૅટિક રીતે નેટવર્ક પસંદ કરો\" ચાલુ કરો" + "સેટિંગમાં \"ઑટોમૅટિક રીતે નેટવર્ક પસંદ કરો\" ચાલુ કરો, જેથી તમારો ફોન સૅટલાઇટ સાથે કામ કરતું નેટવર્ક શોધી શકે" + "ચાલુ કરો" + "પાછા જાઓ" + "બાકી..." + - + - + - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - "બાકી..." "ફિંગરપ્રિન્ટ અનલૉક સુવિધાનું ફરી સેટઅપ કરો" "હવે %s ઓળખી શકાતી નથી." "હવે %1$s અને %2$s ઓળખી શકાતી નથી." diff --git a/core/res/res/values-hi/strings.xml b/core/res/res/values-hi/strings.xml index 7e27cff5ba1332f1c886b0bf3bbe1666a2355deb..38e79b1988dc30b5c2c9de3f2b452dc61ee836e7 100644 --- a/core/res/res/values-hi/strings.xml +++ b/core/res/res/values-hi/strings.xml @@ -1937,15 +1937,15 @@ "हफ़्ते की रात" "सप्ताहांत" "इवेंट" - "सोने का समय" + "स्लीपिंग मोड" + "\'परेशान न करें\' सुविधा (%1$s)" "मैनेज करने वाला ऐप्लिकेशन: %1$s" "चालू है" "बंद है" ", " "%1$s - %2$s" - - - "कोई भी कैलेंडर" + "%1$s से %2$s" + "किसी भी कैलेंडर के इवेंट के लिए" "%1$s कुछ आवाज़ें म्‍यूट कर रहा है" "आपके डिवाइस में कोई अंदरूनी समस्या है और यह तब तक ठीक नहीं होगी जब तक आप फ़ैक्‍टरी डेटा रीसेट नहीं करते." "आपके डिवाइस के साथ कोई आंतरिक गड़बड़ी हुई. विवरणों के लिए अपने निर्माता से संपर्क करें." @@ -2426,15 +2426,59 @@ "मोबाइल या वाई-फ़ाई नेटवर्क के बिना मैसेज भेजें और पाएं" "Messages ऐप्लिकेशन खोलें" "यह सेटिंग कैसे काम करती है" - + "\"नेटवर्क अपने-आप चुना जाए\" को चालू करें" + "सेटिंग में जाकर, \"नेटवर्क अपने-आप चुना जाए\" को चालू करें, ताकि आपका फ़ोन ऐसा नेटवर्क ढूंढ सके जो सैटलाइट के साथ काम करता है" + "चालू करें" + "रद्द करें" + "प्रोसेस जारी है..." + - + - + - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - "प्रोसेस जारी है..." "फ़िंगरप्रिंट अनलॉक की सुविधा दोबारा सेट अप करें" "अब %s की पहचान नहीं की जा सकती." "अब %1$s और %2$s की पहचान नहीं की जा सकती." diff --git a/core/res/res/values-hr/strings.xml b/core/res/res/values-hr/strings.xml index 1066559d8f7c8deb994094f08e27396daabfb619..90e228e65afaa0fc97678d2989de7d049da9cc90 100644 --- a/core/res/res/values-hr/strings.xml +++ b/core/res/res/values-hr/strings.xml @@ -1939,13 +1939,13 @@ "Vikend" "Događaj" "Spavanje" + "Ne uznemiravaj (%1$s)" "Upravlja %1$s" "Uključeno" "Isključeno" ", " "%1$s%2$s" - - + "%1$s%2$s" "Bilo koji kalendar" "%1$s isključuje neke zvukove" "Na vašem uređaju postoji interni problem i možda neće biti stabilan dok ga ne vratite na tvorničko stanje." @@ -2427,15 +2427,59 @@ "Šaljite i primajte poruke kad nije dostupna mobilna ili Wi-Fi mreža" "Otvori Poruke" "Kako to funkcionira" - + "Uključite opciju Automatski odaberi mrežu" + "Uključite opciju Automatski odaberi mrežu u postavkama da bi telefon mogao pronaći mrežu koja funkcionira sa satelitom" + "Uključi" + "Natrag" + "Na čekanju..." + - + - + - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - "Na čekanju..." "Ponovno postavite otključavanje otiskom prsta" "%s više se ne prepoznaje." "%1$s i %2$s više se ne prepoznaju." diff --git a/core/res/res/values-hu/strings.xml b/core/res/res/values-hu/strings.xml index c76d9f493c307d4dadd2591215c894ce8bc7ce58..d5a28f8e21983ceeaf61276a0d6c04c1edbfd43b 100644 --- a/core/res/res/values-hu/strings.xml +++ b/core/res/res/values-hu/strings.xml @@ -1938,13 +1938,13 @@ "Hétvége" "Esemény" "Alvás" + "Ne zavarjanak (%1$s)" "Kezelő: %1$s" "Bekapcsolva" "Kikapcsolva" ", " "%1$s%2$s" - - + "%1$s%2$s" "Bármilyen naptár" "A(z) %1$s lenémít néhány hangot" "Belső probléma van az eszközzel, és instabil lehet, amíg vissza nem állítja a gyári adatokat." @@ -2426,15 +2426,59 @@ "Küldhet és fogadhat üzeneteket mobil- és Wi-Fi-hálózat nélkül is" "A Messages megnyitása" "Hogyan működik?" - + "Kapcsolja be a „Hálózat automatikus kiválasztása” beállítást" + "Kapcsolja be a „Hálózat automatikus kiválasztása” beállítást a Beállításokban, hogy a telefon megtalálja a műholddal működő hálózatot" + "Bekapcsolás" + "Vissza" + "Függőben…" + - + - + - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - "Függőben…" "A Feloldás ujjlenyomattal funkció újbóli beállítása" "A következő már nem felismerhető: %s." "A következők már nem felismerhetők: %1$s és %2$s." diff --git a/core/res/res/values-hy/strings.xml b/core/res/res/values-hy/strings.xml index c91918da268efdce9b086d8a8fa8e474620e9d31..14534a7ca2a8187e641cb59b1d859c66dc9577c2 100644 --- a/core/res/res/values-hy/strings.xml +++ b/core/res/res/values-hy/strings.xml @@ -1112,7 +1112,7 @@ "Sym+" "Function+" "բացակ" - "մուտք" + "enter" "ջնջել" "Որոնել" "Որոնում..." @@ -1600,7 +1600,7 @@ "Պատրաստ է" "Ռեժիմի փոփոխում" "Shift" - "Մուտք" + "Enter" "Ընտրել ծրագիր" "Չհաջողվեց գործարկել %s ծրագիրը" "Կիսվել" @@ -1938,13 +1938,13 @@ "Շաբաթ-կիրակի" "Միջոցառում" "Քնի ժամ" + "Չանհանգստացնել (%1$s)" "Կառավարվում է %1$s հավելվածի կողմից" "Միացված է" "Անջատված է" ", " "%1$s%2$s" - - + "%1$s%2$s" "Ցանկացած օրացույց" "%1$s-ն անջատում է որոշ ձայներ" "Սարքում ներքին խնդիր է առաջացել և այն կարող է կրկնվել, մինչև չվերականգնեք գործարանային կարգավորումները:" @@ -2426,15 +2426,59 @@ "Ուղարկեք և ստացեք հաղորդագրություններ առանց բջջային կամ Wi-Fi ցանցի" "Բացել Messages-ը" "Ինչպես է դա աշխատում" - + "Միացրեք «Ավտոմատ ընտրել ցանցը»" + "Կարգավորումներում միացրեք «Ավտոմատ ընտրել ցանցը», որպեսզի ձեր հեռախոսը կարողանա արբանյակի հետ աշխատող ցանց գտնել" + "Միացնել" + "Հետ" + "Առկախ է…" + - + - + - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - "Առկախ է…" "Նորից կարգավորեք մատնահետքով ապակողպումը" "%s մատնահետքն այլևս չի կարող ճանաչվել։" "%1$s և %2$s մատնահետքերն այլևս չեն կարող ճանաչվել։" diff --git a/core/res/res/values-in/strings.xml b/core/res/res/values-in/strings.xml index 498463083d683146ae00911720a8ee5681354815..360102f13139dd5308555d23c4a044b4ea6c8b0f 100644 --- a/core/res/res/values-in/strings.xml +++ b/core/res/res/values-in/strings.xml @@ -1938,13 +1938,13 @@ "Akhir pekan" "Acara" "Tidur" + "Jangan Ganggu (%1$s)" "Dikelola oleh %1$s" "Aktif" "Nonaktif" ", " "%1$s - %2$s" - - + "%1$s hingga %2$s" "Kalender mana saja" "%1$s mematikan beberapa suara" "Ada masalah dengan perangkat. Hal ini mungkin membuat perangkat jadi tidak stabil dan perlu dikembalikan ke setelan pabrik." @@ -2426,15 +2426,59 @@ "Mengirim dan menerima pesan tanpa jaringan seluler atau Wi-Fi" "Buka Message" "Cara kerjanya" - + "Aktifkan \"Pilih jaringan secara otomatis\"" + "Aktifkan \"Pilih jaringan secara otomatis\" di Setelan agar ponsel dapat menemukan jaringan yang berfungsi dengan satelit" + "Aktifkan" + "Kembali" + "Tertunda..." + - + - + - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - "Tertunda..." "Siapkan Buka dengan Sidik Jari lagi" "%s tidak dapat dikenali lagi." "%1$s dan %2$s tidak dapat dikenali lagi." diff --git a/core/res/res/values-is/strings.xml b/core/res/res/values-is/strings.xml index 47a6c3584f5298a76cd138462c99a3d8b533d6a4..9d3e2e42fb119f72f77c126a4c2590514e6c472c 100644 --- a/core/res/res/values-is/strings.xml +++ b/core/res/res/values-is/strings.xml @@ -1938,13 +1938,13 @@ "Helgi" "Viðburður" "Svefn" + "Ónáðið ekki (%1$s)" "Stýrt af %1$s" "Kveikt" "Slökkt" ", " "%1$s - %2$s" - - + "%1$s til %2$s" "Öll dagatöl" "%1$s þaggar í einhverjum hljóðum" "Innra vandamál kom upp í tækinu og það kann að vera óstöðugt þangað til þú núllstillir það." @@ -2426,15 +2426,59 @@ "Senda og fá skilaboð án tengingar við farsímakerfi eða Wi-Fi-net" "Opna Messages" "Svona virkar þetta" - + "Kveiktu á „Velja net sjálfkrafa“" + "Kveiktu á „Velja net sjálfkrafa“ í stillingunum til að gera símanum kleift að finna net sem virkar með gervihnetti" + "Kveikja" + "Til baka" + "Í bið…" + - + - + - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - "Í bið…" "Setja upp fingrafarskenni aftur" "Ekki er hægt að bera kennsl á %s lengur." "Ekki er hægt að bera kennsl á %1$s og %2$s lengur." diff --git a/core/res/res/values-it/strings.xml b/core/res/res/values-it/strings.xml index 4070f1160aecb143955b1dc0b014261fe44791bf..ee7f08db3e51b90b5056d59ebd1293d8953ccd99 100644 --- a/core/res/res/values-it/strings.xml +++ b/core/res/res/values-it/strings.xml @@ -1939,6 +1939,7 @@ "Fine settimana" "Evento" "Notte" + "Non disturbare (%1$s)" "Gestione: app %1$s" "On" "Off" @@ -2431,6 +2432,54 @@ "Attiva" "Indietro" "In attesa…" + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + "Riconfigura lo Sblocco con l\'Impronta" "%s non può più essere riconosciuto." "%1$s e %2$s non possono più essere riconosciuti." diff --git a/core/res/res/values-iw/strings.xml b/core/res/res/values-iw/strings.xml index 8b0dd8069f587a69a87feb4ae63fd852cef42ff0..e3f2a7cab5ebce99cdf3e6645cc74024394903b2 100644 --- a/core/res/res/values-iw/strings.xml +++ b/core/res/res/values-iw/strings.xml @@ -1939,13 +1939,13 @@ "סוף השבוע" "אירוע" "שינה" + "נא לא להפריע (%1$s)" "בניהול של %1$s" "מצב פעיל" "מצב מושבת" ", " "‫%1$s%2$s" - - + "‫%1$s עד %2$s" "כל יומן" "חלק מהצלילים מושתקים על ידי %1$s" "קיימת בעיה פנימית במכשיר שלך, וייתכן שהוא לא יתפקד כראוי עד שיבוצע איפוס לנתוני היצרן." @@ -2427,15 +2427,59 @@ "‏אפשר לשלוח ולקבל הודעות ללא רשת סלולרית או Wi-Fi" "‏לפתיחת Messages" "איך זה עובד" - + "הפעלת האפשרות \'בחירה אוטומטית של הרשת\'" + "כדי למצוא רשת שעובדת עם לוויין בטלפון, צריך להפעיל את האפשרות \'בחירה אוטומטית של הרשת\' בהגדרות" + "הפעלה" + "חזרה" + "בהמתנה..." + - + - + - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - "בהמתנה..." "הגדרה חוזרת של \'ביטול הנעילה בטביעת אצבע\'" "כבר לא ניתן לזהות את %s." "כבר לא ניתן לזהות את %1$s ואת %2$s." diff --git a/core/res/res/values-ja/strings.xml b/core/res/res/values-ja/strings.xml index 2f389293d84333110e0ee3e96dd3db535b2c2531..0d3a80c9b69a6f174d1827f1e8ae3f17ce137cf2 100644 --- a/core/res/res/values-ja/strings.xml +++ b/core/res/res/values-ja/strings.xml @@ -1938,13 +1938,13 @@ "週末" "予定モード" "おやすみモード" + "サイレント モード(%1$s)" "%1$s によって管理されています" "ON" "OFF" "、 " "%1$s%2$s" - - + "%1$s%2$s" "すべてのカレンダー" "%1$s により一部の音はミュートに設定" "デバイスで内部的な問題が発生しました。データが初期化されるまで不安定になる可能性があります。" @@ -2426,15 +2426,59 @@ "モバイル ネットワークや Wi-Fi ネットワークがなくてもメッセージを送受信できます" "メッセージ アプリを開く" "仕組み" - + "[ネットワークを自動的に選択] を ON にする" + "設定で [ネットワークを自動的に選択] を ON にすると、衛星と通信可能なネットワークをスマートフォンが検出できるようになります" + "ON にする" + "戻る" + "保留中..." + - + - + - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - "保留中..." "指紋認証をもう一度設定してください" "%sを認識できなくなりました。" "%1$s%2$sを認識できなくなりました。" diff --git a/core/res/res/values-ka/strings.xml b/core/res/res/values-ka/strings.xml index 2d9aecd908cab86bc584c14f09b61181497ff6f3..19177d65a991d7deccd642a429e113b48e3e9f93 100644 --- a/core/res/res/values-ka/strings.xml +++ b/core/res/res/values-ka/strings.xml @@ -1938,13 +1938,13 @@ "შაბათ-კვირა" "მოვლენა" "ძილისას" + "არ შემაწუხოთ (%1$s)" "მართავს %1$s" "ჩართული" "გამორთული" ", " "%1$s%2$s" - - + "%1$s-%2$s" "ნებისმიერი კალენდარი" "%1$s ზოგიერთ ხმას ადუმებს" "ფიქსირდება თქვენი მ ოწყობილობის შიდა პრობლემა და შეიძლება არასტაბილური იყოს, სანამ ქარხნულ მონაცემების არ განაახლებთ." @@ -2426,15 +2426,59 @@ "შეტყობინებების გაგზავნა და მიღება მობილური ან Wi-Fi ქსელის გარეშე" "Messages-ის გახსნა" "მუშაობის პრინციპი" - + "„ქსელის ავტომატურად არჩევის“ ჩართვა" + "ჩართეთ „ქსელის ავტომატურად არჩევა“ პარამეტრებში, რათა თქვენმა ტელეფონმა სატელიტთან თავსებადი ქსელის პოვნა შეძლოს" + "ჩართვა" + "უკან დაბრუნება" + "მომლოდინე..." + - + - + - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - "მომლოდინე..." "ანაბეჭდით განბლოკვის ხელახლა დაყენება" "%s-ის ამოცნობა ვეღარ ხერხდება." "%1$s-ისა და %2$s-ის ამოცნობა ვეღარ ხერხდება." diff --git a/core/res/res/values-kk/strings.xml b/core/res/res/values-kk/strings.xml index 6986a7b914a56287e103d0f28077583a9395f2b1..70774d6cafe14bbaca3cf6b6fabf22d9e89ca8b4 100644 --- a/core/res/res/values-kk/strings.xml +++ b/core/res/res/values-kk/strings.xml @@ -1938,13 +1938,13 @@ "Демалыс күндері" "Іс-шара" "Ұйқы режимі" + "Мазаламау (%1$s)" "%1$s басқарады." "Қосулы" "Өшірулі" ", " "%1$s%2$s" - - + "%1$s%2$s" "Кез келген күнтізбе" "%1$s кейбір дыбыстарды өшіруде" "There\'s an internal problem with your device, and it may be unstable until you factory data reset." @@ -2426,15 +2426,59 @@ "Хабарландыруларды мобильдік желіге немесе Wi-Fi желісіне қосылмай жіберіңіз және алыңыз." "Messages қолданбасын ашу" "Бұл қалай орындалады?" - + "\"Желіні автоматты түрде таңдау\" опциясын қосу" + "Телефоныңыз жерсерікпен жұмыс істейтін желіні таба алуы үшін, \"Параметрлер\" бөлімінен \"Желіні автоматты түрде таңдау\" опциясын қосыңыз." + "Қосу" + "Артқа" + "Дайын емес…" + - + - + - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - "Дайын емес…" "Саусақ ізімен ашу функциясын қайта реттеу" "%s бұдан былай танылмайды." "%1$s және %2$s бұдан былай танылмайды." diff --git a/core/res/res/values-km/strings.xml b/core/res/res/values-km/strings.xml index b2bb78b611d58e95f97a2cd6030f2d63dce1126a..c758e0501aa87cd9a9c987eade16c0e97c6f0e07 100644 --- a/core/res/res/values-km/strings.xml +++ b/core/res/res/values-km/strings.xml @@ -1938,13 +1938,13 @@ "ចុងសប្ដាហ៍" "ព្រឹត្តិការណ៍" "កំពុងដេក" + "កុំ​រំខាន (%1$s)" "គ្រប់គ្រងដោយ %1$s" "បើក" "បិទ" ", " "%1$s - %2$s" - - + "%1$s ដល់ %2$s" "ប្រតិទិនណាមួយ" "%1$s កំពុង​បិទសំឡេង​មួយចំនួន" "មានបញ្ហាខាងក្នុងឧបករណ៍របស់អ្នក ហើយវាអ្នកមិនមានស្ថេរភាព រហូតទាល់តែអ្នកកំណត់ដូចដើមវិញទាំងស្រុង។" @@ -2426,15 +2426,59 @@ "ផ្ញើ និងទទួលសារដោយគ្មានបណ្ដាញ Wi-Fi ឬបណ្ដាញទូរសព្ទចល័ត" "បើក​កម្មវិធី Messages" "របៀបដែលវាដំណើរការ" - + "បើក \"ជ្រើសរើស​បណ្ដាញ​ដោយស្វ័យប្រវត្តិ\"" + "បើក \"ជ្រើសរើស​បណ្ដាញ​ដោយស្វ័យប្រវត្តិ\" នៅក្នុង​ការកំណត់​ ដើម្បីឱ្យ​ទូរសព្ទ​របស់អ្នកអាចស្វែងរកបណ្ដាញ ដែល​ដំណើរការតាមរយៈផ្កាយរណប" + "បើក" + "ថយ​ក្រោយ" + "កំពុងរង់ចាំ..." + - + - + - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - "កំពុងរង់ចាំ..." "រៀបចំការដោះសោ​ដោយស្កេន​ស្នាមម្រាមដៃម្ដងទៀត" "លែងអាចសម្គាល់ %s បានទៀតហើយ។" "លែងអាចសម្គាល់ %1$s និង %2$s បានទៀតហើយ។" diff --git a/core/res/res/values-kn/strings.xml b/core/res/res/values-kn/strings.xml index 8332cfcbd2ecc433ea85171a0b584cd946f9031e..8efcd08693031aa8af74e46e2a22fc35cf0ddb5a 100644 --- a/core/res/res/values-kn/strings.xml +++ b/core/res/res/values-kn/strings.xml @@ -1938,13 +1938,13 @@ "ವಾರಾಂತ್ಯ" "ಈವೆಂಟ್" "ನಿದ್ರೆಯ ಸಮಯ" + "ಅಡಚಣೆ ಮಾಡಬೇಡಿ (%1$s)" "%1$s ಮೂಲಕ ನಿರ್ವಹಿಸಲಾಗಿದೆ" "ಆನ್ ಆಗಿದೆ" "ಆಫ್ ಆಗಿದೆ" ", " "%1$s - %2$s" - - + "%1$s ನಿಂದ %2$s ವರೆಗೆ" "ಯಾವುದೇ ಕ್ಯಾಲೆಂಡರ್" "%1$s ಧ್ವನಿ ಮ್ಯೂಟ್ ಮಾಡುತ್ತಿದ್ದಾರೆ" "ನಿಮ್ಮ ಸಾಧನದಲ್ಲಿ ಆಂತರಿಕ ಸಮಸ್ಯೆಯಿದೆ ಹಾಗೂ ನೀವು ಫ್ಯಾಕ್ಟರಿ ಡೇಟಾವನ್ನು ರೀಸೆಟ್ ಮಾಡುವವರೆಗೂ ಅದು ಅಸ್ಥಿರವಾಗಬಹುದು." @@ -2426,15 +2426,59 @@ "ಮೊಬೈಲ್ ಅಥವಾ ವೈ-ಫೈ ನೆಟ್‌ವರ್ಕ್ ಇಲ್ಲದೆಯೇ ಸಂದೇಶಗಳನ್ನು ಕಳುಹಿಸಿ ಮತ್ತು ಸ್ವೀಕರಿಸಿ" "Messages ಅನ್ನು ತೆರೆಯಿರಿ" "ಇದು ಹೇಗೆ ಕೆಲಸ ಮಾಡುತ್ತದೆ" - + "\"ಸ್ವಯಂಚಾಲಿತವಾಗಿ ನೆಟ್‌ವರ್ಕ್ ಅನ್ನು ಆಯ್ಕೆಮಾಡಿ\" ಅನ್ನು ಆನ್ ಮಾಡಿ" + "ಸೆಟ್ಟಿಂಗ್‌ಗಳಲ್ಲಿ \"ಸ್ವಯಂಚಾಲಿತವಾಗಿ ನೆಟ್‌ವರ್ಕ್ ಆಯ್ಕೆಮಾಡಿ\" ಅನ್ನು ಆನ್ ಮಾಡಿ ಇದರಿಂದ ನಿಮ್ಮ ಫೋನ್ ಸ್ಯಾಟಲೈಟ್ ಜೊತೆಗೆ ಕಾರ್ಯನಿರ್ವಹಿಸುವ ನೆಟ್‌ವರ್ಕ್ ಅನ್ನು ಹುಡುಕಬಹುದು" + "ಆನ್ ಮಾಡಿ" + "ಹಿಂದಿರುಗಿ" + "ಬಾಕಿ ಉಳಿದಿದೆ..." + - + - + - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - "ಬಾಕಿ ಉಳಿದಿದೆ..." "ಫಿಂಗರ್‌ಪ್ರಿಂಟ್ ಅನ್‌ಲಾಕ್ ಅನ್ನು ಮತ್ತೊಮ್ಮೆ ಸೆಟಪ್ ಮಾಡಿ" "%s ಅನ್ನು ಇನ್ನು ಮುಂದೆ ಗುರುತಿಸಲಾಗುವುದಿಲ್ಲ." "%1$s ಮತ್ತು %2$s ಅನ್ನು ಇನ್ನು ಮುಂದೆ ಗುರುತಿಸಲಾಗುವುದಿಲ್ಲ." diff --git a/core/res/res/values-ko/strings.xml b/core/res/res/values-ko/strings.xml index 393c956c6fc5a9da57544713f2b269447083610e..a069805148f519a3274d73725c653b41f9be7175 100644 --- a/core/res/res/values-ko/strings.xml +++ b/core/res/res/values-ko/strings.xml @@ -1938,13 +1938,13 @@ "주말" "캘린더 일정" "수면 시간" + "방해 금지 모드(%1$s)" "관리자: %1$s" "사용" "사용 중지" ", " "%1$s~%2$s" - - + "%1$s~%2$s" "모든 캘린더" "%1$s(이)가 일부 소리를 음소거함" "사용 중인 기기 내부에 문제가 발생했습니다. 초기화할 때까지 불안정할 수 있습니다." @@ -2426,15 +2426,59 @@ "모바일 또는 Wi-Fi 네트워크 없이 메시지 주고받기" "메시지 열기" "작동 방식" - + "\'네트워크 자동 선택\' 사용 설정" + "휴대전화에서 위성과 연결되는 네트워크를 찾을 수 있도록 \'설정\'에서 \'네트워크 자동 선택\'을 사용 설정하세요" + "사용" + "뒤로" + "대기 중…" + - + - + - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - "대기 중…" "지문 잠금 해제 다시 설정" "%s 지문을 더 이상 인식할 수 없습니다." "%1$s%2$s 지문을 더 이상 인식할 수 없습니다." diff --git a/core/res/res/values-ky/strings.xml b/core/res/res/values-ky/strings.xml index e44538ba3c9d6621203a01450bb74f8c97216c2a..ec0059bb31f679635c4c981dd2f507429ed8730a 100644 --- a/core/res/res/values-ky/strings.xml +++ b/core/res/res/values-ky/strings.xml @@ -1938,13 +1938,13 @@ "Дем алыш" "Иш-чара" "Уйку режими" + "Тынчымды алба (%1$s)" "%1$s башкарат" "Күйүк" "Өчүк" ", " "%1$s, %2$s" - - + "%1$s%2$s" "Бардык жылнаамалар" "%1$s айрым үндөрдү өчүрүүдө" "Түзмөгүңүздө ички көйгөй бар жана ал баштапкы абалга кайтарылмайынча туруктуу иштебей коюшу мүмкүн." @@ -2426,15 +2426,59 @@ "Мобилдик же Wi-Fi тармагына туташпай эле билдирүүлөрдү жөнөтүп, алыңыз" "Жазышуулар колдонмосун ачуу" "Ал кантип иштейт" - + "\"Тармакты автоматтык түрдө тандоо\" параметрин күйгүзүңүз" + "Телефонуңуз спутник менен иштеген тармакты табышы үчүн, параметрлерден \"Тармакты автоматтык түрдө тандоону\" күйгүзүңүз" + "Күйгүзүү" + "Артка кайтуу" + "Кезекте турат..." + - + - + - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - "Кезекте турат..." "Манжа изи менен ачуу функциясын кайра тууралаңыз" "%s мындан ары таанылбайт." "%1$s жана %2$s мындан ары таанылбайт." diff --git a/core/res/res/values-lo/strings.xml b/core/res/res/values-lo/strings.xml index 15138bb10a362fc8c6d864d86ee115d43e42a940..3962f09f0bacd802ab413e562a4a4c02d1babd5d 100644 --- a/core/res/res/values-lo/strings.xml +++ b/core/res/res/values-lo/strings.xml @@ -1938,13 +1938,13 @@ "ທ້າຍອາທິດ" "ການນັດໝາຍ" "ການນອນ" + "ຫ້າມລົບກວນ (%1$s)" "ຈັດການໂດຍ %1$s" "ເປີດຢູ່" "ປິດຢູ່" ", " "%1$s - %2$s" - - + "%1$s ຫາ %2$s" "ປະ​ຕິ​ທິນ​ໃດ​ກໍໄດ້" "%1$s ປິດສຽງບາງຢ່າງໄວ້" "ມີ​ບັນ​ຫາ​ພາຍ​ໃນ​ກັບ​ອຸ​ປະ​ກອນ​ຂອງ​ທ່ານ, ແລະ​ມັນ​ອາດ​ຈະ​ບໍ່​ສະ​ຖຽນ​ຈົນ​ກວ່າ​ທ່ານ​ຕັ້ງ​ເປັນ​ຂໍ້​ມູນ​ໂຮງ​ງານ​ຄືນ​ແລ້ວ." @@ -2426,15 +2426,59 @@ "ຮັບ ແລະ ສົ່ງຂໍ້ຄວາມໂດຍບໍ່ຕ້ອງໃຊ້ເຄືອຂ່າຍໂທລະສັບມືຖື ຫຼື Wi-Fi" "ເປີດ Messages" "ມັນເຮັດວຽກແນວໃດ" - + "ເປີດໃຊ້ \"ເລືອກເຄືອຂ່າຍອັດຕະໂນມັດ\"" + "ເປີດໃຊ້ \"ເລືອກເຄືອຂ່າຍອັດຕະໂນມັດ\" ໃນການຕັ້ງຄ່າເພື່ອໃຫ້ໂທລະສັບຂອງທ່ານສາມາດຊອກຫາເຄືອຂ່າຍທີ່ໃຊ້ໄດ້ກັບດາວທຽມ" + "ເປີດໃຊ້" + "ກັບຄືນ" + "ລໍຖ້າດຳເນີນການ..." + - + - + - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - "ລໍຖ້າດຳເນີນການ..." "ຕັ້ງຄ່າການປົດລັອກດ້ວຍລາຍນິ້ວມືຄືນໃໝ່" "ບໍ່ສາມາດຈຳແນກ %s ໄດ້ອີກຕໍ່ໄປ." "ບໍ່ສາມາດຈຳແນກ %1$s ແລະ %2$s ໄດ້ອີກຕໍ່ໄປ." diff --git a/core/res/res/values-lt/strings.xml b/core/res/res/values-lt/strings.xml index 51aa8a19efef4c04a6cc8602541c3f7ef1303133..c88b6635fab1c652e66d881ffaf2328ad672ad2d 100644 --- a/core/res/res/values-lt/strings.xml +++ b/core/res/res/values-lt/strings.xml @@ -1940,13 +1940,13 @@ "Savaitgalį" "Įvykis" "Miegas" + "Netrukdymo režimas („%1$s“)" "Tvarko „%1$s“" "Įjungti" "Išjungti" ", " "%1$s%2$s" - - + "%1$s%2$s" "Bet kuris kalendorius" "„%1$s“ nutildo kai kuriuos garsus" "Iškilo vidinė su jūsų įrenginiu susijusi problema, todėl įrenginys gali veikti nestabiliai, kol neatkursite gamyklinių duomenų." @@ -2428,15 +2428,59 @@ "Siųskite ir gaukite pranešimus be mobiliojo ryšio ar „Wi-Fi“ tinklo" "Atidaryti programą „Messages“" "Kaip tai veikia" - + "Parinkties „Automatiškai pasirinkti tinklą“ įjungimas" + "Įjunkite „Automatiškai pasirinkti tinklą“ nustatymuose, kad telefonas galėtų rasti su palydovu suderinamą tinklą" + "Įjungti" + "Grįžti" + "Laukiama..." + - + - + - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - "Laukiama..." "Atrakinimo piršto atspaudu nustatymas dar kartą" "%s nebegalima atpažinti." "%1$s ir %2$s nebegalima atpažinti." diff --git a/core/res/res/values-lv/strings.xml b/core/res/res/values-lv/strings.xml index 43de9f54e560be7f56a261d19ae5d48474cc1561..38d1891b13e27fd8e994c59e1f819cfdeda89cc2 100644 --- a/core/res/res/values-lv/strings.xml +++ b/core/res/res/values-lv/strings.xml @@ -1939,13 +1939,13 @@ "Nedēļas nogalē" "Pasākums" "Gulēšana" + "Netraucēt (%1$s)" "Pārvalda %1$s" "Ieslēgta" "Izslēgta" ", " "%1$s%2$s" - - + "no %1$s līdz %2$s" "Jebkurš kalendārs" "%1$s izslēdz noteiktas skaņas" "Jūsu ierīcē ir radusies iekšēja problēma, un ierīce var darboties nestabili. Lai to labotu, veiciet rūpnīcas datu atiestatīšanu." @@ -2427,15 +2427,59 @@ "Sūtiet un saņemiet ziņojumus bez mobilā vai Wi‑Fi tīkla." "Atvērt lietotni Ziņojumi" "Darbības principi" - + "Ieslēdziet iestatījumu “Automātiski atlasīt tīklu”" + "Iestatījumos ieslēdziet iespēju “Automātiski atlasīt tīklu”, lai tālrunis varētu atrast tīklu, kas ir saderīgs ar satelītu." + "Ieslēgt" + "Atpakaļ" + "Gaida…" + - + - + - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - "Gaida…" "Vēlreiz iestatiet autorizāciju ar pirksta nospiedumu" "Pirksta nospiedumu (%s) vairs nevar atpazīt." "Pirkstu nospiedumus (%1$s un %2$s) vairs nevar atpazīt." diff --git a/core/res/res/values-mk/strings.xml b/core/res/res/values-mk/strings.xml index ea380371f083d5c5cba4ad843010db3902139812..87fd79928298b87913ae570b8498cc6d5774d500 100644 --- a/core/res/res/values-mk/strings.xml +++ b/core/res/res/values-mk/strings.xml @@ -1938,13 +1938,13 @@ "Викенд" "Настан" "Спиење" + "Не вознемирувај (%1$s)" "Управувано од %1$s" "Вклучено" "Исклучено" ", " "%1$s%2$s" - - + "%1$s до %2$s" "Кој било календар" "%1$s исклучи некои звуци" "Настана внатрешен проблем со уредот и може да биде нестабилен сè додека не ресетирате на фабричките податоци." @@ -2426,15 +2426,59 @@ "Испраќајте и примајте пораки без мобилна или Wi-Fi мрежа" "Отворете ја Messages" "Дознајте како функционира" - + "Вклучете „Избирај мрежа автоматски“" + "Вклучете „Избирај мрежа автоматски“ во „Поставки“ за да може телефонот да најде мрежа што функционира со сателит" + "Вклучи" + "Врати се назад" + "Во фаза на чекање…" + - + - + - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - "Во фаза на чекање…" "Поставете „Отклучување со отпечаток“ повторно" "%s веќе не може да се препознае." "%1$s и %2$s веќе не може да се препознаат." diff --git a/core/res/res/values-ml/strings.xml b/core/res/res/values-ml/strings.xml index ae6505dbf952ba19e0665b8f518c9355e7d1752d..086ebe1fcaa5e729302c12b8308ee8634b039a32 100644 --- a/core/res/res/values-ml/strings.xml +++ b/core/res/res/values-ml/strings.xml @@ -1938,13 +1938,13 @@ "വാരാന്ത്യം" "ഇവന്റ്" "ഉറക്കം" + "ശല്യപ്പെടുത്തരുത് (%1$s)" "%1$s മാനേജ് ചെയ്യുന്നത്" "ഓണാണ്" "ഓഫാണ്" ", " "%1$s - %2$s" - - + "%1$s മുതൽ %2$s വരെ" "എല്ലാ കലണ്ടറിലും" "%1$s ചില ശബ്‌ദങ്ങൾ മ്യൂട്ട് ചെയ്യുന്നു" "നിങ്ങളുടെ ഉപകരണത്തിൽ ഒരു ആന്തരിക പ്രശ്‌നമുണ്ട്, ഫാക്‌ടറി വിവര പുനഃസജ്ജീകരണം ചെയ്യുന്നതുവരെ ഇതു അസ്ഥിരമായിരിക്കാനിടയുണ്ട്." @@ -2426,15 +2426,59 @@ "മൊബൈൽ അല്ലെങ്കിൽ വൈഫൈ നെറ്റ്‌വർക്ക് ഇല്ലാതെ സന്ദേശങ്ങൾ അയയ്ക്കുകയും സ്വീകരിക്കുകയും ചെയ്യുക" "Messages തുറക്കുക" "ഇത് പ്രവർത്തിക്കുന്നത് എങ്ങനെയാണ്" - + "\"സ്വയമേവ നെറ്റ്‌വർക്ക് തിരഞ്ഞെടുക്കുക\" ഓണാക്കുക" + "ക്രമീകരണങ്ങളിൽ \"സ്വയമേവ നെറ്റ്‌വർക്ക് തിരഞ്ഞെടുക്കുക\" ഓണാക്കുക, അതുവഴി നിങ്ങളുടെ ഫോണിന് ഉപഗ്രഹത്തിനൊപ്പം പ്രവർത്തിക്കുന്ന ഒരു നെറ്റ്‌വർക്ക് കണ്ടെത്താനാകും" + "ഓണാക്കുക" + "മടങ്ങുക" + "തീർപ്പാക്കിയിട്ടില്ല..." + - + - + - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - "തീർപ്പാക്കിയിട്ടില്ല..." "ഫിംഗർപ്രിന്റ് അൺലോക്ക് വീണ്ടും സജ്ജീകരിക്കുക" "%s ഇനി തിരിച്ചറിയാനാകില്ല." "%1$s, %2$s എന്നിവ ഇനി തിരിച്ചറിയാനാകില്ല." diff --git a/core/res/res/values-mn/strings.xml b/core/res/res/values-mn/strings.xml index 3d2eb04b5356ef3eae35df858d276eaa96295941..42db4c97ace41ba96f623642c4983cc6159ac349 100644 --- a/core/res/res/values-mn/strings.xml +++ b/core/res/res/values-mn/strings.xml @@ -1938,13 +1938,13 @@ "Амралтын өдөр" "Үйл явдал" "Унтлагын цаг" + "Бүү саад бол (%1$s)" "%1$s-с удирддаг" "Асаалттай" "Унтраалттай" ", " "%1$s - %2$s" - - + "%1$s%2$s" "Дурын календарь" "%1$s зарим дууны дууг хааж байна" "Таны төхөөрөмжид дотоод алдаа байна.Та төхөөрөмжөө үйлдвэрээс гарсан төлөвт шилжүүлэх хүртэл таны төхөөрөмж чинь тогтворгүй байж болох юм." @@ -2426,15 +2426,59 @@ "Хөдөлгөөнт холбооны эсвэл Wi-Fi сүлжээгүйгээр мессеж илгээх болон хүлээн авах" "Мессежийг нээх" "Энэ хэрхэн ажилладаг вэ?" - + "\"Сүлжээг автоматаар сонгох\"-ыг асаах" + "Тохиргоонд \"Сүлжээг автоматаар сонгох\"-ыг асааснаар таны утас хиймэл дагуултай ажилладаг сүлжээг олох боломжтой" + "Асаах" + "Буцах" + "Хүлээгдэж буй..." + - + - + - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - "Хүлээгдэж буй..." "Хурууны хээгээр түгжээ тайлахыг дахин тохируулна уу" "%s-г цаашид таних боломжгүй." "%1$s болон %2$s-г цаашид таних боломжгүй." diff --git a/core/res/res/values-mr/strings.xml b/core/res/res/values-mr/strings.xml index 9243f47d9246ae9a539b338bb0ed9f4ac2cb6c4b..2cfeaa2adab91a3fef5b71fc78e1f167a6ed9b20 100644 --- a/core/res/res/values-mr/strings.xml +++ b/core/res/res/values-mr/strings.xml @@ -1938,13 +1938,13 @@ "आठवड्याच्या शेवटी" "इव्‍हेंट" "झोपताना" + "व्यत्यय आणू नका (%1$s)" "%1$s द्वारे व्यवस्थापित" "सुरू आहे" "बंद आहे" ", " "%1$s - %2$s" - - + "%1$s ते %2$s" "कोणतेही कॅलेंडर" "%1$s काही ध्‍वनी म्‍यूट करत आहे" "आपल्‍या डिव्‍हाइसमध्‍ये अंतर्गत समस्‍या आहे आणि तुमचा फॅक्‍टरी डेटा रीसेट होईपर्यंत ती अस्‍थिर असू शकते." @@ -2426,15 +2426,59 @@ "मोबाइल किंवा वाय-फाय नेटवर्कशिवाय मेसेज पाठवणे आणि मिळवणे" "Messages उघडा" "ते कसे काम करते" - + "\"नेटवर्क आपोआप निवडा\" सुरू करा" + "सेटिंग्ज मध्ये \"नेटवर्क आपोआप निवडा\" सुरू करा, जेणेकरून तुमचा फोन सॅटेलाइटसोबत काम करणारे नेटवर्क शोधू शकेल" + "सुरू करा" + "मागे जा" + "प्रलंबित आहे..." + - + - + - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - "प्रलंबित आहे..." "फिंगरप्रिंट अनलॉक पुन्हा सेट करा" "%s यापुढे ओळखता येणार नाही." "%1$s आणि %2$s यापुढे ओळखता येणार नाहीत." diff --git a/core/res/res/values-ms/strings.xml b/core/res/res/values-ms/strings.xml index 9bda1735561eb9505a4e389b0b42eefd0f66bb20..6f5d5e7c36589b4a2dcecb4565610ac149b3f259 100644 --- a/core/res/res/values-ms/strings.xml +++ b/core/res/res/values-ms/strings.xml @@ -1938,13 +1938,13 @@ "Hujung minggu" "Acara" "Tidur" + "Jangan Ganggu (%1$s)" "Diurus oleh %1$s" "Hidup" "Mati" ", " "%1$s - %2$s" - - + "%1$s hingga %2$s" "Sebarang kalendar" "%1$s meredamkan sesetengah bunyi" "Terdapat masalah dalaman dengan peranti anda. Peranti mungkin tidak stabil sehingga anda membuat tetapan semula data kilang." @@ -2426,15 +2426,59 @@ "Hantar dan terima mesej tanpa rangkaian mudah alih atau Wi-Fi" "Buka Messages" "Cara ciri ini berfungsi" - + "Hidupkan \"Pilih rangkaian secara automatik\"" + "Hidupkan \"Pilih rangkaian secara automatik\" dalam Tetapan supaya telefon anda boleh menemukan rangkaian yang berfungsi dengan satelit" + "Hidupkan" + "Kembali" + "Belum selesai..." + - + - + - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - "Belum selesai..." "Sediakan Buka Kunci Cap Jari sekali lagi" "%s tidak dapat dicam lagi." "%1$s dan %2$s tidak dapat dicam lagi." diff --git a/core/res/res/values-my/strings.xml b/core/res/res/values-my/strings.xml index 2581a74c6b4eee1b8cd835659e7416fe32bd9caa..9e7e78f98c6421b9875855505bffd8bf55f59353 100644 --- a/core/res/res/values-my/strings.xml +++ b/core/res/res/values-my/strings.xml @@ -1938,13 +1938,13 @@ "စနေ၊ တနင်္ဂနွေ" "အစီအစဉ်" "အိပ်နေချိန်" + "မနှောင့်ယှက်ရ (%1$s)" "%1$s က စီမံသည်" "ဖွင့်" "ပိတ်" "၊ " "%1$s - %2$s" - - + "%1$s မှ %2$s" "မည်သည့်ပြက္ခဒိန်မဆို" "%1$s သည် အချို့အသံကို ပိတ်နေသည်" "သင့်ကိရိယာအတွင်းပိုင်းတွင် ပြဿနာရှိနေပြီး၊ မူလစက်ရုံထုတ်အခြေအနေအဖြစ် ပြန်လည်ရယူနိုင်သည်အထိ အခြေအနေမတည်ငြိမ်နိုင်ပါ။" @@ -2426,15 +2426,59 @@ "မိုဘိုင်း (သို့) Wi-Fi ကွန်ရက်မရှိဘဲ မက်ဆေ့ဂျ်များ ပို့နိုင်၊ လက်ခံနိုင်သည်" "Messages ဖွင့်ရန်" "အလုပ်လုပ်ပုံ" - + "“ကွန်ရက် အလိုအလျောက်ရွေးရန်” ကို ဖွင့်ပါ" + "သင့်ဖုန်းက ဂြိုဟ်တုဖြင့် အလုပ်လုပ်သော ကွန်ရက်ကို ရှာနိုင်ရန်အတွက် ဆက်တင်များတွင် “ကွန်ရက် အလိုအလျောက်ရွေးရန်” ကို ဖွင့်ပါ" + "ဖွင့်ရန်" + "နောက်သို့" + "ဆိုင်းငံ့ထားသည်…" + - + - + - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - "ဆိုင်းငံ့ထားသည်…" "‘လက်ဗွေသုံး လော့ခ်ဖွင့်ခြင်း’ ကို စနစ်ထပ်မံထည့်သွင်းပါ" "%s ကို မသိရှိနိုင်တော့ပါ။" "%1$s နှင့် %2$s ကို မသိရှိနိုင်တော့ပါ။" diff --git a/core/res/res/values-nb/strings.xml b/core/res/res/values-nb/strings.xml index 22288642cb79244ce2bf88babb1fad8da4a8be21..683ca2661b6b42b4a1e88976fad737d71e87656d 100644 --- a/core/res/res/values-nb/strings.xml +++ b/core/res/res/values-nb/strings.xml @@ -1938,13 +1938,13 @@ "Helg" "Aktivitet" "Sover" + "Ikke forstyrr (%1$s)" "Administreres av %1$s" "På" "Av" ", " "%1$s%2$s" - - + "%1$s til %2$s" "Hvilken som helst kalender" "%1$s slår av noen lyder" "Det har oppstått et internt problem på enheten din, og den kan være ustabil til du tilbakestiller den til fabrikkdata." @@ -2426,15 +2426,59 @@ "Send og motta meldinger uten mobil- eller wifi-nettverk" "Åpne Meldinger" "Slik fungerer det" - + "Slå på «Velg nettverk automatisk»" + "Slå på «Velg nettverk automatisk» i innstillingene, slik at telefonen kan finne et nettverk som fungerer med satellitt" + "Slå på" + "Gå tilbake" + "Venter …" + - + - + - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - "Venter …" "Konfigurer opplåsingen med fingeravtrykk på nytt" "%s gjenkjennes ikke lenger." "%1$s og %2$s gjenkjennes ikke lenger." diff --git a/core/res/res/values-ne/strings.xml b/core/res/res/values-ne/strings.xml index 5684d780be8f86536e734e46847b5227b96b1008..ffeecb1cf0ba03f7949cd6b52ad1aacb1709c555 100644 --- a/core/res/res/values-ne/strings.xml +++ b/core/res/res/values-ne/strings.xml @@ -807,7 +807,7 @@ "सञ्जाल अवस्थाका पर्यवेक्षणका लागि सुन्नुहोस्" "सञ्जाल अवस्थाका पर्यवेक्षण सुन्नका लागि एपलाई अनुमति दिन्छ।सामान्य एपलाई चाँहिदै नचाँहिन सक्छ।" "इनपुट डिभाइस क्यालिब्रेसन परिवर्तन गर्नुहोस्" - "एपलाई टच स्क्रीनको प्यारामिटरहरू क्यालिब्रेसन परिमार्जन गर्न अनुमति दिन्छ। साधारण एपहरूको लागि कहिल्यै आवश्यक पर्दैन।" + "एपलाई टच स्क्रिनको प्यारामिटरहरू क्यालिब्रेसन परिमार्जन गर्न अनुमति दिन्छ। साधारण एपहरूको लागि कहिल्यै आवश्यक पर्दैन।" "DRM प्रमाणपत्रको पहुँच" "DRM प्रमाणपत्रहरू प्रावधान र प्रयोग गर्ने निवेदनको अनुमति दिन्छ। साधारण एपहरूको लागि कहिल्यै पनि आवश्यक पर्दैन।" "Android Beam स्थानान्तरण अवस्था प्राप्त गर्नुहोस्" @@ -1938,13 +1938,13 @@ "शनिवार" "कार्यक्रम" "शयन" + "Do Not Disturb (%1$s)" "%1$s ले व्यवस्थापन गरेको" "अन छ" "अफ छ" ", " "%1$s - %2$s" - - + "%1$s देखि %2$s सम्म" "कुनै पनि पात्रो" "%1$s ले केही ध्वनिहरू म्युट गर्दै छ" "तपाईंको यन्त्रसँग आन्तरिक समस्या छ, र तपाईंले फ्याक्ट्री डाटा रिसेट नगर्दासम्म यो अस्थिर रहन्छ।" @@ -2426,15 +2426,59 @@ "मोबाइल वा Wi-Fi नेटवर्कविनै म्यासेजहरू पठाउनुहोस् र प्राप्त गर्नुहोस्" "Messages खोल्नुहोस्" "यसले काम गर्ने तरिका" - + "\"स्वतः नेटवर्क चयन गर्नुहोस्\" अन गर्नुहोस्" + "तपाईंको फोनले स्याटलाइटसँग काम गर्ने नेटवर्क भेट्टाउन सकोस् भन्नका लागि सेटिङमा गई \"स्वतः नेटवर्क चयन गर्नुहोस्\" अन गर्नुहोस्" + "अन गर्नुहोस्" + "पछाडि जानुहोस्" + "विचाराधीन..." + - + - + - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - "विचाराधीन..." "फिंगरप्रिन्ट अनलक फेरि सेटअप गर्नुहोस्" "%s अब पहिचान गर्न सकिँदैन।" "%1$s%2$s अब पहिचान गर्न सकिँदैन।" diff --git a/core/res/res/values-nl/strings.xml b/core/res/res/values-nl/strings.xml index ac18bcf26f10d2f176cee0e5afba7f0fc6f7cb31..5f77e7304cdbfb7b41d2281a643d64e57ec3662e 100644 --- a/core/res/res/values-nl/strings.xml +++ b/core/res/res/values-nl/strings.xml @@ -1938,13 +1938,13 @@ "Weekend" "Afspraak" "Slapen" + "Niet storen (%1$s)" "Beheerd door %1$s" "Aan" "Uit" ", " "%1$s - %2$s" - - + "%1$s tot %2$s" "Elke agenda" "%1$s zet sommige geluiden uit" "Er is een intern probleem met je apparaat. Het apparaat kan instabiel zijn totdat u het apparaat terugzet naar de fabrieksinstellingen." @@ -2426,15 +2426,59 @@ "Stuur en krijg berichten zonder mobiel of wifi-netwerk" "Berichten openen" "Hoe het werkt" - + "Netwerk automatisch selecteren aanzetten" + "Zet Netwerk automatisch selecteren aan in Instellingen zodat je telefoon een netwerk kan vinden dat werkt met satellieten" + "Aanzetten" + "Terug" + "In behandeling…" + - + - + - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - "In behandeling…" "Ontgrendelen met vingerafdruk weer instellen" "%s wordt niet meer herkend." "%1$s en %2$s worden niet meer herkend." diff --git a/core/res/res/values-or/strings.xml b/core/res/res/values-or/strings.xml index c860657df157a073c0f2cf18351a528cd296f9be..b4f924b7d9dbf2b07bf7db75bd4a17dd8bc6b303 100644 --- a/core/res/res/values-or/strings.xml +++ b/core/res/res/values-or/strings.xml @@ -1112,7 +1112,7 @@ "Sym+" "Function+" "ସ୍ପେସ୍‍" - "ଏଣ୍ଟର୍" + "ଏଣ୍ଟର" "ଡିଲିଟ କରନ୍ତୁ" "ସର୍ଚ୍ଚ କରନ୍ତୁ" "ସର୍ଚ୍ଚ କରନ୍ତୁ…" @@ -1600,7 +1600,7 @@ "ହୋଇଗଲା" "ମୋଡ୍‍ ପରିବର୍ତ୍ତନ" "ଶିଫ୍ଟ" - "ଏଣ୍ଟର୍‌" + "ଏଣ୍ଟର" "ଗୋଟିଏ ଆପ୍‍ ବାଛନ୍ତୁ" "%s ଲଞ୍ଚ କରାଯାଇପାରିଲା ନାହିଁ" "ଏହାଙ୍କ ସହ ସେୟାର୍‍ କରନ୍ତୁ" @@ -1938,13 +1938,13 @@ "ସପ୍ତାହାନ୍ତ" "ଇଭେଣ୍ଟ" "ଶୋଇବା" + "ବିରକ୍ତ କରନ୍ତୁ ନାହିଁ (%1$s)" "%1$s ଦ୍ୱାରା ପରିଚାଳିତ" "ଚାଲୁ ଅଛି" "ବନ୍ଦ ଅଛି" ", " "%1$s - %2$s" - - + "%1$sରୁ %2$s" "ଯେକୌଣସି କ୍ୟାଲେଣ୍ଡର୍‌" "%1$s କିଛି ସାଉଣ୍ଡକୁ ମ୍ୟୁଟ୍ କରୁଛି" "ଆପଣଙ୍କ ଡିଭାଇସ୍‍ରେ ଏକ ସମସ୍ୟା ରହିଛି ଏବଂ ଆପଣ ଫ୍ୟାକ୍ଟୋରୀ ଡାଟା ରିସେଟ୍‍ ନକରିବା ପର୍ଯ୍ୟନ୍ତ ଏହା ଅସ୍ଥିର ରହିପାରେ।" @@ -2426,15 +2426,59 @@ "ଏକ ମୋବାଇଲ କିମ୍ବା ୱାଇ-ଫାଇ ନେଟୱାର୍କ ବିନା ମେସେଜ ପଠାନ୍ତୁ ଏବଂ ପାଆନ୍ତୁ" "Messages ଖୋଲନ୍ତୁ" "ଏହା କିପରି କାମ କରେ" - + "\"ସ୍ୱତଃ ନେଟୱାର୍କକୁ ଚୟନ କରନ୍ତୁ\"କୁ ଚାଲୁ କରନ୍ତୁ" + "ସେଟିଂସରେ \"ସ୍ୱତଃ ନେଟୱାର୍କକୁ ଚୟନ କରନ୍ତୁ\"କୁ ଚାଲୁ କରନ୍ତୁ, ଯାହା ଫଳରେ ଆପଣଙ୍କ ଫୋନ ସେଟେଲାଇଟ ସହିତ କାର୍ଯ୍ୟ କରୁଥିବା ଏକ ନେଟୱାର୍କକୁ ଖୋଜିପାରିବ" + "ଚାଲୁ କରନ୍ତୁ" + "ପଛକୁ ଫେରନ୍ତୁ" + "ବାକି ଅଛି…" + - + - + - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - "ବାକି ଅଛି…" "ଫିଙ୍ଗରପ୍ରିଣ୍ଟ ଅନଲକ ପୁଣି ସେଟ ଅପ କରନ୍ତୁ" "%sକୁ ଆଉ ଚିହ୍ନଟ କରାଯାଇପାରିବ ନାହିଁ।" "%1$s ଏବଂ %2$sକୁ ଆଉ ଚିହ୍ନଟ କରାଯାଇପାରିବ ନାହିଁ।" diff --git a/core/res/res/values-pa/strings.xml b/core/res/res/values-pa/strings.xml index 63ebeb8d567d181d0e97edbb327bee2e47960a1e..fae806c4decab7d8afeedbaa6b86ac0903b584fc 100644 --- a/core/res/res/values-pa/strings.xml +++ b/core/res/res/values-pa/strings.xml @@ -1938,13 +1938,13 @@ "ਹਫ਼ਤੇ ਦਾ ਅੰਤਲਾ ਦਿਨ" "ਇਵੈਂਟ" "ਸੌਣ ਵੇਲੇ" + "ਪਰੇਸ਼ਾਨ ਨਾ ਕਰੋ (%1$s)" "%1$s ਵੱਲੋਂ ਪ੍ਰਬੰਧਿਤ" "ਚਾਲੂ ਹੈ" "ਬੰਦ ਹੈ" ", " "%1$s - %2$s" - - + "%1$s ਤੋਂ %2$s ਤੱਕ" "ਕੋਈ ਵੀ ਕੈਲੰਡਰ" "%1$s ਕੁਝ ਧੁਨੀਆਂ ਨੂੰ ਮਿਊਟ ਕਰ ਰਹੀ ਹੈ" "ਤੁਹਾਡੇ ਡੀਵਾਈਸ ਨਾਲ ਇੱਕ ਅੰਦਰੂਨੀ ਸਮੱਸਿਆ ਹੈ ਅਤੇ ਇਹ ਅਸਥਿਰ ਹੋ ਸਕਦੀ ਹੈ ਜਦੋਂ ਤੱਕ ਤੁਸੀਂ ਫੈਕਟਰੀ ਡਾਟਾ ਰੀਸੈੱਟ ਨਹੀਂ ਕਰਦੇ।" @@ -2426,15 +2426,59 @@ "ਮੋਬਾਈਲ ਜਾਂ ਵਾਈ-ਫਾਈ ਨੈੱਟਵਰਕ ਤੋਂ ਬਿਨਾਂ ਸੁਨੇਹੇ ਭੇਜੋ ਅਤੇ ਪ੍ਰਾਪਤ ਕਰੋ" "Messages ਐਪ ਖੋਲ੍ਹੋ" "ਇਹ ਕਿਵੇਂ ਕੰਮ ਕਰਦਾ ਹੈ" - + "\"ਸਵੈਚਲਿਤ ਤੌਰ \'ਤੇ ਨੈੱਟਵਰਕ ਚੁਣੋ\" ਨੂੰ ਚਾਲੂ ਕਰੋ" + "ਸੈਟਿੰਗਾਂ ਵਿੱਚ ਜਾ ਕੇ \"ਸਵੈਚਲਿਤ ਤੌਰ \'ਤੇ ਨੈੱਟਵਰਕ ਚੁਣੋ\" ਨੂੰ ਚਾਲੂ ਕਰੋ, ਤਾਂ ਜੋ ਤੁਹਾਡਾ ਫ਼ੋਨ ਅਜਿਹਾ ਨੈੱਟਵਰਕ ਲੱਭ ਸਕੇ ਜੋ ਸੈਟੇਲਾਈਟ ਨਾਲ ਕੰਮ ਕਰਦਾ ਹੋਵੇ" + "ਚਾਲੂ ਕਰੋ" + "ਵਾਪਸ ਜਾਓ" + "ਵਿਚਾਰ-ਅਧੀਨ..." + - + - + - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - "ਵਿਚਾਰ-ਅਧੀਨ..." "ਫਿੰਗਰਪ੍ਰਿੰਟ ਅਣਲਾਕ ਦਾ ਦੁਬਾਰਾ ਸੈੱਟਅੱਪ ਕਰੋ" "%s ਦੀ ਹੁਣ ਪਛਾਣ ਨਹੀਂ ਕੀਤੀ ਜਾ ਸਕਦੀ।" "%1$s ਅਤੇ %2$s ਦੀ ਹੁਣ ਪਛਾਣ ਨਹੀਂ ਕੀਤੀ ਜਾ ਸਕਦੀ।" diff --git a/core/res/res/values-pl/strings.xml b/core/res/res/values-pl/strings.xml index fa2b493f843b9900ed4454f26a7301402b397628..cf758feb97ae182e9d4b3ca0695aeacdc20958b1 100644 --- a/core/res/res/values-pl/strings.xml +++ b/core/res/res/values-pl/strings.xml @@ -1940,13 +1940,13 @@ "Weekend" "Wydarzenie" "Sen" + "Nie przeszkadzać (%1$s)" "Zarządzana przez aplikację %1$s" "Włączono" "Wyłączono" ", " "%1$s – %2$s" - - + "Od %1$s do %2$s" "Dowolny kalendarz" "%1$s wycisza niektóre dźwięki" "W Twoim urządzeniu wystąpił problem wewnętrzny. Może być ono niestabilne, dopóki nie przywrócisz danych fabrycznych." @@ -2428,15 +2428,59 @@ "Wysyłaj i odbieraj wiadomości bez sieci komórkowej czy Wi-Fi" "Otwórz Wiadomości" "Jak to działa" - + "Włącz „Automatycznie wybieraj sieć”" + "W Ustawieniach włącz opcję „Automatycznie wybieraj sieć”, aby telefon mógł znaleźć sieć współpracującą z satelitą" + "Włącz" + "Wróć" + "Oczekiwanie…" + - + - + - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - "Oczekiwanie…" "Skonfiguruj ponownie odblokowywanie odciskiem palca" "Ten odcisk palca (%s) nie jest już rozpoznawany." "Te odciski palców (%1$s%2$s) nie są już rozpoznawane." diff --git a/core/res/res/values-pt-rBR/strings.xml b/core/res/res/values-pt-rBR/strings.xml index 76a8dc110eac57c8a11ccc84add605ceb8fe32c1..71b334e89eafc796d4b2aed3d69fd3221e5399e4 100644 --- a/core/res/res/values-pt-rBR/strings.xml +++ b/core/res/res/values-pt-rBR/strings.xml @@ -1939,13 +1939,13 @@ "Fim de semana" "Evento" "Dormir" + "Não perturbe (%1$s)" "Gerenciada pelo app %1$s" "Ativada" "Desativada" ", " "%1$s a %2$s" - - + "%1$s a %2$s" "Qualquer agenda" "%1$s está silenciando alguns sons" "Há um problema interno com seu dispositivo. Ele pode ficar instável até que você faça a redefinição para configuração original." @@ -2427,15 +2427,59 @@ "Enviar e receber mensagens sem uma rede móvel ou Wi-Fi" "Abrir o app Mensagens" "Como funciona" - + "Ative a opção \"Selecionar a rede automaticamente\"" + "Ative a opção \"Selecionar a rede automaticamente\" nas configurações para que o smartphone encontre uma rede que funcione com satélite" + "Ativar" + "Voltar" + "Pendente…" + - + - + - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - "Pendente…" "Configurar o Desbloqueio por impressão digital de novo" "A impressão digital %s não é mais reconhecida." "As impressões digitais %1$s e %2$s não são mais reconhecidas." diff --git a/core/res/res/values-pt-rPT/strings.xml b/core/res/res/values-pt-rPT/strings.xml index 86e0fcdad8a172eefe45a3a023f999b552b037b7..4d5ff474c84f90be2ae240655cf0314c19381593 100644 --- a/core/res/res/values-pt-rPT/strings.xml +++ b/core/res/res/values-pt-rPT/strings.xml @@ -1939,6 +1939,7 @@ "Fim de semana" "Evento" "Dormir" + "Não incomodar (%1$s)" "Gerido por %1$s" "Ativada" "Desativada" @@ -2431,6 +2432,54 @@ "Ativar" "Retroceder" "Pendente…" + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + "Configure o Desbloqueio por impressão digital novamente" "Já não é possível reconhecer %s." "Já não é possível reconhecer %1$s e %2$s." diff --git a/core/res/res/values-pt/strings.xml b/core/res/res/values-pt/strings.xml index 76a8dc110eac57c8a11ccc84add605ceb8fe32c1..71b334e89eafc796d4b2aed3d69fd3221e5399e4 100644 --- a/core/res/res/values-pt/strings.xml +++ b/core/res/res/values-pt/strings.xml @@ -1939,13 +1939,13 @@ "Fim de semana" "Evento" "Dormir" + "Não perturbe (%1$s)" "Gerenciada pelo app %1$s" "Ativada" "Desativada" ", " "%1$s a %2$s" - - + "%1$s a %2$s" "Qualquer agenda" "%1$s está silenciando alguns sons" "Há um problema interno com seu dispositivo. Ele pode ficar instável até que você faça a redefinição para configuração original." @@ -2427,15 +2427,59 @@ "Enviar e receber mensagens sem uma rede móvel ou Wi-Fi" "Abrir o app Mensagens" "Como funciona" - + "Ative a opção \"Selecionar a rede automaticamente\"" + "Ative a opção \"Selecionar a rede automaticamente\" nas configurações para que o smartphone encontre uma rede que funcione com satélite" + "Ativar" + "Voltar" + "Pendente…" + - + - + - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - "Pendente…" "Configurar o Desbloqueio por impressão digital de novo" "A impressão digital %s não é mais reconhecida." "As impressões digitais %1$s e %2$s não são mais reconhecidas." diff --git a/core/res/res/values-ro/strings.xml b/core/res/res/values-ro/strings.xml index 384d1b3b22fd7663d62892f19f1654772e213cc2..6e43d317e0f05f878be4a53379e637775153cfed 100644 --- a/core/res/res/values-ro/strings.xml +++ b/core/res/res/values-ro/strings.xml @@ -1939,13 +1939,13 @@ "Weekend" "Eveniment" "Somn" + "Nu deranja (%1$s)" "Gestionat de %1$s" "Activată" "Dezactivată" ", " "%1$s%2$s" - - + "%1$s%2$s" "Orice calendar" "%1$s dezactivează anumite sunete" "A apărut o problemă internă pe dispozitiv, iar acesta poate fi instabil până la revenirea la setările din fabrică." @@ -2183,7 +2183,7 @@ "Conexiunea Bluetooth va rămâne activată în modul Avion" "Se încarcă" "{count,plural, =1{{file_name} + # fișier}few{{file_name} + # fișiere}other{{file_name} + # de fișiere}}" - "Nu există persoane recomandate pentru permiterea accesului" + "Nu există persoane recomandate pentru trimitere" "Lista de aplicații" "Permisiunea de înregistrare nu a fost acordată aplicației, dar aceasta poate să înregistreze conținut audio prin intermediul acestui dispozitiv USB." "Pornire" @@ -2427,15 +2427,59 @@ "Trimite și primește mesaje fără o rețea mobilă sau Wi-Fi" "Deschide Mesaje" "Cum funcționează" - + "Activează opțiunea Selectează automat rețeaua" + "Activează opțiunea Selectează automat rețeaua în Setări pentru ca telefonul să găsească o rețea compatibilă cu satelitul" + "Activează" + "Înapoi" + "În așteptare..." + - + - + - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - "În așteptare..." "Configurează din nou Deblocarea cu amprenta" "%s nu mai poate fi recunoscută." "%1$s și %2$s nu mai pot fi recunoscute." diff --git a/core/res/res/values-ru/strings.xml b/core/res/res/values-ru/strings.xml index f7e3610a20224a3ea799c5b7e0d1b69bb52b1288..b23a44bcc9fc40d99be8afb8860f08cf65958eaa 100644 --- a/core/res/res/values-ru/strings.xml +++ b/core/res/res/values-ru/strings.xml @@ -1940,13 +1940,13 @@ "Выходные" "Мероприятие" "Время сна" + "Не беспокоить (%1$s)" "Под управлением приложения \"%1$s\"" "Включено" "Отключено" ", " "%1$s – %2$s" - - + "%1$s – %2$s" "Любой календарь" "%1$s приглушает некоторые звуки." "Произошла внутренняя ошибка, и устройство может работать нестабильно, пока вы не выполните сброс настроек." @@ -2428,15 +2428,59 @@ "Отправляйте и получайте сообщения без подключения к мобильной сети или Wi-Fi." "Открыть Сообщения" "Узнать принцип работы" - + "Включите автоматический выбор сети" + "Чтобы ваш телефон мог найти сеть, которая поддерживает спутниковую связь, включите в настройках параметр \"Выбирать сеть автоматически\"." + "Включить" + "Назад" + "Обработка…" + - + - + - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - "Обработка…" "Настройте разблокировку по отпечатку пальца заново" "Отпечаток \"%s\" больше нельзя распознать." "Отпечатки \"%1$s\" и \"%2$s\" больше нельзя распознать." diff --git a/core/res/res/values-si/strings.xml b/core/res/res/values-si/strings.xml index ea404f1a684483427e5908c1c1213ac08418a9c5..db82c6c98fa4f2a4db00c5a976bbe235169d562e 100644 --- a/core/res/res/values-si/strings.xml +++ b/core/res/res/values-si/strings.xml @@ -1938,13 +1938,13 @@ "සති අන්තය" "සිදුවීම" "නිදා ගනිමින්" + "බාධා නොකරන්න (%1$s)" "%1$s විසින් කළමනාකරණය කරයි" "ක්‍රියාත්මකයි" "ක්‍රියාවිරහිතයි" ", " "%1$s - %2$s" - - + "%2$s සිට %1$s දක්වා" "ඕනෑම දින දර්ශනයක්" "%1$s සමහර ශබ්ද නිහඬ කරමින්" "ඔබේ උපාංගය සමගින් ගැටලුවක් ඇති අතර, ඔබේ කර්මාන්තශාලා දත්ත යළි සකසන තෙක් එය අස්ථායි විය හැකිය." @@ -2426,15 +2426,59 @@ "ජංගම හෝ Wi-Fi ජාලයකින් තොරව පණිවිඩ යැවීම සහ ලැබීම" "Messages විවෘත කරන්න" "එය ක්‍රියා කරන ආකාරය" - + "\"ස්වයංක්‍රීයව ජාලය තෝරන්න\" ක්‍රියාත්මක කරන්න" + "ඔබේ දුරකථනයට චන්ද්‍රිකාව සමග ක්‍රියා කරන ජාලයක් සොයා ගැනීමට හැකි වන පරිදි සැකසීම් තුළ \"ස්වයංක්‍රීයව ජාලය තෝරන්න\" ක්‍රියාත්මක කරන්න" + "ක්‍රියාත්මක කරන්න" + "ආපසු යන්න" + "පොරොත්තුයි..." + - + - + - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - "පොරොත්තුයි..." "ඇඟිලි සලකුණු අගුලු හැරීම නැවත සකසන්න" "%s තවදුරටත් හඳුනා ගත නොහැක." "%1$s සහ %2$s තවදුරටත් හඳුනා ගත නොහැක." diff --git a/core/res/res/values-sk/strings.xml b/core/res/res/values-sk/strings.xml index eeb308187cb619de7df1400ff4b456e19d209be0..cbabfb6e107634d3f19711f4194cd15d10cb5abe 100644 --- a/core/res/res/values-sk/strings.xml +++ b/core/res/res/values-sk/strings.xml @@ -1940,13 +1940,13 @@ "Víkend" "Udalosť" "Spánok" + "Režim bez vyrušení (%1$s)" "Spravované aplikáciou %1$s" "Zapnuté" "Vypnuté" ", " "%1$s – %2$s" - - + "%1$s – %2$s" "Ľubovoľný kalendár" "%1$s vypína niektoré zvuky" "Vo vašom zariadení došlo k internému problému. Môže byť nestabilné, kým neobnovíte jeho výrobné nastavenia." @@ -2428,15 +2428,59 @@ "Odosielajte a prijímajte správy bez mobilnej siete či siete Wi‑Fi" "Otvoriť Správy" "Ako to funguje" - + "Zapnite Vyberať sieť automaticky" + "Zapnite v Nastaveniach možnosť Vyberať sieť automaticky, aby telefón mohol nájsť sieť, ktorá spolupracuje so satelitom" + "Zapnúť" + "Prejsť späť" + "Nespracovaná…" + - + - + - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - "Nespracovaná…" "Znova nastavte odomknutie odtlačkom prsta" "%s sa už nedari rozpoznať." "%1$s%2$s sa už nedari rozpoznať." diff --git a/core/res/res/values-sl/strings.xml b/core/res/res/values-sl/strings.xml index 514ad1656760a23d8a6c45ce6b8d39b785100712..d7178c802ec6bb8577f6f90833b6863447a0ff73 100644 --- a/core/res/res/values-sl/strings.xml +++ b/core/res/res/values-sl/strings.xml @@ -1940,13 +1940,13 @@ "Konec tedna" "Dogodek" "Spanje" + "Ne moti (%1$s)" "Upravlja %1$s" "Vklopljeno" "Izklopljeno" ", " "%1$s%2$s" - - + "%1$s do %2$s" "Kateri koli koledar" "%1$s izklaplja nekatere zvoke" "Vaša naprava ima notranjo napako in bo morda nestabilna, dokler je ne ponastavite na tovarniške nastavitve." @@ -2428,15 +2428,59 @@ "Pošiljanje in prejemanje sporočil brez mobilnega omrežja ali omrežja Wi-Fi" "Odpri Sporočila" "Kako deluje" - + "Vklopite »Samodejno izberi omrežje«" + "V nastavitvah vklopite možnost »Samodejno izberi omrežje«, da bo telefon lahko našel omrežje, ki deluje s satelitsko povezavo" + "Vklopi" + "Nazaj" + "V teku …" + - + - + - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - "V teku …" "Vnovična nastavitev odklepanja s prstnim odtisom" "Odtisa »%s« ni več mogoče prepoznati." "Odtisov »%1$s« in »%2$s« ni več mogoče prepoznati." diff --git a/core/res/res/values-sq/strings.xml b/core/res/res/values-sq/strings.xml index 8d535b9a9b8dc32b2d57b4f9f3c69d541dfec43e..42356bf8cc076661fc6bd004a892a7cd4f71ce13 100644 --- a/core/res/res/values-sq/strings.xml +++ b/core/res/res/values-sq/strings.xml @@ -1938,13 +1938,13 @@ "Fundjava" "Ngjarje" "Në gjumë" + "Mos shqetëso (%1$s)" "Menaxhohet nga %1$s" "Aktivizuar" "Çaktivizuar" ", " "%1$s - %2$s" - - + "%1$s - %2$s" "Çdo kalendar" "%1$s po çaktivizon disa tinguj" "Ka një problem të brendshëm me pajisjen tënde. Ajo mund të jetë e paqëndrueshme derisa të rivendosësh të dhënat në gjendje fabrike." @@ -2426,15 +2426,59 @@ "Dërgo dhe merr mesazhe pa një rrjet celular ose Wi-Fi" "Hap \"Mesazhet\"" "Si funksionon" - + "Aktivizo \"Zgjidh automatikisht rrjetin\"" + "Aktivizo \"Zgjidh automatikisht rrjetin\" te \"Cilësimet\" që telefoni yt të mund të gjejë një rrjet që funksionon me satelitin" + "Aktivizo" + "Kthehu prapa" + "Në pritje..." + - + - + - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - "Në pritje..." "Konfiguro përsëri \"Shkyçjen me gjurmën e gishtit\"" "%s nuk mund të njihet më." "%1$s dhe %2$s nuk mund të njihen më." diff --git a/core/res/res/values-sr/strings.xml b/core/res/res/values-sr/strings.xml index af75a5c135e3346d0aa712488240d4deba12d453..10fa5f831fb4932584a90d906a2cd11adbf5357b 100644 --- a/core/res/res/values-sr/strings.xml +++ b/core/res/res/values-sr/strings.xml @@ -1939,13 +1939,13 @@ "Викенд" "Догађај" "Спавање" + "Не узнемиравај (%1$s)" "Управља: %1$s" "Укључено" "Искључено" ", " "%1$s%2$s" - - + "%1$s%2$s" "Било који календар" "%1$s искључује неке звуке" "Дошло је до интерног проблема у вези са уређајем и можда ће бити нестабилан док не обавите ресетовање на фабричка подешавања." @@ -2427,15 +2427,59 @@ "Шаљите и примајте поруке без мобилне или WiFi мреже" "Отвори Messages" "Принцип рада" - + "Укључите опцију Аутоматски изабери мрежу" + "Укључите опцију Аутоматски изабери мрежу у Подешавањима да би телефон могао да пронађе мрежу која ради са сателитом" + "Укључи" + "Назад" + "На чекању..." + - + - + - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - "На чекању..." "Поново подесите откључавање отиском прста" "%s више не може да се препозна." "%1$s и %2$s више не могу да се препознају." diff --git a/core/res/res/values-sv/strings.xml b/core/res/res/values-sv/strings.xml index 0cff2e5077101d9c03e875e98e5a049ddd1f92a5..857b060452ec56bc2bbcc82e6a37f290fce69ec2 100644 --- a/core/res/res/values-sv/strings.xml +++ b/core/res/res/values-sv/strings.xml @@ -1938,13 +1938,13 @@ "I helgen" "Händelse" "Sover" + "Stör ej (%1$s)" "Hanteras av %1$s" "På" "Av" ", " "%1$s%2$s" - - + "%1$s till %2$s" "Alla kalendrar" "%1$s stänger av vissa ljud" "Ett internt problem har uppstått i enheten, och det kan hända att problemet kvarstår tills du återställer standardinställningarna." @@ -2426,15 +2426,59 @@ "Skicka och ta emot meddelanden utan ett mobil- eller wifi-nätverk" "Öppna Messages" "Så fungerar det" - + "Aktivera Välj nätverk automatiskt" + "Aktivera Välj nätverk automatiskt i inställningarna så att telefonen kan hitta ett nätverk som fungerar med satellit" + "Aktivera" + "Tillbaka" + "Väntar …" + - + - + - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - "Väntar …" "Konfigurera fingeravtryckslås igen" "Det går inte längre att känna igen %s." "Det går inte längre att känna igen %1$s och %2$s." diff --git a/core/res/res/values-sw/strings.xml b/core/res/res/values-sw/strings.xml index bf5189261e8f023042fb7f550e9850276559e278..d46fa084258bb9cab70854d8c0833f1e74da158a 100644 --- a/core/res/res/values-sw/strings.xml +++ b/core/res/res/values-sw/strings.xml @@ -1938,13 +1938,13 @@ "Wikendi" "Tukio" "Kulala" + "Usinisumbue (%1$s)" "Inadhibitiwa na %1$s" "Imewashwa" "Imezimwa" ", " "%1$s - %2$s" - - + "%1$s hadi %2$s" "Kalenda yoyote" "%1$s inazima baadhi ya sauti" "Kuna hitilafu ya ndani ya kifaa chako, na huenda kisiwe thabiti mpaka urejeshe mipangilio ya kiwandani." @@ -2426,15 +2426,59 @@ "Tuma na upokee ujumbe bila kutumia mtandao wa simu wala Wi-Fi" "Fungua Programu ya Messages" "Utaratibu wake" - + "Washa kipengele cha \"Chagua mtandao kiotomatiki\"" + "Washa kipengele cha \"Chagua mtandao kiotomatiki\" katika Mipangilio ili simu yako iweze kupata mtandao unaotumia setilaiti" + "Washa" + "Rudi nyuma" + "Inashughulikiwa..." + - + - + - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - "Inashughulikiwa..." "Weka tena mipangilio ya Kufungua kwa Alama ya Kidole" "%s haitambuliki tena." "%1$s na %2$s havitambuliki tena." diff --git a/core/res/res/values-ta/strings.xml b/core/res/res/values-ta/strings.xml index 8ff19a98f6d89bd945d1976f3673abc670116287..32fefacb111596ef88340950dfd2eba733a40dca 100644 --- a/core/res/res/values-ta/strings.xml +++ b/core/res/res/values-ta/strings.xml @@ -1937,14 +1937,14 @@ "வார இரவு" "வார இறுதி" "நிகழ்வு" - "உறக்கத்தில்" + "உறங்குதல்" + "தொந்தரவு செய்ய வேண்டாம் (%1$s)" "நிர்வகிப்பது: %1$s" "ஆன்" "ஆஃப்" ", " "%1$s - %2$s" - - + "%1$s முதல் %2$s வரை" "ஏதேனும் கேலெண்டர்" "%1$s சில ஒலிகளை முடக்குகிறது" "சாதனத்தில் அகச் சிக்கல் இருக்கிறது, அதனை ஆரம்பநிலைக்கு மீட்டமைக்கும் வரை நிலையற்று இயங்கலாம்." @@ -2426,15 +2426,59 @@ "மொபைல்/வைஃபை நெட்வொர்க் இல்லாமல் மெசேஜ்களை அனுப்பலாம், பெறலாம்" "Messages ஆப்ஸைத் திறக்கவும்" "இது செயல்படும் விதம்" - + "\"நெட்வொர்க்கைத் தானாகத் தேர்ந்தெடு\" என்பதை இயக்குங்கள்" + "அமைப்புகளில் \"நெட்வொர்க்கைத் தானாகத் தேர்ந்தெடு\" என்பதை இயக்கினால் செயற்கைக்கோள் மூலம் இயங்கும் நெட்வொர்க்கை உங்கள் மொபைல் கண்டறிய முடியும்" + "இயக்கு" + "பின்செல்" + "நிலுவையிலுள்ளது..." + - + - + - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - "நிலுவையிலுள்ளது..." "கைரேகை அன்லாக் அம்சத்தை மீண்டும் அமையுங்கள்" "%sஐ இனி அடையாளம் காண முடியாது." "%1$s, %2$s ஆகியவற்றை இனி அடையாளம் காண முடியாது." diff --git a/core/res/res/values-te/strings.xml b/core/res/res/values-te/strings.xml index 1d9e00c012bb73c87b836243f8c7c22f266e743b..8500e9dcd0d78fc40eb98cb61922bb0fd139c1e0 100644 --- a/core/res/res/values-te/strings.xml +++ b/core/res/res/values-te/strings.xml @@ -1938,13 +1938,13 @@ "వారాంతం" "ఈవెంట్" "స్లీప్ మోడ్" + "అంతరాయం కలిగించవద్దు (%1$s)" "%1$s ద్వారా మేనేజ్ చేయబడుతోంది" "ఆన్‌లో ఉంది" "ఆఫ్‌లో ఉంది" ", " "%1$s - %2$s" - - + "%1$s నుండి %2$s వరకు" "ఏదైనా క్యాలెండర్" "%1$s కొన్ని ధ్వనులను మ్యూట్ చేస్తోంది" "మీ పరికరంతో అంతర్గత సమస్య ఏర్పడింది మరియు మీరు ఫ్యాక్టరీ డేటా రీసెట్ చేసే వరకు అస్థిరంగా ఉంటుంది." @@ -2426,15 +2426,59 @@ "మొబైల్ లేదా Wi-Fi నెట్‌వర్క్ లేకుండా మెసేజ్‌లను పంపండి, స్వీకరించండి" "Messagesను తెరవండి" "ఇది ఎలా పని చేస్తుంది" - + "\"నెట్‌వర్క్‌ను ఆటోమేటిక్‌గా ఎంచుకోండి\" అనే ఆప్షన్‌ను ఆన్ చేయండి" + "సెట్టింగ్‌లలో \"నెట్‌వర్క్‌ను ఆటోమేటిక్‌గా ఎంచుకోండి\" అనే ఆప్షన్‌ను ఆన్ చేయండి, తద్వారా మీ ఫోన్ శాటిలైట్‌తో పనిచేసే నెట్‌వర్క్‌ను కనుగొనగలదు" + "ఆన్ చేయండి" + "వెనుకకు వెళ్లండి" + "పెండింగ్‌లో ఉంది..." + - + - + - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - "పెండింగ్‌లో ఉంది..." "వేలిముద్ర అన్‌లాక్‌ను మళ్లీ సెటప్ చేయండి" "%s‌ను ఇకపై గుర్తించడం సాధ్యం కాదు." "%1$s, %2$s‌లను ఇకపై గుర్తించడం సాధ్యం కాదు." diff --git a/core/res/res/values-th/strings.xml b/core/res/res/values-th/strings.xml index 90a90ee9ab18c5c17f135b3180ec77bbc04f0e25..a1c7b4f59608af04b4698700560474912ab3795c 100644 --- a/core/res/res/values-th/strings.xml +++ b/core/res/res/values-th/strings.xml @@ -1938,13 +1938,13 @@ "สุดสัปดาห์" "กิจกรรม" "นอนหลับ" + "ห้ามรบกวน (%1$s)" "จัดการโดย %1$s" "เปิด" "ปิด" ", " "%1$s - %2$s" - - + "%1$sถึง%2$s" "ปฏิทินทั้งหมด" "%1$s กำลังปิดเสียงบางรายการ" "อุปกรณ์ของคุณเกิดปัญหาภายในเครื่อง อุปกรณ์อาจทำงานไม่เสถียรจนกว่าคุณจะรีเซ็ตข้อมูลเป็นค่าเริ่มต้น" @@ -2426,15 +2426,59 @@ "รับและส่งข้อความโดยไม่ต้องใช้เครือข่ายมือถือหรือ Wi-Fi" "เปิด Messages" "วิธีการทำงาน" - + "เปิด \"เลือกเครือข่ายโดยอัตโนมัติ\"" + "เปิด \"เลือกเครือข่ายโดยอัตโนมัติ\" ในการตั้งค่าเพื่อให้โทรศัพท์ค้นหาเครือข่ายที่ใช้งานร่วมกับดาวเทียมได้" + "เปิด" + "ย้อนกลับ" + "รอดำเนินการ..." + - + - + - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - "รอดำเนินการ..." "ตั้งค่าการปลดล็อกด้วยลายนิ้วมืออีกครั้ง" "ระบบไม่จดจำ %s อีกต่อไป" "ระบบไม่จดจำ %1$s และ %2$s อีกต่อไป" diff --git a/core/res/res/values-tl/strings.xml b/core/res/res/values-tl/strings.xml index f4df0e2ed7ae1831fdfad5d6ac5771fb6eb1a846..f15d952db15ae7cbc01d8af97a970adc70401355 100644 --- a/core/res/res/values-tl/strings.xml +++ b/core/res/res/values-tl/strings.xml @@ -1938,13 +1938,13 @@ "Weekend" "Event" "Pag-sleep" + "Huwag Istorbohin (%1$s)" "Pinapamahalaan ng %1$s" "Naka-on" "Naka-off" ", " "%1$s, %2$s" - - + "%1$s patungong %2$s" "Anumang kalendaryo" "Minu-mute ng %1$s ang ilang tunog" "May internal na problema sa iyong device, at maaaring hindi ito maging stable hanggang sa i-reset mo ang factory data." @@ -2426,15 +2426,59 @@ "Magpadala at tumanggap ng mga mensahe nang walang mobile o Wi-Fi network" "Buksan ang Messages" "Paano ito gumagana" - + "I-on ang \"Awtomatikong pumili ng network\"" + "I-on ang \"Awtomatikong piliin ang network\" sa Mga Setting para mahanap ng iyong telepono ang isang network na gumagana sa satellite" + "I-on" + "Bumalik" + "Nakabinbin..." + - + - + - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - "Nakabinbin..." "I-set up ulit ang Pag-unlock Gamit ang Fingerprint" "Hindi na makilala ang %s." "Hindi na makilala ang %1$s at %2$s." diff --git a/core/res/res/values-tr/strings.xml b/core/res/res/values-tr/strings.xml index 77c3ee24ba59fcff5a264d951b32b9f0a389995f..39a005f628f568a6c88b86c6e3f4d62247a46868 100644 --- a/core/res/res/values-tr/strings.xml +++ b/core/res/res/values-tr/strings.xml @@ -1938,13 +1938,13 @@ "Hafta sonu" "Etkinlik" "Uyku" + "Rahatsız Etmeyin (%1$s)" "%1$s tarafından yönetiliyor" "Açık" "Kapalı" ", " "%1$s-%2$s" - - + "%1$s-%2$s" "Tüm takvimler" "%1$s bazı sesleri kapatıyor" "Cihazınızla ilgili dahili bir sorun oluştu ve fabrika verilerine sıfırlama işlemi gerçekleştirilene kadar kararsız çalışabilir." @@ -2426,15 +2426,59 @@ "Mobil veya kablosuz ağ kullanmadan mesaj gönderip alın" "Mesajlar\'ı aç" "İşleyiş şekli" - + "\"Ağı otomatik seç\"i etkinleştirin" + "Telefonunuzun uyduyla çalışan bir ağ bulabilmesi için Ayarlar\'da \"Ağı otomatik seç\"i etkinleştirin" + "Etkinleştir" + "Geri dön" + "Bekliyor..." + - + - + - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - "Bekliyor..." "Parmak İzi Kilidi\'ni tekrar kurun" "%s artık tanınamayacak." "%1$s ve %2$s artık tanınamayacak." diff --git a/core/res/res/values-uk/strings.xml b/core/res/res/values-uk/strings.xml index 2f1a1d5987e27c0e1fcd4bd3d8567a3b2462d9e9..3b9cd192f7a4c16c39a896524fa07ba8b1f97804 100644 --- a/core/res/res/values-uk/strings.xml +++ b/core/res/res/values-uk/strings.xml @@ -1940,13 +1940,13 @@ "На вихідних" "Подія" "Під час сну" + "Не турбувати (%1$s)" "Керує додаток %1$s" "Увімкнено" "Вимкнено" ", " "%1$s%2$s" - - + "%1$s%2$s" "З усіх календарів" "%1$s вимикає деякі звуки" "Через внутрішню помилку ваш пристрій може працювати нестабільно. Відновіть заводські налаштування." @@ -2428,15 +2428,59 @@ "Надсилайте й отримуйте текстові повідомлення без мобільної мережі або Wi-Fi" "Відкрийте Повідомлення" "Як це працює" - + "Увімкніть опцію \"Вибирати мережу автоматично\"" + "У налаштуваннях увімкніть опцію \"Вибирати мережу автоматично\", щоб телефон міг знайти мережу, яка працює через супутник" + "Увімкнути" + "Назад" + "Обробка…" + - + - + - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - "Обробка…" "Налаштуйте розблокування відбитком пальця повторно" "Відбиток пальця %s більше не розпізнається." "Відбитки пальців %1$s і %2$s більше не розпізнаються." diff --git a/core/res/res/values-ur/strings.xml b/core/res/res/values-ur/strings.xml index 6c78283d9494f44352c709305b71c06293095651..679f1026197a94582027f26351fdce7816d5ca72 100644 --- a/core/res/res/values-ur/strings.xml +++ b/core/res/res/values-ur/strings.xml @@ -1938,13 +1938,13 @@ "ویک اینڈ" "ایونٹ" "سونا" + "ڈسٹرب نہ کریں (%1$s)" "%1$s کے زیر انتظام ہے" "آن ہے" "آف ہے" "، " "%1$s - %2$s" - - + "%1$s تا %2$s" "کوئی بھی کیلنڈر" "%1$s کچھ آوازوں کو خاموش کر رہا ہے" "آپ کے آلہ میں ایک داخلی مسئلہ ہے اور جب تک آپ فیکٹری ڈیٹا کو دوبارہ ترتیب نہیں دے دیتے ہیں، ہوسکتا ہے کہ یہ غیر مستحکم رہے۔" @@ -2426,15 +2426,59 @@ "‏موبائل یا Wi-Fi نیٹ ورک کے بغیر پیغامات بھیجیں اور موصول کریں" "پیغامات ایپ کو کھولیں" "اس کے کام کرنے کا طریقہ" - + "\"خودکار طور پر نیٹ ورک منتخب کریں\" کو آن کریں" + "ترتیبات میں \"خودکار طور پر نیٹ ورک منتخب کریں\" کو آن کریں تاکہ آپ کا فون سیٹلائٹ کے ساتھ کام کرنے والے نیٹ ورک کو تلاش کر سکے" + "آن کریں" + "واپس جائیں" + "زیر التواء..." + - + - + - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - "زیر التواء..." "فنگر پرنٹ اَن لاک کو دوبارہ سیٹ اپ کریں" "%s مزید پہچانا نہیں جا سکتا۔" "%1$s اور %2$s کو مزید پہچانا نہیں جا سکتا۔" diff --git a/core/res/res/values-uz/strings.xml b/core/res/res/values-uz/strings.xml index ac70b93d22486c9d1eb640ffe27b219af8fe5aed..d7620e1f3afbab05b11f7cda12587e9681a71495 100644 --- a/core/res/res/values-uz/strings.xml +++ b/core/res/res/values-uz/strings.xml @@ -1938,13 +1938,13 @@ "Dam olish kunlari" "Tadbir" "Uyquda" + "Bezovta qilinmasin (%1$s)" "%1$s tomonidan boshqariladi" "Yoniq" "Oʻchiq" ", " "%1$s%2$s" - - + "%1$s%2$s" "Har qanday taqvim" "%1$s ayrim tovushlarni ovozsiz qilgan" "Qurilmangiz bilan bog‘liq ichki muammo mavjud. U zavod sozlamalari tiklanmaguncha barqaror ishlamasligi mumkin." @@ -2426,15 +2426,59 @@ "Mobil yoki Wi-Fi tarmoq blan aloqa yoʻqligida xabar yuboring va qabul qiling" "Xabarlar ilovasini ochish" "Ishlash tartibi" - + "“Tarmoqni avtomatik tanlash” sozlamasini yoqing" + "Telefoningiz sputnik bilan ishlaydigan tarmoqni topishi uchun Sozlamalar orqali “Tarmoqni avtomatik tanlash” sozlamasini yoqing" + "Yoqish" + "Orqaga" + "Kutilmoqda..." + - + - + - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - "Kutilmoqda..." "Barmoq izi bilan ochish funksiyasini qayta sozlang" "%s endi tanilmaydi." "%1$s va %2$s endi tanilmaydi." diff --git a/core/res/res/values-vi/strings.xml b/core/res/res/values-vi/strings.xml index d4551b178568c6eac8cd5bbd2a4816435ea9bd7e..663078b5caf4bff6bd9678289b6d4834549c7a4a 100644 --- a/core/res/res/values-vi/strings.xml +++ b/core/res/res/values-vi/strings.xml @@ -1938,13 +1938,13 @@ "Cuối tuần" "Sự kiện" "Ngủ" + "Không làm phiền (%1$s)" "Do %1$s quản lý" "Bật" "Tắt" ", " "%1$s%2$s" - - + "%1$s đến %2$s" "Bất kỳ lịch nào" "%1$s đang tắt một số âm thanh" "Đã xảy ra sự cố nội bộ với thiết bị của bạn và thiết bị có thể sẽ không ổn định cho tới khi bạn thiết lập lại dữ liệu ban đầu." @@ -2426,15 +2426,59 @@ "Gửi và nhận tin nhắn mà không cần mạng di động hoặc Wi-Fi" "Mở ứng dụng Tin nhắn" "Cách hoạt động" - + "Bật tính năng \"Tự động chọn mạng\"" + "Bật tính năng \"Tự động chọn mạng\" trong phần Cài đặt để điện thoại có thể tìm thấy mạng hoạt động với vệ tinh" + "Bật" + "Quay lại" + "Đang chờ xử lý..." + - + - + - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - "Đang chờ xử lý..." "Thiết lập lại tính năng Mở khoá bằng vân tay" "Không nhận dạng được %s nữa." "Không nhận dạng được %1$s%2$s nữa." diff --git a/core/res/res/values-zh-rCN/strings.xml b/core/res/res/values-zh-rCN/strings.xml index 22f80bd2d511b838231fd88e101113d3209d2cb8..6007d1e5f9c5e86280824e58a1669ba8268b9169 100644 --- a/core/res/res/values-zh-rCN/strings.xml +++ b/core/res/res/values-zh-rCN/strings.xml @@ -1938,13 +1938,13 @@ "周末" "活动" "睡眠" + "勿扰 (%1$s)" "由%1$s管理" "已启用" "已停用" "、 " "%1$s - %2$s" - - + "%1$s%2$s" "所有日历" "%1$s正在将某些音效设为静音" "您的设备内部出现了问题。如果不将设备恢复出厂设置,设备运行可能会不稳定。" @@ -2426,15 +2426,59 @@ "即使没有移动网络或 WLAN 网络,也能收发消息" "打开“信息”应用" "运作方式" - + "开启“自动选择网络”" + "在“设置”中开启“自动选择网络”,以便手机找到可与卫星配合使用的网络" + "开启" + "返回" + "待归档…" + - + - + - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - "待归档…" "重新设置指纹解锁功能" "系统无法再识别%s。" "系统无法再识别%1$s%2$s。" diff --git a/core/res/res/values-zh-rHK/strings.xml b/core/res/res/values-zh-rHK/strings.xml index 3f4c1758b1fbb5ef90faa5e8fdf5eef2cce71d98..fcf50e4beec406b0acf6678b93fd73c96d0f2461 100644 --- a/core/res/res/values-zh-rHK/strings.xml +++ b/core/res/res/values-zh-rHK/strings.xml @@ -1938,13 +1938,13 @@ "週末" "活動" "睡眠" + "請勿騷擾 (%1$s)" "由%1$s管理" "已開啟" "已關閉" "、 " "%1$s - %2$s" - - + "%1$s%2$s" "任何日曆" "%1$s正將某些音效設為靜音" "你裝置的系統發生問題,回復原廠設定後即可解決該問題。" @@ -2426,15 +2426,59 @@ "在沒有流動網絡或 Wi-Fi 網絡的情況下收發短訊" "開啟「訊息」" "運作方式" - + "開啟「自動選取網絡」" + "前往設定開啟「自動選取網絡」,讓手機可以尋找可使用衛星的網絡" + "開啟" + "返回" + "待處理…" + - + - + - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - "待處理…" "重新設定「指紋解鎖」功能" "無法再辨識%s。" "無法再辨識%1$s%2$s。" diff --git a/core/res/res/values-zh-rTW/strings.xml b/core/res/res/values-zh-rTW/strings.xml index 90cede80e250188b6349f61794bcb448bdd3d6dc..e186e7c908b2036ae381026d2160a726faa80971 100644 --- a/core/res/res/values-zh-rTW/strings.xml +++ b/core/res/res/values-zh-rTW/strings.xml @@ -1938,13 +1938,13 @@ "週末" "活動" "睡眠" + "零打擾 (%1$s)" "由「%1$s」管理" "已啟用" "已停用" "、 " "%1$s - %2$s" - - + "%1$s%2$s" "任何日曆" "「%1$s」正在關閉部分音效" "你的裝置發生內部問題,必須將裝置恢復原廠設定才能解除不穩定狀態。" @@ -2426,15 +2426,59 @@ "即使沒有行動或 Wi-Fi 網路,還是可以收發訊息" "開啟「訊息」應用程式" "運作方式" - + "開啟「自動選取網路」" + "請前往「設定」開啟「自動選取網路」,讓手機可以找到支援衛星的網路" + "開啟" + "返回" + "待處理…" + - + - + - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - "待處理…" "重新設定指紋解鎖" "系統無法再辨識「%s」。" "系統無法再辨識「%1$s」和「%2$s」。" diff --git a/core/res/res/values-zu/strings.xml b/core/res/res/values-zu/strings.xml index 5448fcd98d2b22c094da0882a9bb4a55a2a4ea78..69ec5edc9004224019bc2b7d894a7046f838157d 100644 --- a/core/res/res/values-zu/strings.xml +++ b/core/res/res/values-zu/strings.xml @@ -1938,13 +1938,13 @@ "Ngempelasonto" "Umcimbi" "Ulele" + "Ungaphazamisi (%1$s)" "Iphethwe yi-%1$s" "Kuvuliwe" "Kuvaliwe" ", " "%1$s, %2$s" - - + "U-%1$s ukuya ku-%2$s" "Noma iyiphi ikhalenda" "%1$s ithulisa eminye imisindo" "Kukhona inkinga yangaphakathi ngedivayisi yakho, futhi ingase ibe engazinzile kuze kube yilapho usetha kabusha yonke idatha." @@ -2426,15 +2426,59 @@ "Thumela futhi wamukele imilayezo ngaphandle kwenethiwekhi yeselula noma yeWiFi" "Vula Imilayezo" "Indlela esebenza ngayo" - + "Vula okuthi \"Khetha inethiwekhi ngokuzenzekela\"" + "Vula okuthi \"Khetha inethiwekhi ngokuzenzekela\" kumasethingi ukuze ifoni yakho ithole inethiwekhi esebenza nesathelayithi" + "Vula" + "Iya emuva" + "Ilindile..." + - + - + - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - "Ilindile..." "Setha Ukuvula ngesigxivizo somunwe futhi" "I-%s angeke isaziwa." "I-%1$s kanye ne-%2$s angeke isaziwa." diff --git a/core/res/res/values/attrs.xml b/core/res/res/values/attrs.xml index 092d2a72580a95f3b3c1f0bbc499d8efca361333..e6dedce8feaf4836588e7cf55d7609414a8475d6 100644 --- a/core/res/res/values/attrs.xml +++ b/core/res/res/values/attrs.xml @@ -4418,6 +4418,10 @@ + + + + + + false + + 0 + @@ -4590,6 +4596,11 @@ exists on the device, the accessibility shortcut will be disabled by default. --> + + + diff --git a/core/res/res/values/config_telephony.xml b/core/res/res/values/config_telephony.xml index 779422a70cad3b8e9d646ba2299faadfd6db76fe..31e9913dd98861134b7c9f3b2469be33b91582d0 100644 --- a/core/res/res/values/config_telephony.xml +++ b/core/res/res/values/config_telephony.xml @@ -472,10 +472,13 @@ 300000 - + + false + diff --git a/core/res/res/values/public-staging.xml b/core/res/res/values/public-staging.xml index 0c28ea406aa225c46f4817fd0403e5c85fc1b72a..b6436d0b30a5dd6f3e0a4997a96852dae63b48f7 100644 --- a/core/res/res/values/public-staging.xml +++ b/core/res/res/values/public-staging.xml @@ -125,6 +125,12 @@ + + + + + + diff --git a/core/res/res/values/stoppable_fgs_system_apps.xml b/core/res/res/values/stoppable_fgs_system_apps.xml new file mode 100644 index 0000000000000000000000000000000000000000..165ff61c7b3e46da58bce01720c06d253892a2af --- /dev/null +++ b/core/res/res/values/stoppable_fgs_system_apps.xml @@ -0,0 +1,26 @@ + + + + + + + + + + diff --git a/core/res/res/values/strings.xml b/core/res/res/values/strings.xml index d3ef07ca8122f93ba4c03415757d4f26bb7dd6e0..c13fdb17dfe3f2a974d3c2df437c8e1340c31073 100644 --- a/core/res/res/values/strings.xml +++ b/core/res/res/values/strings.xml @@ -1766,6 +1766,11 @@ Allows the app to advertise, connect, and determine the relative position of nearby Wi\u2011Fi devices + + determine relative position between nearby devices + + Allow the app to determine relative position between nearby devices + Preferred NFC Payment Service Information @@ -6522,6 +6527,54 @@ ul. Go back Pending... + + Satellite SOS is now available + + You can message emergency services if there\'s no mobile or Wi-Fi network. Google Messages must be your default messaging app. + + Satellite SOS isn\'t supported + + Satellite SOS isn\'t supported on this device + + Satellite SOS isn\'t set up + + Make sure you\'re connected to the internet and try setup again + + Satellite SOS isn\'t available + + Satellite SOS isn\'t available in this country or region + + Satellite SOS not set up + + To message by satellite, set Google Messages as your default messaging app + + Satellite SOS isn\'t available + + To check if satellite SOS is available in this country or region, turn on location settings + + Satellite messaging available + + You can message by satellite if there\'s no mobile or Wi-Fi network. Google Messages must be your default messaging app. + + Satellite messaging not supported + + Satellite messaging isn\'t supported on this device + + Satellite messaging not set up + + Make sure you\'re connected to the internet and try setup again + + Satellite messaging not available + + Satellite messaging isn\'t available in this country or region + + Satellite messaging not set up + + To message by satellite, set Google Messages as your default messaging app + + Satellite messaging not available + + To check if satellite messaging is available in this country or region, turn on location settings Set up Fingerprint Unlock again diff --git a/core/res/res/values/symbols.xml b/core/res/res/values/symbols.xml index 515ebd54b5eb06396e735d4a09cc7698c196d80d..badb98686fb232cc96e5ee032babe305c4c33d2e 100644 --- a/core/res/res/values/symbols.xml +++ b/core/res/res/values/symbols.xml @@ -312,6 +312,7 @@ + @@ -1305,6 +1306,8 @@ + + @@ -3715,6 +3718,7 @@ + @@ -5551,6 +5555,30 @@ + + + + + + + + + + + + + + + + + + + + + + + + @@ -5622,7 +5650,6 @@ - diff --git a/core/tests/coretests/src/android/app/PropertyInvalidatedCacheTests.java b/core/tests/coretests/src/android/app/PropertyInvalidatedCacheTests.java index c2d8f9129e2c7fff62c1b87865690db6ef08e2be..a2598f69e031cdb01f121b84411a4d19422f6e54 100644 --- a/core/tests/coretests/src/android/app/PropertyInvalidatedCacheTests.java +++ b/core/tests/coretests/src/android/app/PropertyInvalidatedCacheTests.java @@ -16,7 +16,11 @@ package android.app; +import static android.app.Flags.FLAG_PIC_ISOLATE_CACHE_BY_UID; import static android.app.PropertyInvalidatedCache.NONCE_UNSET; +import static android.app.PropertyInvalidatedCache.MODULE_BLUETOOTH; +import static android.app.PropertyInvalidatedCache.MODULE_SYSTEM; +import static android.app.PropertyInvalidatedCache.MODULE_TEST; import static android.app.PropertyInvalidatedCache.NonceStore.INVALID_NONCE_INDEX; import static com.android.internal.os.Flags.FLAG_APPLICATION_SHARED_MEMORY_ENABLED; @@ -27,6 +31,9 @@ import static org.junit.Assert.assertSame; import static org.junit.Assert.assertTrue; import static org.junit.Assert.fail; +import android.annotation.SuppressLint; +import android.app.PropertyInvalidatedCache.Args; +import android.os.Binder; import com.android.internal.os.ApplicationSharedMemory; import android.platform.test.annotations.IgnoreUnderRavenwood; @@ -53,11 +60,12 @@ import org.junit.Test; */ @SmallTest public class PropertyInvalidatedCacheTests { + @Rule public final CheckFlagsRule mCheckFlagsRule = DeviceFlagsValueProvider.createCheckFlagsRule(); // Configuration for creating caches - private static final String MODULE = PropertyInvalidatedCache.MODULE_TEST; + private static final String MODULE = MODULE_TEST; private static final String API = "testApi"; // This class is a proxy for binder calls. It contains a counter that increments @@ -245,6 +253,12 @@ public class PropertyInvalidatedCacheTests { mQuery = query; } + // Create a cache from the args. The name of the cache is the api. + TestCache(Args args, TestQuery query) { + super(args, args.mApi(), query); + mQuery = query; + } + public int getRecomputeCount() { return mQuery.getRecomputeCount(); } @@ -374,14 +388,11 @@ public class PropertyInvalidatedCacheTests { @Test public void testPropertyNames() { String n1; - n1 = PropertyInvalidatedCache.createPropertyName( - PropertyInvalidatedCache.MODULE_SYSTEM, "getPackageInfo"); + n1 = PropertyInvalidatedCache.createPropertyName(MODULE_SYSTEM, "getPackageInfo"); assertEquals(n1, "cache_key.system_server.get_package_info"); - n1 = PropertyInvalidatedCache.createPropertyName( - PropertyInvalidatedCache.MODULE_SYSTEM, "get_package_info"); + n1 = PropertyInvalidatedCache.createPropertyName(MODULE_SYSTEM, "get_package_info"); assertEquals(n1, "cache_key.system_server.get_package_info"); - n1 = PropertyInvalidatedCache.createPropertyName( - PropertyInvalidatedCache.MODULE_BLUETOOTH, "getState"); + n1 = PropertyInvalidatedCache.createPropertyName(MODULE_BLUETOOTH, "getState"); assertEquals(n1, "cache_key.bluetooth.get_state"); } @@ -391,7 +402,7 @@ public class PropertyInvalidatedCacheTests { reason = "SystemProperties doesn't have permission check") public void testPermissionFailure() { // Create a cache that will write a system nonce. - TestCache sysCache = new TestCache(PropertyInvalidatedCache.MODULE_SYSTEM, "mode1"); + TestCache sysCache = new TestCache(MODULE_SYSTEM, "mode1"); try { // Invalidate the cache, which writes the system property. There must be a permission // failure. @@ -407,7 +418,7 @@ public class PropertyInvalidatedCacheTests { @Test public void testTestMode() { // Create a cache that will write a system nonce. - TestCache sysCache = new TestCache(PropertyInvalidatedCache.MODULE_SYSTEM, "mode1"); + TestCache sysCache = new TestCache(MODULE_SYSTEM, "mode1"); sysCache.testPropertyName(); // Invalidate the cache. This must succeed because the property has been marked for @@ -416,7 +427,7 @@ public class PropertyInvalidatedCacheTests { // Create a cache that uses MODULE_TEST. Invalidation succeeds whether or not the // property is tagged as being tested. - TestCache testCache = new TestCache(PropertyInvalidatedCache.MODULE_TEST, "mode2"); + TestCache testCache = new TestCache(MODULE_TEST, "mode2"); testCache.invalidateCache(); testCache.testPropertyName(); testCache.invalidateCache(); @@ -432,7 +443,7 @@ public class PropertyInvalidatedCacheTests { // The expected exception. } // Configuring a property for testing must fail if test mode is false. - TestCache cache2 = new TestCache(PropertyInvalidatedCache.MODULE_SYSTEM, "mode3"); + TestCache cache2 = new TestCache(MODULE_SYSTEM, "mode3"); try { cache2.testPropertyName(); fail("expected an IllegalStateException"); @@ -444,6 +455,35 @@ public class PropertyInvalidatedCacheTests { PropertyInvalidatedCache.setTestMode(true); } + // Test the Args-style constructor. + @Test + public void testArgsConstructor() { + // Create a cache with a maximum of four entries and non-isolated UIDs. + TestCache cache = new TestCache(new Args(MODULE_TEST) + .maxEntries(4).isolateUids(false).api("init1"), + new TestQuery()); + + cache.invalidateCache(); + for (int i = 1; i <= 4; i++) { + assertEquals("foo" + i, cache.query(i)); + assertEquals(i, cache.getRecomputeCount()); + } + // Everything is in the cache. The recompute count must not increase. + for (int i = 1; i <= 4; i++) { + assertEquals("foo" + i, cache.query(i)); + assertEquals(4, cache.getRecomputeCount()); + } + // Overflow the max entries. The recompute count increases by one. + assertEquals("foo5", cache.query(5)); + assertEquals(5, cache.getRecomputeCount()); + // The oldest entry (1) has been evicted. Iterating through the first four entries will + // sequentially evict them all because the loop is proceeding oldest to newest. + for (int i = 1; i <= 4; i++) { + assertEquals("foo" + i, cache.query(i)); + assertEquals(5+i, cache.getRecomputeCount()); + } + } + // Verify the behavior of shared memory nonce storage. This does not directly test the cache // storing nonces in shared memory. @RequiresFlagsEnabled(FLAG_APPLICATION_SHARED_MEMORY_ENABLED) @@ -495,4 +535,112 @@ public class PropertyInvalidatedCacheTests { shmem.close(); } + + // Verify that an invalid module causes an exception. + private void testInvalidModule(String module) { + try { + @SuppressLint("UnusedVariable") + Args arg = new Args(module); + fail("expected an invalid module exception: module=" + module); + } catch (IllegalArgumentException e) { + // Expected exception. + } + } + + // Test various instantiation errors. The good path is tested in other methods. + @Test + public void testArgumentErrors() { + // Verify that an illegal module throws an exception. + testInvalidModule(MODULE_SYSTEM.substring(0, MODULE_SYSTEM.length() - 1)); + testInvalidModule(MODULE_SYSTEM + "x"); + testInvalidModule("mymodule"); + + // Verify that a negative max entries throws. + Args arg = new Args(MODULE_SYSTEM); + try { + arg.maxEntries(0); + fail("expected an invalid maxEntries exception"); + } catch (IllegalArgumentException e) { + // Expected exception. + } + + // Verify that creating a cache with an invalid property string throws. + try { + final String badKey = "cache_key.volume_list"; + @SuppressLint("UnusedVariable") + var cache = new PropertyInvalidatedCache(4, badKey); + fail("expected bad property exception: prop=" + badKey); + } catch (IllegalArgumentException e) { + // Expected exception. + } + } + + // Verify that a cache created with isolatedUids(true) separates out the results. + @RequiresFlagsEnabled(FLAG_PIC_ISOLATE_CACHE_BY_UID) + @Test + public void testIsolatedUids() { + TestCache cache = new TestCache(new Args(MODULE_TEST) + .maxEntries(4).isolateUids(true).api("testIsolatedUids").testMode(true), + new TestQuery()); + cache.invalidateCache(); + final int uid1 = 1; + final int uid2 = 2; + + long token = Binder.setCallingWorkSourceUid(uid1); + try { + // Populate the cache for user 1 + assertEquals("foo5", cache.query(5)); + assertEquals(1, cache.getRecomputeCount()); + assertEquals("foo5", cache.query(5)); + assertEquals(1, cache.getRecomputeCount()); + assertEquals("foo6", cache.query(6)); + assertEquals(2, cache.getRecomputeCount()); + + // Populate the cache for user 2. User 1 values are not reused. + Binder.setCallingWorkSourceUid(uid2); + assertEquals("foo5", cache.query(5)); + assertEquals(3, cache.getRecomputeCount()); + assertEquals("foo5", cache.query(5)); + assertEquals(3, cache.getRecomputeCount()); + + // Verify that the cache for user 1 is still populated. + Binder.setCallingWorkSourceUid(uid1); + assertEquals("foo5", cache.query(5)); + assertEquals(3, cache.getRecomputeCount()); + + } finally { + Binder.restoreCallingWorkSource(token); + } + + // Repeat the test with a non-isolated cache. + cache = new TestCache(new Args(MODULE_TEST) + .maxEntries(4).isolateUids(false).api("testIsolatedUids2").testMode(true), + new TestQuery()); + cache.invalidateCache(); + token = Binder.setCallingWorkSourceUid(uid1); + try { + // Populate the cache for user 1 + assertEquals("foo5", cache.query(5)); + assertEquals(1, cache.getRecomputeCount()); + assertEquals("foo5", cache.query(5)); + assertEquals(1, cache.getRecomputeCount()); + assertEquals("foo6", cache.query(6)); + assertEquals(2, cache.getRecomputeCount()); + + // Populate the cache for user 2. User 1 values are reused. + Binder.setCallingWorkSourceUid(uid2); + assertEquals("foo5", cache.query(5)); + assertEquals(2, cache.getRecomputeCount()); + assertEquals("foo5", cache.query(5)); + assertEquals(2, cache.getRecomputeCount()); + + // Verify that the cache for user 1 is still populated. + Binder.setCallingWorkSourceUid(uid1); + assertEquals("foo5", cache.query(5)); + assertEquals(2, cache.getRecomputeCount()); + + } finally { + Binder.restoreCallingWorkSource(token); + } + } } diff --git a/core/tests/coretests/src/android/app/activity/ActivityThreadTest.java b/core/tests/coretests/src/android/app/activity/ActivityThreadTest.java index 24f6ceaf786cb6ded7579366da142bd9c27b9da2..8d045f87063b9a8c8dd80612819540a78fd8e31c 100644 --- a/core/tests/coretests/src/android/app/activity/ActivityThreadTest.java +++ b/core/tests/coretests/src/android/app/activity/ActivityThreadTest.java @@ -26,6 +26,7 @@ import static android.view.Display.DEFAULT_DISPLAY; import static android.view.Display.INVALID_DISPLAY; import static com.google.common.truth.Truth.assertThat; +import static com.google.common.truth.Truth.assertWithMessage; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertFalse; @@ -59,6 +60,7 @@ import android.app.servertransaction.ResumeActivityItem; import android.app.servertransaction.StopActivityItem; import android.content.Context; import android.content.Intent; +import android.content.pm.ApplicationInfo; import android.content.res.CompatibilityInfo; import android.content.res.Configuration; import android.content.res.Resources; @@ -67,7 +69,11 @@ import android.hardware.display.DisplayManager; import android.hardware.display.VirtualDisplay; import android.os.Bundle; import android.os.IBinder; +import android.os.Looper; import android.platform.test.annotations.Presubmit; +import android.platform.test.annotations.RequiresFlagsEnabled; +import android.platform.test.flag.junit.CheckFlagsRule; +import android.platform.test.flag.junit.DeviceFlagsValueProvider; import android.platform.test.flag.junit.SetFlagsRule; import android.util.DisplayMetrics; import android.util.Log; @@ -129,6 +135,9 @@ public class ActivityThreadTest { @Rule(order = 1) public final SetFlagsRule mSetFlagsRule = new SetFlagsRule(DEVICE_DEFAULT); + @Rule + public final CheckFlagsRule mCheckFlagsRule = DeviceFlagsValueProvider.createCheckFlagsRule(); + private ActivityWindowInfoListener mActivityWindowInfoListener; private WindowTokenClientController mOriginalWindowTokenClientController; private Configuration mOriginalAppConfig; @@ -911,6 +920,32 @@ public class ActivityThreadTest { }); } + /** + * Verifies that {@link ActivityThread#handleApplicationInfoChanged} does send updates to the + * system context, when given the system application info. + */ + @RequiresFlagsEnabled(android.content.res.Flags.FLAG_SYSTEM_CONTEXT_HANDLE_APP_INFO_CHANGED) + @Test + public void testHandleApplicationInfoChanged_systemContext() { + Looper.prepare(); + final var systemThread = ActivityThread.createSystemActivityThreadForTesting(); + + final Context systemContext = systemThread.getSystemContext(); + final var appInfo = systemContext.getApplicationInfo(); + // sourceDir must not be null, and contain at least a '/', for handleApplicationInfoChanged. + appInfo.sourceDir = "/"; + + // Create a copy of the application info. + final var newAppInfo = new ApplicationInfo(appInfo); + newAppInfo.sourceDir = "/"; + assertWithMessage("New application info is a separate instance") + .that(systemContext.getApplicationInfo()).isNotSameInstanceAs(newAppInfo); + + systemThread.handleApplicationInfoChanged(newAppInfo); + assertWithMessage("Application info was updated successfully") + .that(systemContext.getApplicationInfo()).isSameInstanceAs(newAppInfo); + } + /** * Calls {@link ActivityThread#handleActivityConfigurationChanged(ActivityClientRecord, * Configuration, int, ActivityWindowInfo)} to try to push activity configuration to the diff --git a/core/tests/coretests/src/android/app/servertransaction/ClientTransactionListenerControllerTest.java b/core/tests/coretests/src/android/app/servertransaction/ClientTransactionListenerControllerTest.java index 31a4f16553a0855d8cc83a30cfab82c54c9caeee..911b7ce22741f576620e7e332e6818217b13f7ec 100644 --- a/core/tests/coretests/src/android/app/servertransaction/ClientTransactionListenerControllerTest.java +++ b/core/tests/coretests/src/android/app/servertransaction/ClientTransactionListenerControllerTest.java @@ -120,7 +120,8 @@ public class ClientTransactionListenerControllerTest { doReturn(newDisplayInfo).when(mIDisplayManager).getDisplayInfo(123); mDisplayManager.registerDisplayListener(mListener, mHandler, - DisplayManager.EVENT_FLAG_DISPLAY_CHANGED, null /* packageName */); + DisplayManagerGlobal.INTERNAL_EVENT_FLAG_DISPLAY_CHANGED, + null /* packageName */); mController.onDisplayChanged(123); mHandler.runWithScissors(() -> { }, 0); diff --git a/core/tests/coretests/src/android/hardware/display/DisplayManagerGlobalTest.java b/core/tests/coretests/src/android/hardware/display/DisplayManagerGlobalTest.java index 5a0dacb38865b9a6ef5c9faca8d7d6351ff28465..9552c887443b1d07758baffd7feac3306908f561 100644 --- a/core/tests/coretests/src/android/hardware/display/DisplayManagerGlobalTest.java +++ b/core/tests/coretests/src/android/hardware/display/DisplayManagerGlobalTest.java @@ -55,9 +55,10 @@ import org.mockito.MockitoAnnotations; @RunWith(AndroidJUnit4.class) public class DisplayManagerGlobalTest { - private static final long ALL_DISPLAY_EVENTS = DisplayManager.EVENT_FLAG_DISPLAY_ADDED - | DisplayManager.EVENT_FLAG_DISPLAY_CHANGED - | DisplayManager.EVENT_FLAG_DISPLAY_REMOVED; + private static final long ALL_DISPLAY_EVENTS = + DisplayManagerGlobal.INTERNAL_EVENT_FLAG_DISPLAY_ADDED + | DisplayManagerGlobal.INTERNAL_EVENT_FLAG_DISPLAY_CHANGED + | DisplayManagerGlobal.INTERNAL_EVENT_FLAG_DISPLAY_REMOVED; @Mock private IDisplayManager mDisplayManager; @@ -127,19 +128,22 @@ public class DisplayManagerGlobalTest { int displayId = 1; mDisplayManagerGlobal.registerDisplayListener(mListener, mHandler, - ALL_DISPLAY_EVENTS & ~DisplayManager.EVENT_FLAG_DISPLAY_ADDED, null); + ALL_DISPLAY_EVENTS + & ~DisplayManagerGlobal.INTERNAL_EVENT_FLAG_DISPLAY_ADDED, null); callback.onDisplayEvent(displayId, DisplayManagerGlobal.EVENT_DISPLAY_ADDED); waitForHandler(); Mockito.verifyZeroInteractions(mListener); mDisplayManagerGlobal.registerDisplayListener(mListener, mHandler, - ALL_DISPLAY_EVENTS & ~DisplayManager.EVENT_FLAG_DISPLAY_CHANGED, null); + ALL_DISPLAY_EVENTS + & ~DisplayManagerGlobal.INTERNAL_EVENT_FLAG_DISPLAY_CHANGED, null); callback.onDisplayEvent(displayId, DisplayManagerGlobal.EVENT_DISPLAY_CHANGED); waitForHandler(); Mockito.verifyZeroInteractions(mListener); mDisplayManagerGlobal.registerDisplayListener(mListener, mHandler, - ALL_DISPLAY_EVENTS & ~DisplayManager.EVENT_FLAG_DISPLAY_REMOVED, null); + ALL_DISPLAY_EVENTS + & ~DisplayManagerGlobal.INTERNAL_EVENT_FLAG_DISPLAY_REMOVED, null); callback.onDisplayEvent(displayId, DisplayManagerGlobal.EVENT_DISPLAY_REMOVED); waitForHandler(); Mockito.verifyZeroInteractions(mListener); @@ -162,22 +166,25 @@ public class DisplayManagerGlobalTest { public void testDisplayManagerGlobalRegistersWithDisplayManager_WhenThereAreListeners() throws RemoteException { mDisplayManagerGlobal.registerDisplayListener(mListener, mHandler, - DisplayManager.EVENT_FLAG_DISPLAY_BRIGHTNESS, null); + DisplayManagerGlobal.INTERNAL_EVENT_FLAG_DISPLAY_BRIGHTNESS_CHANGED, + null); InOrder inOrder = Mockito.inOrder(mDisplayManager); inOrder.verify(mDisplayManager) .registerCallbackWithEventMask(mCallbackCaptor.capture(), - eq(DisplayManager.EVENT_FLAG_DISPLAY_BRIGHTNESS)); + eq(DisplayManagerGlobal.INTERNAL_EVENT_FLAG_DISPLAY_BRIGHTNESS_CHANGED)); mDisplayManagerGlobal.registerNativeChoreographerForRefreshRateCallbacks(); inOrder.verify(mDisplayManager) .registerCallbackWithEventMask(mCallbackCaptor.capture(), - eq(ALL_DISPLAY_EVENTS | DisplayManager.EVENT_FLAG_DISPLAY_BRIGHTNESS)); + eq(ALL_DISPLAY_EVENTS + | DisplayManagerGlobal + .INTERNAL_EVENT_FLAG_DISPLAY_BRIGHTNESS_CHANGED)); mDisplayManagerGlobal.unregisterNativeChoreographerForRefreshRateCallbacks(); inOrder.verify(mDisplayManager) .registerCallbackWithEventMask(mCallbackCaptor.capture(), - eq(DisplayManager.EVENT_FLAG_DISPLAY_BRIGHTNESS)); + eq(DisplayManagerGlobal.INTERNAL_EVENT_FLAG_DISPLAY_BRIGHTNESS_CHANGED)); mDisplayManagerGlobal.unregisterDisplayListener(mListener); inOrder.verify(mDisplayManager) @@ -196,10 +203,12 @@ public class DisplayManagerGlobalTest { // One listener listens on add/remove, and the other one listens on change. mDisplayManagerGlobal.registerDisplayListener(mListener, mHandler, - DisplayManager.EVENT_FLAG_DISPLAY_ADDED - | DisplayManager.EVENT_FLAG_DISPLAY_REMOVED, null /* packageName */); + DisplayManagerGlobal.INTERNAL_EVENT_FLAG_DISPLAY_ADDED + | DisplayManagerGlobal.INTERNAL_EVENT_FLAG_DISPLAY_REMOVED, + null /* packageName */); mDisplayManagerGlobal.registerDisplayListener(mListener2, mHandler, - DisplayManager.EVENT_FLAG_DISPLAY_CHANGED, null /* packageName */); + DisplayManagerGlobal.INTERNAL_EVENT_FLAG_DISPLAY_CHANGED, + null /* packageName */); mDisplayManagerGlobal.handleDisplayChangeFromWindowManager(321); waitForHandler(); diff --git a/core/tests/coretests/src/android/hardware/display/DisplayTopologyTest.kt b/core/tests/coretests/src/android/hardware/display/DisplayTopologyTest.kt new file mode 100644 index 0000000000000000000000000000000000000000..a6de611cc077914eaf52974216e74091000afd64 --- /dev/null +++ b/core/tests/coretests/src/android/hardware/display/DisplayTopologyTest.kt @@ -0,0 +1,472 @@ +/* + * 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.display + +import android.hardware.display.DisplayTopology.TreeNode.POSITION_BOTTOM +import android.hardware.display.DisplayTopology.TreeNode.POSITION_TOP +import android.hardware.display.DisplayTopology.TreeNode.POSITION_RIGHT +import android.view.Display +import com.google.common.truth.Truth.assertThat +import org.junit.Test + +class DisplayTopologyTest { + private var topology = DisplayTopology() + + @Test + fun addOneDisplay() { + val displayId = 1 + val width = 800f + val height = 600f + + topology.addDisplay(displayId, width, height) + + assertThat(topology.primaryDisplayId).isEqualTo(displayId) + + val display = topology.root!! + assertThat(display.displayId).isEqualTo(displayId) + assertThat(display.width).isEqualTo(width) + assertThat(display.height).isEqualTo(height) + assertThat(display.children).isEmpty() + } + + @Test + fun addTwoDisplays() { + val displayId1 = 1 + val width1 = 800f + val height1 = 600f + + val displayId2 = 2 + val width2 = 1000f + val height2 = 1500f + + topology.addDisplay(displayId1, width1, height1) + topology.addDisplay(displayId2, width2, height2) + + assertThat(topology.primaryDisplayId).isEqualTo(displayId1) + + val display1 = topology.root!! + assertThat(display1.displayId).isEqualTo(displayId1) + assertThat(display1.width).isEqualTo(width1) + assertThat(display1.height).isEqualTo(height1) + assertThat(display1.children).hasSize(1) + + val display2 = display1.children[0] + assertThat(display2.displayId).isEqualTo(displayId2) + assertThat(display2.width).isEqualTo(width2) + assertThat(display2.height).isEqualTo(height2) + assertThat(display2.children).isEmpty() + assertThat(display2.position).isEqualTo(POSITION_TOP) + assertThat(display2.offset).isEqualTo(width1 / 2 - width2 / 2) + } + + @Test + fun addManyDisplays() { + val displayId1 = 1 + val width1 = 800f + val height1 = 600f + + val displayId2 = 2 + val width2 = 1000f + val height2 = 1500f + + topology.addDisplay(displayId1, width1, height1) + topology.addDisplay(displayId2, width2, height2) + + val noOfDisplays = 30 + for (i in 3..noOfDisplays) { + topology.addDisplay(/* displayId= */ i, width1, height1) + } + + assertThat(topology.primaryDisplayId).isEqualTo(displayId1) + + val display1 = topology.root!! + assertThat(display1.displayId).isEqualTo(displayId1) + assertThat(display1.width).isEqualTo(width1) + assertThat(display1.height).isEqualTo(height1) + assertThat(display1.children).hasSize(1) + + val display2 = display1.children[0] + assertThat(display2.displayId).isEqualTo(displayId2) + assertThat(display2.width).isEqualTo(width2) + assertThat(display2.height).isEqualTo(height2) + assertThat(display2.children).hasSize(1) + assertThat(display2.position).isEqualTo(POSITION_TOP) + assertThat(display2.offset).isEqualTo(width1 / 2 - width2 / 2) + + var display = display2 + for (i in 3..noOfDisplays) { + display = display.children[0] + assertThat(display.displayId).isEqualTo(i) + assertThat(display.width).isEqualTo(width1) + assertThat(display.height).isEqualTo(height1) + // The last display should have no children + assertThat(display.children).hasSize(if (i < noOfDisplays) 1 else 0) + assertThat(display.position).isEqualTo(POSITION_RIGHT) + assertThat(display.offset).isEqualTo(0) + } + } + + @Test + fun removeDisplays() { + val displayId1 = 1 + val width1 = 800f + val height1 = 600f + + val displayId2 = 2 + val width2 = 1000f + val height2 = 1500f + + topology.addDisplay(displayId1, width1, height1) + topology.addDisplay(displayId2, width2, height2) + + val noOfDisplays = 30 + for (i in 3..noOfDisplays) { + topology.addDisplay(/* displayId= */ i, width1, height1) + } + + var removedDisplays = arrayOf(20) + topology.removeDisplay(20) + + assertThat(topology.primaryDisplayId).isEqualTo(displayId1) + + var display1 = topology.root!! + assertThat(display1.displayId).isEqualTo(displayId1) + assertThat(display1.width).isEqualTo(width1) + assertThat(display1.height).isEqualTo(height1) + assertThat(display1.children).hasSize(1) + + var display2 = display1.children[0] + assertThat(display2.displayId).isEqualTo(displayId2) + assertThat(display2.width).isEqualTo(width2) + assertThat(display2.height).isEqualTo(height2) + assertThat(display2.children).hasSize(1) + assertThat(display2.position).isEqualTo(POSITION_TOP) + assertThat(display2.offset).isEqualTo(width1 / 2 - width2 / 2) + + var display = display2 + for (i in 3..noOfDisplays) { + if (i in removedDisplays) { + continue + } + display = display.children[0] + assertThat(display.displayId).isEqualTo(i) + assertThat(display.width).isEqualTo(width1) + assertThat(display.height).isEqualTo(height1) + // The last display should have no children + assertThat(display.children).hasSize(if (i < noOfDisplays) 1 else 0) + assertThat(display.position).isEqualTo(POSITION_RIGHT) + assertThat(display.offset).isEqualTo(0) + } + + topology.removeDisplay(22) + removedDisplays += 22 + topology.removeDisplay(23) + removedDisplays += 23 + topology.removeDisplay(25) + removedDisplays += 25 + + assertThat(topology.primaryDisplayId).isEqualTo(displayId1) + + display1 = topology.root!! + assertThat(display1.displayId).isEqualTo(displayId1) + assertThat(display1.width).isEqualTo(width1) + assertThat(display1.height).isEqualTo(height1) + assertThat(display1.children).hasSize(1) + + display2 = display1.children[0] + assertThat(display2.displayId).isEqualTo(displayId2) + assertThat(display2.width).isEqualTo(width2) + assertThat(display2.height).isEqualTo(height2) + assertThat(display2.children).hasSize(1) + assertThat(display2.position).isEqualTo(POSITION_TOP) + assertThat(display2.offset).isEqualTo(width1 / 2 - width2 / 2) + + display = display2 + for (i in 3..noOfDisplays) { + if (i in removedDisplays) { + continue + } + display = display.children[0] + assertThat(display.displayId).isEqualTo(i) + assertThat(display.width).isEqualTo(width1) + assertThat(display.height).isEqualTo(height1) + // The last display should have no children + assertThat(display.children).hasSize(if (i < noOfDisplays) 1 else 0) + assertThat(display.position).isEqualTo(POSITION_RIGHT) + assertThat(display.offset).isEqualTo(0) + } + } + + @Test + fun removeAllDisplays() { + val displayId = 1 + val width = 800f + val height = 600f + + topology.addDisplay(displayId, width, height) + topology.removeDisplay(displayId) + + assertThat(topology.primaryDisplayId).isEqualTo(Display.INVALID_DISPLAY) + assertThat(topology.root).isNull() + } + + @Test + fun removeDisplayThatDoesNotExist() { + val displayId = 1 + val width = 800f + val height = 600f + + topology.addDisplay(displayId, width, height) + topology.removeDisplay(3) + + assertThat(topology.primaryDisplayId).isEqualTo(displayId) + + val display = topology.root!! + assertThat(display.displayId).isEqualTo(displayId) + assertThat(display.width).isEqualTo(width) + assertThat(display.height).isEqualTo(height) + assertThat(display.children).isEmpty() + } + + @Test + fun removePrimaryDisplay() { + val displayId1 = 1 + val displayId2 = 2 + val width = 800f + val height = 600f + + topology = DisplayTopology(/* root= */ null, displayId2) + topology.addDisplay(displayId1, width, height) + topology.addDisplay(displayId2, width, height) + topology.removeDisplay(displayId2) + + assertThat(topology.primaryDisplayId).isEqualTo(displayId1) + val display = topology.root!! + assertThat(display.displayId).isEqualTo(displayId1) + assertThat(display.width).isEqualTo(width) + assertThat(display.height).isEqualTo(height) + assertThat(display.children).isEmpty() + } + + @Test + fun normalization_noOverlaps_leavesTopologyUnchanged() { + val display1 = DisplayTopology.TreeNode(/* displayId= */ 1, /* width= */ 200f, + /* height= */ 600f, /* position= */ 0, /* offset= */ 0f) + + val display2 = DisplayTopology.TreeNode(/* displayId= */ 2, /* width= */ 600f, + /* height= */ 200f, POSITION_RIGHT, /* offset= */ 0f) + display1.addChild(display2) + + val primaryDisplayId = 3 + val display3 = DisplayTopology.TreeNode(primaryDisplayId, /* width= */ 600f, + /* height= */ 200f, POSITION_RIGHT, /* offset= */ 400f) + display1.addChild(display3) + + val display4 = DisplayTopology.TreeNode(/* displayId= */ 4, /* width= */ 200f, + /* height= */ 600f, POSITION_RIGHT, /* offset= */ 0f) + display2.addChild(display4) + + topology = DisplayTopology(display1, primaryDisplayId) + topology.normalize() + + assertThat(topology.primaryDisplayId).isEqualTo(primaryDisplayId) + + val actualDisplay1 = topology.root!! + assertThat(actualDisplay1.displayId).isEqualTo(1) + assertThat(actualDisplay1.width).isEqualTo(200f) + assertThat(actualDisplay1.height).isEqualTo(600f) + assertThat(actualDisplay1.children).hasSize(2) + + val actualDisplay2 = actualDisplay1.children[0] + assertThat(actualDisplay2.displayId).isEqualTo(2) + assertThat(actualDisplay2.width).isEqualTo(600f) + assertThat(actualDisplay2.height).isEqualTo(200f) + assertThat(actualDisplay2.position).isEqualTo(POSITION_RIGHT) + assertThat(actualDisplay2.offset).isEqualTo(0f) + assertThat(actualDisplay2.children).hasSize(1) + + val actualDisplay3 = actualDisplay1.children[1] + assertThat(actualDisplay3.displayId).isEqualTo(3) + assertThat(actualDisplay3.width).isEqualTo(600f) + assertThat(actualDisplay3.height).isEqualTo(200f) + assertThat(actualDisplay3.position).isEqualTo(POSITION_RIGHT) + assertThat(actualDisplay3.offset).isEqualTo(400f) + assertThat(actualDisplay3.children).isEmpty() + + val actualDisplay4 = actualDisplay2.children[0] + assertThat(actualDisplay4.displayId).isEqualTo(4) + assertThat(actualDisplay4.width).isEqualTo(200f) + assertThat(actualDisplay4.height).isEqualTo(600f) + assertThat(actualDisplay4.position).isEqualTo(POSITION_RIGHT) + assertThat(actualDisplay4.offset).isEqualTo(0f) + assertThat(actualDisplay4.children).isEmpty() + } + + @Test + fun normalization_moveDisplayWithoutReparenting() { + val display1 = DisplayTopology.TreeNode(/* displayId= */ 1, /* width= */ 200f, + /* height= */ 600f, /* position= */ 0, /* offset= */ 0f) + + val display2 = DisplayTopology.TreeNode(/* displayId= */ 2, /* width= */ 200f, + /* height= */ 600f, POSITION_RIGHT, /* offset= */ 0f) + display1.addChild(display2) + + val primaryDisplayId = 3 + val display3 = DisplayTopology.TreeNode(primaryDisplayId, /* width= */ 600f, + /* height= */ 200f, POSITION_RIGHT, /* offset= */ 10f) + display1.addChild(display3) + + val display4 = DisplayTopology.TreeNode(/* displayId= */ 4, /* width= */ 200f, + /* height= */ 600f, POSITION_RIGHT, /* offset= */ 0f) + display2.addChild(display4) + + topology = DisplayTopology(display1, primaryDisplayId) + // Display 3 becomes a child of display 2. Display 4 gets moved without changing its parent. + topology.normalize() + + assertThat(topology.primaryDisplayId).isEqualTo(primaryDisplayId) + + val actualDisplay1 = topology.root!! + assertThat(actualDisplay1.displayId).isEqualTo(1) + assertThat(actualDisplay1.width).isEqualTo(200f) + assertThat(actualDisplay1.height).isEqualTo(600f) + assertThat(actualDisplay1.children).hasSize(1) + + val actualDisplay2 = actualDisplay1.children[0] + assertThat(actualDisplay2.displayId).isEqualTo(2) + assertThat(actualDisplay2.width).isEqualTo(200f) + assertThat(actualDisplay2.height).isEqualTo(600f) + assertThat(actualDisplay2.position).isEqualTo(POSITION_RIGHT) + assertThat(actualDisplay2.offset).isEqualTo(0f) + assertThat(actualDisplay2.children).hasSize(2) + + val actualDisplay3 = actualDisplay2.children[1] + assertThat(actualDisplay3.displayId).isEqualTo(3) + assertThat(actualDisplay3.width).isEqualTo(600f) + assertThat(actualDisplay3.height).isEqualTo(200f) + assertThat(actualDisplay3.position).isEqualTo(POSITION_RIGHT) + assertThat(actualDisplay3.offset).isEqualTo(10f) + assertThat(actualDisplay3.children).isEmpty() + + val actualDisplay4 = actualDisplay2.children[0] + assertThat(actualDisplay4.displayId).isEqualTo(4) + assertThat(actualDisplay4.width).isEqualTo(200f) + assertThat(actualDisplay4.height).isEqualTo(600f) + assertThat(actualDisplay4.position).isEqualTo(POSITION_RIGHT) + assertThat(actualDisplay4.offset).isEqualTo(210f) + assertThat(actualDisplay4.children).isEmpty() + } + + @Test + fun normalization_moveDisplayWithoutReparenting_offsetOutOfBounds() { + val display1 = DisplayTopology.TreeNode(/* displayId= */ 1, /* width= */ 200f, + /* height= */ 50f, /* position= */ 0, /* offset= */ 0f) + + val display2 = DisplayTopology.TreeNode(/* displayId= */ 2, /* width= */ 600f, + /* height= */ 200f, POSITION_RIGHT, /* offset= */ 0f) + display1.addChild(display2) + + val primaryDisplayId = 3 + val display3 = DisplayTopology.TreeNode(primaryDisplayId, /* width= */ 600f, + /* height= */ 200f, POSITION_RIGHT, /* offset= */ 10f) + display1.addChild(display3) + + topology = DisplayTopology(display1, primaryDisplayId) + // Display 3 gets moved and its left side is still on the same line as the right side + // of Display 1, but it no longer touches it (the offset is out of bounds), so Display 2 + // becomes its new parent. + topology.normalize() + + assertThat(topology.primaryDisplayId).isEqualTo(primaryDisplayId) + + val actualDisplay1 = topology.root!! + assertThat(actualDisplay1.displayId).isEqualTo(1) + assertThat(actualDisplay1.width).isEqualTo(200f) + assertThat(actualDisplay1.height).isEqualTo(50f) + assertThat(actualDisplay1.children).hasSize(1) + + val actualDisplay2 = actualDisplay1.children[0] + assertThat(actualDisplay2.displayId).isEqualTo(2) + assertThat(actualDisplay2.width).isEqualTo(600f) + assertThat(actualDisplay2.height).isEqualTo(200f) + assertThat(actualDisplay2.position).isEqualTo(POSITION_RIGHT) + assertThat(actualDisplay2.offset).isEqualTo(0f) + assertThat(actualDisplay2.children).hasSize(1) + + val actualDisplay3 = actualDisplay2.children[0] + assertThat(actualDisplay3.displayId).isEqualTo(3) + assertThat(actualDisplay3.width).isEqualTo(600f) + assertThat(actualDisplay3.height).isEqualTo(200f) + assertThat(actualDisplay3.position).isEqualTo(POSITION_BOTTOM) + assertThat(actualDisplay3.offset).isEqualTo(0f) + assertThat(actualDisplay3.children).isEmpty() + } + + @Test + fun normalization_moveAndReparentDisplay() { + val display1 = DisplayTopology.TreeNode(/* displayId= */ 1, /* width= */ 200f, + /* height= */ 600f, /* position= */ 0, /* offset= */ 0f) + + val display2 = DisplayTopology.TreeNode(/* displayId= */ 2, /* width= */ 200f, + /* height= */ 600f, POSITION_RIGHT, /* offset= */ 0f) + display1.addChild(display2) + + val primaryDisplayId = 3 + val display3 = DisplayTopology.TreeNode(primaryDisplayId, /* width= */ 600f, + /* height= */ 200f, POSITION_RIGHT, /* offset= */ 400f) + display1.addChild(display3) + + val display4 = DisplayTopology.TreeNode(/* displayId= */ 4, /* width= */ 200f, + /* height= */ 600f, POSITION_RIGHT, /* offset= */ 0f) + display2.addChild(display4) + + topology = DisplayTopology(display1, primaryDisplayId) + topology.normalize() + + assertThat(topology.primaryDisplayId).isEqualTo(primaryDisplayId) + + val actualDisplay1 = topology.root!! + assertThat(actualDisplay1.displayId).isEqualTo(1) + assertThat(actualDisplay1.width).isEqualTo(200f) + assertThat(actualDisplay1.height).isEqualTo(600f) + assertThat(actualDisplay1.children).hasSize(1) + + val actualDisplay2 = actualDisplay1.children[0] + assertThat(actualDisplay2.displayId).isEqualTo(2) + assertThat(actualDisplay2.width).isEqualTo(200f) + assertThat(actualDisplay2.height).isEqualTo(600f) + assertThat(actualDisplay2.position).isEqualTo(POSITION_RIGHT) + assertThat(actualDisplay2.offset).isEqualTo(0f) + assertThat(actualDisplay2.children).hasSize(1) + + val actualDisplay3 = actualDisplay2.children[0] + assertThat(actualDisplay3.displayId).isEqualTo(3) + assertThat(actualDisplay3.width).isEqualTo(600f) + assertThat(actualDisplay3.height).isEqualTo(200f) + assertThat(actualDisplay3.position).isEqualTo(POSITION_RIGHT) + assertThat(actualDisplay3.offset).isEqualTo(400f) + assertThat(actualDisplay3.children).hasSize(1) + + val actualDisplay4 = actualDisplay3.children[0] + assertThat(actualDisplay4.displayId).isEqualTo(4) + assertThat(actualDisplay4.width).isEqualTo(200f) + assertThat(actualDisplay4.height).isEqualTo(600f) + assertThat(actualDisplay4.position).isEqualTo(POSITION_RIGHT) + assertThat(actualDisplay4.offset).isEqualTo(-400f) + assertThat(actualDisplay4.children).isEmpty() + } +} \ No newline at end of file diff --git a/core/tests/coretests/src/android/os/PowerManagerTest.java b/core/tests/coretests/src/android/os/PowerManagerTest.java index 3b27fc06352ef44b352539be88f14575c4704dfb..e4e965f1cadbe9bf29d16f010e1b3971a496a4b0 100644 --- a/core/tests/coretests/src/android/os/PowerManagerTest.java +++ b/core/tests/coretests/src/android/os/PowerManagerTest.java @@ -21,6 +21,8 @@ import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertNotNull; import static org.junit.Assert.assertTrue; import static org.junit.Assert.fail; +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.ArgumentMatchers.anyInt; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.reset; import static org.mockito.Mockito.timeout; @@ -61,9 +63,13 @@ public class PowerManagerTest { private UiDevice mUiDevice; private Executor mExec = Executors.newSingleThreadExecutor(); @Mock - private PowerManager.OnThermalStatusChangedListener mListener1; + private PowerManager.OnThermalStatusChangedListener mStatusListener1; @Mock - private PowerManager.OnThermalStatusChangedListener mListener2; + private PowerManager.OnThermalStatusChangedListener mStatusListener2; + @Mock + private PowerManager.OnThermalHeadroomChangedListener mHeadroomListener1; + @Mock + private PowerManager.OnThermalHeadroomChangedListener mHeadroomListener2; private static final long CALLBACK_TIMEOUT_MILLI_SEC = 5000; private native Parcel nativeObtainPowerSaveStateParcel(boolean batterySaverEnabled, boolean globalBatterySaverEnabled, int locationMode, int soundTriggerMode, @@ -245,53 +251,90 @@ public class PowerManagerTest { // Initial override status is THERMAL_STATUS_NONE int status = PowerManager.THERMAL_STATUS_NONE; // Add listener1 - mPm.addThermalStatusListener(mExec, mListener1); - verify(mListener1, timeout(CALLBACK_TIMEOUT_MILLI_SEC) + mPm.addThermalStatusListener(mExec, mStatusListener1); + verify(mStatusListener1, timeout(CALLBACK_TIMEOUT_MILLI_SEC) .times(1)).onThermalStatusChanged(status); - reset(mListener1); + reset(mStatusListener1); status = PowerManager.THERMAL_STATUS_SEVERE; mUiDevice.executeShellCommand("cmd thermalservice override-status " + Integer.toString(status)); - verify(mListener1, timeout(CALLBACK_TIMEOUT_MILLI_SEC) + verify(mStatusListener1, timeout(CALLBACK_TIMEOUT_MILLI_SEC) .times(1)).onThermalStatusChanged(status); - reset(mListener1); + reset(mStatusListener1); // Add listener1 again try { - mPm.addThermalStatusListener(mListener1); + mPm.addThermalStatusListener(mStatusListener1); fail("Expected exception not thrown"); } catch (IllegalArgumentException expectedException) { } // Add listener2 on main thread. - mPm.addThermalStatusListener(mListener2); - verify(mListener2, timeout(CALLBACK_TIMEOUT_MILLI_SEC) + mPm.addThermalStatusListener(mStatusListener2); + verify(mStatusListener2, timeout(CALLBACK_TIMEOUT_MILLI_SEC) .times(1)).onThermalStatusChanged(status); - reset(mListener2); + reset(mStatusListener2); status = PowerManager.THERMAL_STATUS_MODERATE; mUiDevice.executeShellCommand("cmd thermalservice override-status " + Integer.toString(status)); - verify(mListener1, timeout(CALLBACK_TIMEOUT_MILLI_SEC) + verify(mStatusListener1, timeout(CALLBACK_TIMEOUT_MILLI_SEC) .times(1)).onThermalStatusChanged(status); - verify(mListener2, timeout(CALLBACK_TIMEOUT_MILLI_SEC) + verify(mStatusListener2, timeout(CALLBACK_TIMEOUT_MILLI_SEC) .times(1)).onThermalStatusChanged(status); - reset(mListener1); - reset(mListener2); + reset(mStatusListener1); + reset(mStatusListener2); // Remove listener1 - mPm.removeThermalStatusListener(mListener1); + mPm.removeThermalStatusListener(mStatusListener1); // Remove listener1 again try { - mPm.removeThermalStatusListener(mListener1); + mPm.removeThermalStatusListener(mStatusListener1); fail("Expected exception not thrown"); } catch (IllegalArgumentException expectedException) { } status = PowerManager.THERMAL_STATUS_LIGHT; mUiDevice.executeShellCommand("cmd thermalservice override-status " + Integer.toString(status)); - verify(mListener1, timeout(CALLBACK_TIMEOUT_MILLI_SEC) + verify(mStatusListener1, timeout(CALLBACK_TIMEOUT_MILLI_SEC) .times(0)).onThermalStatusChanged(status); - verify(mListener2, timeout(CALLBACK_TIMEOUT_MILLI_SEC) + verify(mStatusListener2, timeout(CALLBACK_TIMEOUT_MILLI_SEC) .times(1)).onThermalStatusChanged(status); } + /** + * Confirm that we can add/remove thermal headroom listener. + */ + @Test + @RequiresFlagsEnabled(Flags.FLAG_ALLOW_THERMAL_THRESHOLDS_CALLBACK) + public void testThermalHeadroomCallback() throws Exception { + float headroom = mPm.getThermalHeadroom(0); + // If the device doesn't support thermal headroom, return early + if (Float.isNaN(headroom)) { + return; + } + // Add listener1 + mPm.addThermalHeadroomListener(mExec, mHeadroomListener1); + verify(mHeadroomListener1, timeout(CALLBACK_TIMEOUT_MILLI_SEC) + .times(1)).onThermalHeadroomChanged(anyInt(), anyInt(), anyInt(), any()); + reset(mHeadroomListener1); + // Add listener1 again + try { + mPm.addThermalHeadroomListener(mHeadroomListener1); + fail("Expected exception not thrown"); + } catch (IllegalArgumentException expectedException) { + } + // Add listener2 on main thread. + mPm.addThermalHeadroomListener(mHeadroomListener2); + verify(mHeadroomListener2, timeout(CALLBACK_TIMEOUT_MILLI_SEC) + .times(1)).onThermalHeadroomChanged(anyInt(), anyInt(), anyInt(), any()); + reset(mHeadroomListener2); + // Remove listener1 + mPm.removeThermalHeadroomListener(mHeadroomListener1); + // Remove listener1 again + try { + mPm.removeThermalHeadroomListener(mHeadroomListener1); + fail("Expected exception not thrown"); + } catch (IllegalArgumentException expectedException) { + } + } + @Test public void testGetThermalHeadroom() throws Exception { float headroom = mPm.getThermalHeadroom(0); diff --git a/core/tests/coretests/src/android/view/DisplayInfoTest.java b/core/tests/coretests/src/android/view/DisplayInfoTest.java index 4c5b7e508e344eb008814ae87b8c66a2ec2823ab..8932cf1ba552721456677cb7aa0b93e1d8abe1d4 100644 --- a/core/tests/coretests/src/android/view/DisplayInfoTest.java +++ b/core/tests/coretests/src/android/view/DisplayInfoTest.java @@ -77,6 +77,23 @@ public class DisplayInfoTest { assertTrue(displayInfo1.equals(displayInfo2)); } + @Test + public void testRefreshRateOverride_keepsDisplyInfosEqualWhenOverrideIsSame() { + Display.Mode mode = new Display.Mode( + /*modeId=*/1, /*width=*/1000, /*height=*/1000, /*refreshRate=*/120); + DisplayInfo displayInfo1 = new DisplayInfo(); + setSupportedMode(displayInfo1, mode); + displayInfo1.renderFrameRate = 60; + displayInfo1.refreshRateOverride = 30; + + DisplayInfo displayInfo2 = new DisplayInfo(); + setSupportedMode(displayInfo2, mode); + displayInfo2.renderFrameRate = 30; + displayInfo2.refreshRateOverride = 30; + + assertTrue(displayInfo1.equals(displayInfo2)); + } + @Test public void testRefreshRateOverride_makeDisplayInfosDifferent() { Display.Mode mode = new Display.Mode( diff --git a/core/tests/coretests/src/android/view/ImeBackAnimationControllerTest.java b/core/tests/coretests/src/android/view/ImeBackAnimationControllerTest.java index 00ffda867d6aba9c544766e6bd380da173a1f6b8..a47a3e0e6c2a75ad4e168727f8a8a7a93660c033 100644 --- a/core/tests/coretests/src/android/view/ImeBackAnimationControllerTest.java +++ b/core/tests/coretests/src/android/view/ImeBackAnimationControllerTest.java @@ -161,7 +161,7 @@ public class ImeBackAnimationControllerTest { mBackAnimationController.onBackInvoked(); // verify that InputMethodManager#notifyImeHidden is called (which is the case whenever // getInputMethodManager is called from ImeBackAnimationController) - verify(mViewRootInsetsControllerHost, times(1)).getInputMethodManager(); + verify(mViewRootInsetsControllerHost, times(2)).getInputMethodManager(); // verify that ImeBackAnimationController does not take control over IME insets verify(mInsetsController, never()).controlWindowInsetsAnimation(anyInt(), any(), any(), anyBoolean(), anyLong(), any(), anyInt(), anyBoolean()); @@ -180,7 +180,7 @@ public class ImeBackAnimationControllerTest { mBackAnimationController.onBackInvoked(); // verify that InputMethodManager#notifyImeHidden is called (which is the case whenever // getInputMethodManager is called from ImeBackAnimationController) - verify(mViewRootInsetsControllerHost, times(1)).getInputMethodManager(); + verify(mViewRootInsetsControllerHost, times(2)).getInputMethodManager(); // verify that ImeBackAnimationController does not take control over IME insets verify(mInsetsController, never()).controlWindowInsetsAnimation(anyInt(), any(), any(), anyBoolean(), anyLong(), any(), anyInt(), anyBoolean()); @@ -300,7 +300,7 @@ public class ImeBackAnimationControllerTest { mBackAnimationController.onBackInvoked(); // verify that InputMethodManager#notifyImeHidden is called (which is the case whenever // getInputMethodManager is called from ImeBackAnimationController) - verify(mViewRootInsetsControllerHost, times(1)).getInputMethodManager(); + verify(mViewRootInsetsControllerHost, times(2)).getInputMethodManager(); }); } diff --git a/core/tests/coretests/src/android/view/RoundScrollbarRendererTest.java b/core/tests/coretests/src/android/view/RoundScrollbarRendererTest.java index 262bd5cd6c01bc8d524428d54d05a83950144ae8..0f17f9cdddc8c270a7a0d4df618874a2fc8d3426 100644 --- a/core/tests/coretests/src/android/view/RoundScrollbarRendererTest.java +++ b/core/tests/coretests/src/android/view/RoundScrollbarRendererTest.java @@ -16,7 +16,11 @@ package android.view; +import static android.view.RoundScrollbarRenderer.BLUECHIP_ENABLED_SYSPROP; + import static org.junit.Assert.assertEquals; +import static org.junit.Assume.assumeFalse; +import static org.junit.Assume.assumeTrue; import static org.mockito.ArgumentMatchers.any; import static org.mockito.ArgumentMatchers.anyFloat; import static org.mockito.ArgumentMatchers.anyInt; @@ -30,11 +34,8 @@ import android.content.Context; import android.graphics.Canvas; import android.graphics.Paint; import android.graphics.Rect; +import android.os.SystemProperties; import android.platform.test.annotations.Presubmit; -import android.platform.test.annotations.RequiresFlagsDisabled; -import android.platform.test.annotations.RequiresFlagsEnabled; -import android.platform.test.flag.junit.CheckFlagsRule; -import android.platform.test.flag.junit.DeviceFlagsValueProvider; import android.view.flags.Flags; import androidx.test.core.app.ApplicationProvider; @@ -42,7 +43,6 @@ import androidx.test.ext.junit.runners.AndroidJUnit4; import androidx.test.filters.SmallTest; import org.junit.Before; -import org.junit.Rule; import org.junit.Test; import org.junit.runner.RunWith; import org.mockito.ArgumentCaptor; @@ -66,9 +66,6 @@ public class RoundScrollbarRendererTest { private static final float DEFAULT_ALPHA = 0.5f; private static final Rect BOUNDS = new Rect(0, 0, 200, 200); - @Rule - public final CheckFlagsRule mCheckFlagsRule = DeviceFlagsValueProvider.createCheckFlagsRule(); - @Mock private Canvas mCanvas; @Captor private ArgumentCaptor mPaintCaptor; private RoundScrollbarRenderer mScrollbar; @@ -88,8 +85,8 @@ public class RoundScrollbarRendererTest { } @Test - @RequiresFlagsDisabled(Flags.FLAG_USE_REFACTORED_ROUND_SCROLLBAR) public void testScrollbarDrawn_legacy() { + assumeFalse(usingRefactoredScrollbar()); mScrollbar.drawRoundScrollbars(mCanvas, DEFAULT_ALPHA, BOUNDS, /* drawToLeft= */ false); // The arc will be drawn twice, i.e. once for track and once for thumb @@ -105,8 +102,8 @@ public class RoundScrollbarRendererTest { } @Test - @RequiresFlagsEnabled(Flags.FLAG_USE_REFACTORED_ROUND_SCROLLBAR) public void testScrollbarDrawn() { + assumeTrue(usingRefactoredScrollbar()); mScrollbar.drawRoundScrollbars(mCanvas, DEFAULT_ALPHA, BOUNDS, /* drawToLeft= */ false); // The arc will be drawn thrice, i.e. twice for track and once for thumb @@ -143,4 +140,9 @@ public class RoundScrollbarRendererTest { return super.computeVerticalScrollExtent(); } } + + private static boolean usingRefactoredScrollbar() { + return Flags.useRefactoredRoundScrollbar() + && SystemProperties.getBoolean(BLUECHIP_ENABLED_SYSPROP, false); + } } diff --git a/core/tests/coretests/src/com/android/internal/accessibility/util/ShortcutUtilsTest.java b/core/tests/coretests/src/com/android/internal/accessibility/util/ShortcutUtilsTest.java index 8bebc62e93f2a949faaa7eca4415de2dab3873a5..1a9af6b55eedb17cccc24a4a9e7380f2ed55df61 100644 --- a/core/tests/coretests/src/com/android/internal/accessibility/util/ShortcutUtilsTest.java +++ b/core/tests/coretests/src/com/android/internal/accessibility/util/ShortcutUtilsTest.java @@ -21,6 +21,7 @@ import static android.provider.Settings.Secure.ACCESSIBILITY_SHORTCUT_TARGET_MAG import static com.android.internal.accessibility.common.ShortcutConstants.SERVICES_SEPARATOR; import static com.android.internal.accessibility.common.ShortcutConstants.UserShortcutType.GESTURE; +import static com.android.internal.accessibility.common.ShortcutConstants.UserShortcutType.KEY_GESTURE; import static com.android.internal.accessibility.common.ShortcutConstants.UserShortcutType.SOFTWARE; import static com.google.common.truth.Truth.assertThat; @@ -122,6 +123,14 @@ public class ShortcutUtilsTest { ).isEmpty(); } + @Test + public void getShortcutTargets_keyGestureShortcutNoService_emptyResult() { + assertThat( + ShortcutUtils.getShortcutTargetsFromSettings( + mContext, KEY_GESTURE, mDefaultUserId) + ).isEmpty(); + } + @Test public void getShortcutTargets_softwareShortcut1Service_return1Service() { setupShortcutTargets(ONE_COMPONENT, Settings.Secure.ACCESSIBILITY_BUTTON_TARGETS); diff --git a/core/tests/coretests/src/com/android/internal/os/KernelSingleUidTimeReaderTest.java b/core/tests/coretests/src/com/android/internal/os/KernelSingleUidTimeReaderTest.java index 120a4de54427fce4e7fe5111a5092ad21ce93dac..3239598eccdc92b8723ed5b56f59de4d994be631 100644 --- a/core/tests/coretests/src/com/android/internal/os/KernelSingleUidTimeReaderTest.java +++ b/core/tests/coretests/src/com/android/internal/os/KernelSingleUidTimeReaderTest.java @@ -301,18 +301,14 @@ public class KernelSingleUidTimeReaderTest { {1_000_000, 2_000_000, 3_000_000}, {4_000_000, 5_000_000}}); - LongArrayMultiStateCounter.LongArrayContainer array = - new LongArrayMultiStateCounter.LongArrayContainer(5); + long[] out = new long[5]; - success = mInjector.addDelta(TEST_UID, counter, 2000, array); + success = mInjector.addDelta(TEST_UID, counter, 2000, out); assertThat(success).isTrue(); - - array.getValues(out); assertThat(out).isEqualTo(new long[]{1, 2, 3, 4, 5}); - counter.getCounts(array, 0); - array.getValues(out); + counter.getCounts(out, 0); assertThat(out).isEqualTo(new long[]{1, 2, 3, 4, 5}); counter.setState(1, 3000); @@ -322,18 +318,14 @@ public class KernelSingleUidTimeReaderTest { {11_000_000, 22_000_000, 33_000_000}, {44_000_000, 55_000_000}}); - success = mInjector.addDelta(TEST_UID, counter, 4000, array); + success = mInjector.addDelta(TEST_UID, counter, 4000, out); assertThat(success).isTrue(); - - array.getValues(out); assertThat(out).isEqualTo(new long[]{10, 20, 30, 40, 50}); - counter.getCounts(array, 0); - array.getValues(out); + counter.getCounts(out, 0); assertThat(out).isEqualTo(new long[]{1 + 5, 2 + 10, 3 + 15, 4 + 20, 5 + 25}); - counter.getCounts(array, 1); - array.getValues(out); + counter.getCounts(out, 1); assertThat(out).isEqualTo(new long[]{5, 10, 15, 20, 25}); } @@ -385,7 +377,7 @@ public class KernelSingleUidTimeReaderTest { @Override public boolean addDelta(int uid, LongArrayMultiStateCounter counter, long timestampMs, - LongArrayMultiStateCounter.LongArrayContainer deltaOut) { + long[] deltaOut) { return addDeltaForTest(uid, counter, timestampMs, mCpuTimeInStatePerClusterNs, deltaOut); } diff --git a/core/tests/coretests/src/com/android/internal/os/LongArrayMultiStateCounterTest.java b/core/tests/coretests/src/com/android/internal/os/LongArrayMultiStateCounterTest.java index b86dc5807b22c31e73bf5a0f5a4d3d7548883f7c..7e5d0a4c2e42bb2a5c7dd9d1449e08ad7ac9ded7 100644 --- a/core/tests/coretests/src/com/android/internal/os/LongArrayMultiStateCounterTest.java +++ b/core/tests/coretests/src/com/android/internal/os/LongArrayMultiStateCounterTest.java @@ -24,14 +24,11 @@ import android.os.BadParcelableException; import android.os.Parcel; import android.platform.test.ravenwood.RavenwoodRule; -import androidx.test.ext.junit.runners.AndroidJUnit4; import androidx.test.filters.SmallTest; import org.junit.Rule; import org.junit.Test; -import org.junit.runner.RunWith; -@RunWith(AndroidJUnit4.class) @SmallTest public class LongArrayMultiStateCounterTest { @Rule @@ -41,11 +38,11 @@ public class LongArrayMultiStateCounterTest { public void setStateAndUpdateValue() { LongArrayMultiStateCounter counter = new LongArrayMultiStateCounter(2, 4); - updateValue(counter, new long[]{0, 0, 0, 0}, 1000); + counter.updateValues(new long[]{0, 0, 0, 0}, 1000); counter.setState(0, 1000); counter.setState(1, 2000); counter.setState(0, 4000); - updateValue(counter, new long[]{100, 200, 300, 400}, 9000); + counter.updateValues(new long[]{100, 200, 300, 400}, 9000); assertCounts(counter, 0, new long[]{75, 150, 225, 300}); assertCounts(counter, 1, new long[]{25, 50, 75, 100}); @@ -54,16 +51,29 @@ public class LongArrayMultiStateCounterTest { "[0: {75, 150, 225, 300}, 1: {25, 50, 75, 100}] updated: 9000 currentState: 0"); } + @Test + public void increment() { + LongArrayMultiStateCounter counter = new LongArrayMultiStateCounter(2, 4); + + counter.updateValues(new long[]{0, 0, 0, 0}, 1000); + counter.setState(0, 1000); + counter.incrementValues(new long[]{1, 2, 3, 4}, 2000); + counter.incrementValues(new long[]{100, 200, 300, 400}, 3000); + + assertCounts(counter, 0, new long[]{101, 202, 303, 404}); + assertCounts(counter, 1, new long[]{0, 0, 0, 0}); + } + @Test public void copyStatesFrom() { LongArrayMultiStateCounter source = new LongArrayMultiStateCounter(2, 1); - updateValue(source, new long[]{0}, 1000); + source.updateValues(new long[]{0}, 1000); source.setState(0, 1000); source.setState(1, 2000); LongArrayMultiStateCounter target = new LongArrayMultiStateCounter(2, 1); target.copyStatesFrom(source); - updateValue(target, new long[]{1000}, 5000); + target.updateValues(new long[]{1000}, 5000); assertCounts(target, 0, new long[]{250}); assertCounts(target, 1, new long[]{750}); @@ -83,25 +93,25 @@ public class LongArrayMultiStateCounterTest { public void setEnabled() { LongArrayMultiStateCounter counter = new LongArrayMultiStateCounter(2, 4); counter.setState(0, 1000); - updateValue(counter, new long[]{0, 0, 0, 0}, 1000); - updateValue(counter, new long[]{100, 200, 300, 400}, 2000); + counter.updateValues(new long[]{0, 0, 0, 0}, 1000); + counter.updateValues(new long[]{100, 200, 300, 400}, 2000); assertCounts(counter, 0, new long[]{100, 200, 300, 400}); counter.setEnabled(false, 3000); // Partially included, because the counter is disabled after the previous update - updateValue(counter, new long[]{200, 300, 400, 500}, 4000); + counter.updateValues(new long[]{200, 300, 400, 500}, 4000); // Count only 50%, because the counter was disabled for 50% of the time assertCounts(counter, 0, new long[]{150, 250, 350, 450}); // Not counted because the counter is disabled - updateValue(counter, new long[]{250, 350, 450, 550}, 5000); + counter.updateValues(new long[]{250, 350, 450, 550}, 5000); counter.setEnabled(true, 6000); - updateValue(counter, new long[]{300, 400, 500, 600}, 7000); + counter.updateValues(new long[]{300, 400, 500, 600}, 7000); // Again, take 50% of the delta assertCounts(counter, 0, new long[]{175, 275, 375, 475}); @@ -111,8 +121,8 @@ public class LongArrayMultiStateCounterTest { public void reset() { LongArrayMultiStateCounter counter = new LongArrayMultiStateCounter(2, 4); counter.setState(0, 1000); - updateValue(counter, new long[]{0, 0, 0, 0}, 1000); - updateValue(counter, new long[]{100, 200, 300, 400}, 2000); + counter.updateValues(new long[]{0, 0, 0, 0}, 1000); + counter.updateValues(new long[]{100, 200, 300, 400}, 2000); assertCounts(counter, 0, new long[]{100, 200, 300, 400}); @@ -120,8 +130,8 @@ public class LongArrayMultiStateCounterTest { assertCounts(counter, 0, new long[]{0, 0, 0, 0}); - updateValue(counter, new long[]{200, 300, 400, 500}, 3000); - updateValue(counter, new long[]{300, 400, 500, 600}, 4000); + counter.updateValues(new long[]{200, 300, 400, 500}, 3000); + counter.updateValues(new long[]{300, 400, 500, 600}, 4000); assertCounts(counter, 0, new long[]{100, 100, 100, 100}); } @@ -129,11 +139,11 @@ public class LongArrayMultiStateCounterTest { @Test public void parceling() { LongArrayMultiStateCounter counter = new LongArrayMultiStateCounter(2, 4); - updateValue(counter, new long[]{0, 0, 0, 0}, 1000); + counter.updateValues(new long[]{0, 0, 0, 0}, 1000); counter.setState(0, 1000); - updateValue(counter, new long[]{100, 200, 300, 400}, 2000); + counter.updateValues(new long[]{100, 200, 300, 400}, 2000); counter.setState(1, 2000); - updateValue(counter, new long[]{101, 202, 304, 408}, 3000); + counter.updateValues(new long[]{101, 202, 304, 408}, 3000); assertCounts(counter, 0, new long[]{100, 200, 300, 400}); assertCounts(counter, 1, new long[]{1, 2, 4, 8}); @@ -158,27 +168,17 @@ public class LongArrayMultiStateCounterTest { // State, last update timestamp and current counts are undefined at this point. newCounter.setState(0, 100); - updateValue(newCounter, new long[]{300, 400, 500, 600}, 100); + newCounter.updateValues(new long[]{300, 400, 500, 600}, 100); // A new base state and counters are established; we can continue accumulating deltas - updateValue(newCounter, new long[]{316, 432, 564, 728}, 200); + newCounter.updateValues(new long[]{316, 432, 564, 728}, 200); assertCounts(newCounter, 0, new long[]{116, 232, 364, 528}); } - private void updateValue(LongArrayMultiStateCounter counter, long[] values, int timestamp) { - LongArrayMultiStateCounter.LongArrayContainer container = - new LongArrayMultiStateCounter.LongArrayContainer(values.length); - container.setValues(values); - counter.updateValues(container, timestamp); - } - private void assertCounts(LongArrayMultiStateCounter counter, int state, long[] expected) { - LongArrayMultiStateCounter.LongArrayContainer container = - new LongArrayMultiStateCounter.LongArrayContainer(expected.length); long[] counts = new long[expected.length]; - counter.getCounts(container, state); - container.getValues(counts); + counter.getCounts(counts, state); assertThat(counts).isEqualTo(expected); } @@ -230,33 +230,4 @@ public class LongArrayMultiStateCounterTest { parcel.writeInt(endPos - startPos); parcel.setDataPosition(endPos); } - - @Test - public void combineValues() { - long[] values = new long[] {0, 1, 2, 3, 42}; - LongArrayMultiStateCounter.LongArrayContainer container = - new LongArrayMultiStateCounter.LongArrayContainer(values.length); - container.setValues(values); - - long[] out = new long[3]; - int[] indexes = {2, 1, 1, 0, 0}; - boolean nonZero = container.combineValues(out, indexes); - assertThat(nonZero).isTrue(); - assertThat(out).isEqualTo(new long[]{45, 3, 0}); - - // All zeros - container.setValues(new long[]{0, 0, 0, 0, 0}); - nonZero = container.combineValues(out, indexes); - assertThat(nonZero).isFalse(); - assertThat(out).isEqualTo(new long[]{0, 0, 0}); - - // Index out of range - IndexOutOfBoundsException e1 = assertThrows( - IndexOutOfBoundsException.class, - () -> container.combineValues(out, new int[]{0, 1, -1, 0, 0})); - assertThat(e1.getMessage()).isEqualTo("Index -1 is out of bounds: [0, 2]"); - IndexOutOfBoundsException e2 = assertThrows(IndexOutOfBoundsException.class, - () -> container.combineValues(out, new int[]{0, 1, 4, 0, 0})); - assertThat(e2.getMessage()).isEqualTo("Index 4 is out of bounds: [0, 2]"); - } } diff --git a/core/tests/vibrator/src/android/os/VibratorTest.java b/core/tests/vibrator/src/android/os/VibratorTest.java index 6210a00a594046bd49d2815261dd36ee095bd029..09bfadbf56a4b3936892dd9dcb480d20982af70a 100644 --- a/core/tests/vibrator/src/android/os/VibratorTest.java +++ b/core/tests/vibrator/src/android/os/VibratorTest.java @@ -110,8 +110,9 @@ public class VibratorTest { @Test public void onVibratorStateChanged_noVibrator_registersNoListenerToVibratorManager() { + int[] vibratorIds = new int[0]; VibratorManager mockVibratorManager = mock(VibratorManager.class); - when(mockVibratorManager.getVibratorIds()).thenReturn(new int[0]); + when(mockVibratorManager.getVibratorIds()).thenReturn(vibratorIds); Vibrator.OnVibratorStateChangedListener mockListener = mock(Vibrator.OnVibratorStateChangedListener.class); @@ -119,7 +120,7 @@ public class VibratorTest { new SystemVibrator.MultiVibratorStateListener( mTestLooper.getNewExecutor(), mockListener); - multiVibratorListener.register(mockVibratorManager); + multiVibratorListener.register(mockVibratorManager, vibratorIds); // Never tries to register a listener to an individual vibrator. assertFalse(multiVibratorListener.hasRegisteredListeners()); @@ -128,8 +129,9 @@ public class VibratorTest { @Test public void onVibratorStateChanged_singleVibrator_forwardsAllCallbacks() { + int[] vibratorIds = new int[] { 1 }; VibratorManager mockVibratorManager = mock(VibratorManager.class); - when(mockVibratorManager.getVibratorIds()).thenReturn(new int[] { 1 }); + when(mockVibratorManager.getVibratorIds()).thenReturn(vibratorIds); when(mockVibratorManager.getVibrator(anyInt())).thenReturn(NullVibrator.getInstance()); Vibrator.OnVibratorStateChangedListener mockListener = @@ -138,7 +140,7 @@ public class VibratorTest { new SystemVibrator.MultiVibratorStateListener( mTestLooper.getNewExecutor(), mockListener); - multiVibratorListener.register(mockVibratorManager); + multiVibratorListener.register(mockVibratorManager, vibratorIds); assertTrue(multiVibratorListener.hasRegisteredListeners()); multiVibratorListener.onVibrating(/* vibratorIdx= */ 0, /* vibrating= */ false); @@ -156,8 +158,9 @@ public class VibratorTest { @Test public void onVibratorStateChanged_multipleVibrators_triggersOnlyWhenAllVibratorsInitialized() { + int[] vibratorIds = new int[] { 1, 2 }; VibratorManager mockVibratorManager = mock(VibratorManager.class); - when(mockVibratorManager.getVibratorIds()).thenReturn(new int[] { 1, 2 }); + when(mockVibratorManager.getVibratorIds()).thenReturn(vibratorIds); when(mockVibratorManager.getVibrator(anyInt())).thenReturn(NullVibrator.getInstance()); Vibrator.OnVibratorStateChangedListener mockListener = @@ -166,7 +169,7 @@ public class VibratorTest { new SystemVibrator.MultiVibratorStateListener( mTestLooper.getNewExecutor(), mockListener); - multiVibratorListener.register(mockVibratorManager); + multiVibratorListener.register(mockVibratorManager, vibratorIds); assertTrue(multiVibratorListener.hasRegisteredListeners()); multiVibratorListener.onVibrating(/* vibratorIdx= */ 0, /* vibrating= */ false); @@ -181,8 +184,9 @@ public class VibratorTest { @Test public void onVibratorStateChanged_multipleVibrators_stateChangeIsDeduped() { + int[] vibratorIds = new int[] { 1, 2 }; VibratorManager mockVibratorManager = mock(VibratorManager.class); - when(mockVibratorManager.getVibratorIds()).thenReturn(new int[] { 1, 2 }); + when(mockVibratorManager.getVibratorIds()).thenReturn(vibratorIds); when(mockVibratorManager.getVibrator(anyInt())).thenReturn(NullVibrator.getInstance()); Vibrator.OnVibratorStateChangedListener mockListener = @@ -191,7 +195,7 @@ public class VibratorTest { new SystemVibrator.MultiVibratorStateListener( mTestLooper.getNewExecutor(), mockListener); - multiVibratorListener.register(mockVibratorManager); + multiVibratorListener.register(mockVibratorManager, vibratorIds); assertTrue(multiVibratorListener.hasRegisteredListeners()); multiVibratorListener.onVibrating(/* vibratorIdx= */ 0, /* vibrating= */ false); // none diff --git a/data/etc/platform.xml b/data/etc/platform.xml index 7b96699f7f71553d6035b497d19192e754209804..857df1038df1cb0f6ed9e4c8f5ee3e7b4a715a18 100644 --- a/data/etc/platform.xml +++ b/data/etc/platform.xml @@ -213,6 +213,8 @@ + + diff --git a/data/etc/privapp-permissions-platform.xml b/data/etc/privapp-permissions-platform.xml index 56e55df3f27c4056cdc89746e95cdc8a977c57d6..541ca602a386f343ed7a0365d4dc8012f1d58247 100644 --- a/data/etc/privapp-permissions-platform.xml +++ b/data/etc/privapp-permissions-platform.xml @@ -402,6 +402,9 @@ applications that come with the platform + + + @@ -591,6 +594,9 @@ applications that come with the platform + + + diff --git a/data/keyboards/Generic.kl b/data/keyboards/Generic.kl index f8d3bffbe00b004802bf642326c8728503a67116..2b0802b54c140d8f3879c04b3da3f332000814b6 100644 --- a/data/keyboards/Generic.kl +++ b/data/keyboards/Generic.kl @@ -171,7 +171,7 @@ key 143 WAKEUP # key 149 "KEY_PROG2" key 150 EXPLORER # key 151 "KEY_MSDOS" -key 152 POWER +key 152 LOCK # key 153 "KEY_DIRECTION" # key 154 "KEY_CYCLEWINDOWS" key 155 ENVELOPE @@ -200,20 +200,20 @@ key 177 PAGE_UP key 178 PAGE_DOWN key 179 NUMPAD_LEFT_PAREN key 180 NUMPAD_RIGHT_PAREN -# key 181 "KEY_NEW" +key 181 NEW # key 182 "KEY_REDO" -# key 183 F13 -# key 184 F14 -# key 185 F15 -# key 186 F16 -# key 187 F17 -# key 188 F18 -# key 189 F19 -# key 190 F20 -# key 191 F21 -# key 192 F22 -# key 193 F23 -# key 194 F24 +key 183 F13 +key 184 F14 +key 185 F15 +key 186 F16 +key 187 F17 +key 188 F18 +key 189 F19 +key 190 F20 +key 191 F21 +key 192 F22 +key 193 F23 +key 194 F24 # key 195 (undefined) # key 196 (undefined) # key 197 (undefined) @@ -225,11 +225,11 @@ key 201 MEDIA_PAUSE # key 203 "KEY_PROG4" key 204 NOTIFICATION # key 205 "KEY_SUSPEND" -# key 206 "KEY_CLOSE" +key 206 CLOSE key 207 MEDIA_PLAY key 208 MEDIA_FAST_FORWARD # key 209 "KEY_BASSBOOST" -# key 210 "KEY_PRINT" +key 210 PRINT # key 211 "KEY_HP" key 212 CAMERA key 213 MUSIC @@ -328,7 +328,7 @@ key 368 LANGUAGE_SWITCH # key 369 "KEY_TITLE" key 370 CAPTIONS # key 371 "KEY_ANGLE" -# key 372 "KEY_ZOOM" +key 372 FULLSCREEN # key 373 "KEY_MODE" # key 374 "KEY_KEYBOARD" # key 375 "KEY_SCREEN" @@ -425,12 +425,15 @@ key 582 VOICE_ASSIST # Linux KEY_ASSISTANT key 583 ASSIST key 585 EMOJI_PICKER +key 586 DICTATE key 656 MACRO_1 key 657 MACRO_2 key 658 MACRO_3 key 659 MACRO_4 # Keys defined by HID usages +key usage 0x010082 LOCK FALLBACK_USAGE_MAPPING +key usage 0x01009B DO_NOT_DISTURB FALLBACK_USAGE_MAPPING key usage 0x0c0065 SCREENSHOT FALLBACK_USAGE_MAPPING key usage 0x0c0067 WINDOW FALLBACK_USAGE_MAPPING key usage 0x0c006F BRIGHTNESS_UP FALLBACK_USAGE_MAPPING @@ -438,12 +441,17 @@ key usage 0x0c0070 BRIGHTNESS_DOWN FALLBACK_USAGE_MAPPING key usage 0x0c0079 KEYBOARD_BACKLIGHT_UP FALLBACK_USAGE_MAPPING key usage 0x0c007A KEYBOARD_BACKLIGHT_DOWN FALLBACK_USAGE_MAPPING key usage 0x0c007C KEYBOARD_BACKLIGHT_TOGGLE FALLBACK_USAGE_MAPPING +key usage 0x0c00D8 DICTATE FALLBACK_USAGE_MAPPING key usage 0x0c00D9 EMOJI_PICKER FALLBACK_USAGE_MAPPING key usage 0x0c0173 MEDIA_AUDIO_TRACK FALLBACK_USAGE_MAPPING key usage 0x0c019C PROFILE_SWITCH FALLBACK_USAGE_MAPPING key usage 0x0c019F SETTINGS FALLBACK_USAGE_MAPPING key usage 0x0c01A2 ALL_APPS FALLBACK_USAGE_MAPPING +key usage 0x0c0201 NEW FALLBACK_USAGE_MAPPING +key usage 0x0c0203 CLOSE FALLBACK_USAGE_MAPPING +key usage 0x0c0208 PRINT FALLBACK_USAGE_MAPPING key usage 0x0c0227 REFRESH FALLBACK_USAGE_MAPPING +key usage 0x0c0232 FULLSCREEN FALLBACK_USAGE_MAPPING key usage 0x0c029D LANGUAGE_SWITCH FALLBACK_USAGE_MAPPING key usage 0x0c029F RECENT_APPS FALLBACK_USAGE_MAPPING key usage 0x0c02A2 ALL_APPS FALLBACK_USAGE_MAPPING diff --git a/graphics/java/android/graphics/ColorSpace.java b/graphics/java/android/graphics/ColorSpace.java index 4c47de0ca754483f8851175782bb369f8f6ab7ec..d55a71e2193192d303af73a3311f3a1afc1296e7 100644 --- a/graphics/java/android/graphics/ColorSpace.java +++ b/graphics/java/android/graphics/ColorSpace.java @@ -1761,7 +1761,7 @@ public abstract class ColorSpace { if (Flags.displayBt2020Colorspace()) { sNamedColorSpaceMap.put(Named.DISPLAY_BT2020.ordinal(), new ColorSpace.Rgb( - "BT 2020", + "Display BT. 2020", BT2020_PRIMARIES, ILLUMINANT_D65, null, diff --git a/graphics/java/android/graphics/ImageFormat.java b/graphics/java/android/graphics/ImageFormat.java index 93d94c9cd7ebf0bbef145bd2d172b1dc2cbeba94..b4899f975f43f2a608715a3cad2d5c35b6798389 100644 --- a/graphics/java/android/graphics/ImageFormat.java +++ b/graphics/java/android/graphics/ImageFormat.java @@ -19,6 +19,8 @@ package android.graphics; import android.annotation.FlaggedApi; import android.annotation.IntDef; +import com.android.internal.camera.flags.Flags; + import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; @@ -63,6 +65,7 @@ public class ImageFormat { RAW_DEPTH10, PRIVATE, HEIC, + HEIC_ULTRAHDR, JPEG_R }) public @interface Format { @@ -831,6 +834,16 @@ public class ImageFormat { */ public static final int HEIC = 0x48454946; + /** + * High Efficiency Image File Format (HEIF) with embedded HDR gain map + * + *

    This format defines the HEIC brand of High Efficiency Image File + * Format as described in ISO/IEC 23008-12:2024 with HDR gain map according + * to ISO/CD 21496‐1.

    + */ + @FlaggedApi(Flags.FLAG_CAMERA_HEIF_GAINMAP) + public static final int HEIC_ULTRAHDR = 0x1006; + /** * Use this function to retrieve the number of bits per pixel of an * ImageFormat. @@ -926,6 +939,11 @@ public class ImageFormat { if (android.media.codec.Flags.p210FormatSupport() && format == YCBCR_P210) { return true; } + if (Flags.cameraHeifGainmap()){ + if (format == HEIC_ULTRAHDR) { + return true; + } + } return false; } } diff --git a/graphics/java/android/graphics/Paint.java b/graphics/java/android/graphics/Paint.java index b7a1c13c75c7f4ccca22ae612dc1b2cbd0358333..8bb32568ec5af639f1e077b0211394e62678a233 100644 --- a/graphics/java/android/graphics/Paint.java +++ b/graphics/java/android/graphics/Paint.java @@ -19,7 +19,7 @@ package android.graphics; import static com.android.text.flags.Flags.FLAG_FIX_LINE_HEIGHT_FOR_LOCALE; import static com.android.text.flags.Flags.FLAG_LETTER_SPACING_JUSTIFICATION; import static com.android.text.flags.Flags.FLAG_DEPRECATE_ELEGANT_TEXT_HEIGHT_API; - +import static com.android.text.flags.Flags.FLAG_VERTICAL_TEXT_LAYOUT; import android.annotation.ColorInt; import android.annotation.ColorLong; @@ -35,6 +35,7 @@ import android.compat.annotation.ChangeId; import android.compat.annotation.EnabledSince; import android.compat.annotation.UnsupportedAppUsage; import android.graphics.fonts.FontVariationAxis; +import android.graphics.text.TextRunShaper; import android.os.Build; import android.os.LocaleList; import android.text.GraphicsOperations; @@ -269,7 +270,24 @@ public class Paint { public static final int EMBEDDED_BITMAP_TEXT_FLAG = 0x400; /** @hide bit mask for the flag forcing freetype's autohinter on for text */ public static final int AUTO_HINTING_TEXT_FLAG = 0x800; - /** @hide bit mask for the flag enabling vertical rendering for text */ + + /** + * A flat that controls text to be written in vertical orientation + * + *

    + * This flag is used for telling the underlying text layout engine that the text is for vertical + * direction. By enabling this flag, text measurement, drawing and shaping APIs works for + * vertical text layout. For example, {@link Canvas#drawText(String, float, float, Paint)} draws + * text from top to bottom. {@link Paint#measureText(String)} returns vertical advances instead + * of horizontal advances. {@link TextRunShaper} shapes text vertically and report glyph IDs for + * vertical layout. + * + *

    + * Do not set this flag for making {@link android.text.Layout}. The {@link android.text.Layout} + * class and its subclasses are designed for horizontal text only and does not work for vertical + * text. + */ + @FlaggedApi(FLAG_VERTICAL_TEXT_LAYOUT) public static final int VERTICAL_TEXT_FLAG = 0x1000; /** diff --git a/keystore/java/android/security/keystore/KeyStoreManager.java b/keystore/java/android/security/keystore/KeyStoreManager.java index 197aaba4bcb5435a4cc55ad558288de4241388e4..e6091c1da8a5efa5aa2668384f1b1a273fec8877 100644 --- a/keystore/java/android/security/keystore/KeyStoreManager.java +++ b/keystore/java/android/security/keystore/KeyStoreManager.java @@ -49,7 +49,7 @@ import java.util.List; */ @FlaggedApi(android.security.Flags.FLAG_KEYSTORE_GRANT_API) @SystemService(Context.KEYSTORE_SERVICE) -public class KeyStoreManager { +public final class KeyStoreManager { private static final String TAG = "KeyStoreManager"; private static final Object sInstanceLock = new Object(); diff --git a/libs/WindowManager/Jetpack/src/androidx/window/extensions/area/WindowAreaComponentImpl.java b/libs/WindowManager/Jetpack/src/androidx/window/extensions/area/WindowAreaComponentImpl.java index 438532725686e353c3d2b97d6aa5ad2d88ef0781..4d7be39ca5a40888713e81a9676f266dcb6507e0 100644 --- a/libs/WindowManager/Jetpack/src/androidx/window/extensions/area/WindowAreaComponentImpl.java +++ b/libs/WindowManager/Jetpack/src/androidx/window/extensions/area/WindowAreaComponentImpl.java @@ -16,6 +16,7 @@ package androidx.window.extensions.area; +import static android.hardware.devicestate.DeviceState.PROPERTY_EMULATED_ONLY; import static android.hardware.devicestate.DeviceState.PROPERTY_FEATURE_DUAL_DISPLAY_INTERNAL_DEFAULT; import static android.hardware.devicestate.DeviceState.PROPERTY_FEATURE_REAR_DISPLAY; import static android.hardware.devicestate.DeviceState.PROPERTY_FOLDABLE_DISPLAY_CONFIGURATION_OUTER_PRIMARY; @@ -569,7 +570,8 @@ public class WindowAreaComponentImpl implements WindowAreaComponent, private boolean isDeviceFolded() { if (Flags.deviceStatePropertyApi()) { return mCurrentDeviceState.hasProperty( - PROPERTY_FOLDABLE_DISPLAY_CONFIGURATION_OUTER_PRIMARY); + PROPERTY_FOLDABLE_DISPLAY_CONFIGURATION_OUTER_PRIMARY) + && !mCurrentDeviceState.hasProperty(PROPERTY_EMULATED_ONLY); } else { return ArrayUtils.contains(mFoldedDeviceStates, mCurrentDeviceState.getIdentifier()); } diff --git a/libs/WindowManager/Shell/multivalentTests/src/com/android/wm/shell/bubbles/bar/BubbleBarExpandedViewTest.kt b/libs/WindowManager/Shell/multivalentTests/src/com/android/wm/shell/bubbles/bar/BubbleBarExpandedViewTest.kt index 08d647de4a51ca4ed4bb9d418eb7fe32e9e97721..0d742cc6e382c9cb226dd9dc4cdccc0998967c45 100644 --- a/libs/WindowManager/Shell/multivalentTests/src/com/android/wm/shell/bubbles/bar/BubbleBarExpandedViewTest.kt +++ b/libs/WindowManager/Shell/multivalentTests/src/com/android/wm/shell/bubbles/bar/BubbleBarExpandedViewTest.kt @@ -47,6 +47,7 @@ import com.android.wm.shell.shared.handles.RegionSamplingHelper import com.android.wm.shell.taskview.TaskView import com.android.wm.shell.taskview.TaskViewTaskController import com.google.common.truth.Truth.assertThat +import com.google.common.truth.Truth.assertWithMessage import com.google.common.util.concurrent.MoreExecutors.directExecutor import java.util.Collections import java.util.concurrent.Executor @@ -147,6 +148,7 @@ class BubbleBarExpandedViewTest { @After fun tearDown() { testableRegionSamplingHelper?.stopAndDestroy() + getInstrumentation().waitForIdleSync() } @Test @@ -218,8 +220,8 @@ class BubbleBarExpandedViewTest { @Test fun testEventLogging_dismissBubbleViaAppMenu() { getInstrumentation().runOnMainSync { bubbleExpandedView.handleView.performClick() } - val dismissMenuItem = - bubbleExpandedView.findViewWithTag(BubbleBarMenuView.DISMISS_ACTION_TAG) + val dismissMenuItem = bubbleExpandedView.menuView() + .actionViewWithText(context.getString(R.string.bubble_dismiss_text)) assertThat(dismissMenuItem).isNotNull() getInstrumentation().runOnMainSync { dismissMenuItem.performClick() } assertThat(uiEventLoggerFake.numLogs()).isEqualTo(1) @@ -228,6 +230,42 @@ class BubbleBarExpandedViewTest { assertThat(uiEventLoggerFake.logs[0]).hasBubbleInfo(bubble) } + @Test + fun testEventLogging_openAppSettings() { + getInstrumentation().runOnMainSync { bubbleExpandedView.handleView.performClick() } + val appMenuItem = bubbleExpandedView.menuView() + .actionViewWithText(context.getString(R.string.bubbles_app_settings, bubble.appName)) + getInstrumentation().runOnMainSync { appMenuItem.performClick() } + assertThat(uiEventLoggerFake.numLogs()).isEqualTo(1) + assertThat(uiEventLoggerFake.logs[0].eventId) + .isEqualTo(BubbleLogger.Event.BUBBLE_BAR_APP_MENU_GO_TO_SETTINGS.id) + assertThat(uiEventLoggerFake.logs[0]).hasBubbleInfo(bubble) + } + + @Test + fun testEventLogging_unBubbleConversation() { + getInstrumentation().runOnMainSync { bubbleExpandedView.handleView.performClick() } + val menuItem = bubbleExpandedView.menuView() + .actionViewWithText(context.getString(R.string.bubbles_dont_bubble_conversation)) + getInstrumentation().runOnMainSync { menuItem.performClick() } + assertThat(uiEventLoggerFake.numLogs()).isEqualTo(1) + assertThat(uiEventLoggerFake.logs[0].eventId) + .isEqualTo(BubbleLogger.Event.BUBBLE_BAR_APP_MENU_OPT_OUT.id) + assertThat(uiEventLoggerFake.logs[0]).hasBubbleInfo(bubble) + } + + private fun BubbleBarExpandedView.menuView(): BubbleBarMenuView { + return findViewByPredicate { it is BubbleBarMenuView } + } + + private fun BubbleBarMenuView.actionViewWithText(text: CharSequence): View { + val views = ArrayList() + findViewsWithText(views, text, View.FIND_VIEWS_WITH_TEXT) + assertWithMessage("Expecting a single action with text '$text'").that(views).hasSize(1) + // findViewsWithText returns the TextView, but the click listener is on the parent container + return views.first().parent as View + } + private inner class FakeBubbleTaskViewFactory : BubbleTaskViewFactory { override fun create(): BubbleTaskView { val taskViewTaskController = mock() diff --git a/libs/WindowManager/Shell/multivalentTests/src/com/android/wm/shell/bubbles/bar/BubbleBarLayerViewTest.kt b/libs/WindowManager/Shell/multivalentTests/src/com/android/wm/shell/bubbles/bar/BubbleBarLayerViewTest.kt index 2fbf089d99d6b8bc1fb5ff75ef182873a9f9ef03..00d9a931cebe1b03ed8211d3bd015f7f0b090f74 100644 --- a/libs/WindowManager/Shell/multivalentTests/src/com/android/wm/shell/bubbles/bar/BubbleBarLayerViewTest.kt +++ b/libs/WindowManager/Shell/multivalentTests/src/com/android/wm/shell/bubbles/bar/BubbleBarLayerViewTest.kt @@ -19,12 +19,15 @@ package com.android.wm.shell.bubbles.bar import android.app.ActivityManager import android.content.Context import android.content.pm.LauncherApps +import android.graphics.PointF import android.os.Handler import android.os.UserManager import android.view.IWindowManager import android.view.LayoutInflater +import android.view.MotionEvent import android.view.View import android.view.WindowManager +import androidx.core.animation.AnimatorTestRule import androidx.test.core.app.ApplicationProvider import androidx.test.ext.junit.runners.AndroidJUnit4 import androidx.test.filters.SmallTest @@ -48,6 +51,7 @@ import com.android.wm.shell.bubbles.BubbleTaskViewFactory import com.android.wm.shell.bubbles.Bubbles.SysuiProxy import com.android.wm.shell.bubbles.FakeBubbleFactory import com.android.wm.shell.bubbles.UiEventSubject.Companion.assertThat +import com.android.wm.shell.bubbles.animation.AnimatableScaleMatrix import com.android.wm.shell.bubbles.properties.BubbleProperties import com.android.wm.shell.bubbles.storage.BubblePersistentRepository import com.android.wm.shell.common.DisplayController @@ -57,6 +61,7 @@ import com.android.wm.shell.common.ShellExecutor import com.android.wm.shell.common.SyncTransactionQueue import com.android.wm.shell.common.TaskStackListenerImpl import com.android.wm.shell.shared.TransactionPool +import com.android.wm.shell.shared.animation.PhysicsAnimatorTestUtils import com.android.wm.shell.shared.bubbles.BubbleBarLocation import com.android.wm.shell.sysui.ShellCommandHandler import com.android.wm.shell.sysui.ShellController @@ -66,8 +71,10 @@ import com.android.wm.shell.taskview.TaskViewTaskController import com.android.wm.shell.taskview.TaskViewTransitions import com.android.wm.shell.transition.Transitions import com.google.common.truth.Truth.assertThat +import org.junit.After import java.util.Collections import org.junit.Before +import org.junit.ClassRule import org.junit.Test import org.junit.runner.RunWith import org.mockito.Mockito.mock @@ -79,18 +86,28 @@ import org.mockito.kotlin.whenever @RunWith(AndroidJUnit4::class) class BubbleBarLayerViewTest { + companion object { + @JvmField @ClassRule + val animatorTestRule: AnimatorTestRule = AnimatorTestRule() + } + private val context = ApplicationProvider.getApplicationContext() private lateinit var bubbleBarLayerView: BubbleBarLayerView private lateinit var uiEventLoggerFake: UiEventLoggerFake + private lateinit var bubbleController: BubbleController + + private lateinit var bubblePositioner: BubblePositioner + private lateinit var bubble: Bubble @Before fun setUp() { ProtoLog.REQUIRE_PROTOLOGTOOL = false ProtoLog.init() + PhysicsAnimatorTestUtils.prepareForTest() uiEventLoggerFake = UiEventLoggerFake() val bubbleLogger = BubbleLogger(uiEventLoggerFake) @@ -100,7 +117,7 @@ class BubbleBarLayerViewTest { val windowManager = context.getSystemService(WindowManager::class.java) - val bubblePositioner = BubblePositioner(context, windowManager) + bubblePositioner = BubblePositioner(context, windowManager) bubblePositioner.setShowingInBubbleBar(true) val bubbleData = @@ -113,7 +130,7 @@ class BubbleBarLayerViewTest { bgExecutor, ) - val bubbleController = + bubbleController = createBubbleController( bubbleData, windowManager, @@ -151,6 +168,12 @@ class BubbleBarLayerViewTest { bubble = FakeBubbleFactory.createChatBubbleWithViewInfo(context, viewInfo = viewInfo) } + @After + fun tearDown() { + PhysicsAnimatorTestUtils.tearDown() + getInstrumentation().waitForIdleSync() + } + private fun createBubbleController( bubbleData: BubbleData, windowManager: WindowManager?, @@ -224,6 +247,70 @@ class BubbleBarLayerViewTest { assertThat(uiEventLoggerFake.logs[0]).hasBubbleInfo(bubble) } + @Test + fun testEventLogging_dragExpandedViewLeft() { + bubblePositioner.bubbleBarLocation = BubbleBarLocation.RIGHT + + getInstrumentation().runOnMainSync { + bubbleBarLayerView.showExpandedView(bubble) + } + waitForExpandedViewAnimation() + + val handleView = bubbleBarLayerView.findViewById(R.id.bubble_bar_handle_view) + assertThat(handleView).isNotNull() + + // Drag from right to left + handleView.dispatchTouchEvent(0L, MotionEvent.ACTION_DOWN, rightEdge()) + handleView.dispatchTouchEvent(10L, MotionEvent.ACTION_MOVE, leftEdge()) + handleView.dispatchTouchEvent(20L, MotionEvent.ACTION_UP, leftEdge()) + + assertThat(uiEventLoggerFake.numLogs()).isEqualTo(1) + assertThat(uiEventLoggerFake.logs[0].eventId) + .isEqualTo(BubbleLogger.Event.BUBBLE_BAR_MOVED_LEFT_DRAG_EXP_VIEW.id) + assertThat(uiEventLoggerFake.logs[0]).hasBubbleInfo(bubble) + } + + @Test + fun testEventLogging_dragExpandedViewRight() { + bubblePositioner.bubbleBarLocation = BubbleBarLocation.LEFT + + getInstrumentation().runOnMainSync { + bubbleBarLayerView.showExpandedView(bubble) + } + waitForExpandedViewAnimation() + + val handleView = bubbleBarLayerView.findViewById(R.id.bubble_bar_handle_view) + assertThat(handleView).isNotNull() + + // Drag from left to right + handleView.dispatchTouchEvent(0L, MotionEvent.ACTION_DOWN, leftEdge()) + handleView.dispatchTouchEvent(10L, MotionEvent.ACTION_MOVE, rightEdge()) + handleView.dispatchTouchEvent(20L, MotionEvent.ACTION_UP, rightEdge()) + + assertThat(uiEventLoggerFake.numLogs()).isEqualTo(1) + assertThat(uiEventLoggerFake.logs[0].eventId) + .isEqualTo(BubbleLogger.Event.BUBBLE_BAR_MOVED_RIGHT_DRAG_EXP_VIEW.id) + assertThat(uiEventLoggerFake.logs[0]).hasBubbleInfo(bubble) + } + + private fun leftEdge(): PointF { + val screenSize = bubblePositioner.availableRect + return PointF(screenSize.left.toFloat(), screenSize.height() / 2f) + } + + private fun rightEdge(): PointF { + val screenSize = bubblePositioner.availableRect + return PointF(screenSize.right.toFloat(), screenSize.height() / 2f) + } + + private fun waitForExpandedViewAnimation() { + // wait for idle to allow the animation to start + getInstrumentation().waitForIdleSync() + getInstrumentation().runOnMainSync { animatorTestRule.advanceTimeBy(200) } + PhysicsAnimatorTestUtils.blockUntilAnimationsEnd( + AnimatableScaleMatrix.SCALE_X, AnimatableScaleMatrix.SCALE_Y) + } + private inner class FakeBubbleTaskViewFactory(private val mainExecutor: ShellExecutor) : BubbleTaskViewFactory { override fun create(): BubbleTaskView { @@ -290,4 +377,9 @@ class BubbleBarLayerViewTest { } } } + + private fun View.dispatchTouchEvent(eventTime: Long, action: Int, point: PointF) { + val event = MotionEvent.obtain(0L, eventTime, action, point.x, point.y, 0) + getInstrumentation().runOnMainSync { dispatchTouchEvent(event) } + } } diff --git a/libs/WindowManager/Shell/multivalentTests/src/com/android/wm/shell/bubbles/bar/BubbleExpandedViewPinControllerTest.kt b/libs/WindowManager/Shell/multivalentTests/src/com/android/wm/shell/bubbles/bar/BubbleExpandedViewPinControllerTest.kt index ecb2b25a02f1583c87fd4f1fcff5456994814392..d4cbe6e1097125a1846b91b798c5b5e88a3427d4 100644 --- a/libs/WindowManager/Shell/multivalentTests/src/com/android/wm/shell/bubbles/bar/BubbleExpandedViewPinControllerTest.kt +++ b/libs/WindowManager/Shell/multivalentTests/src/com/android/wm/shell/bubbles/bar/BubbleExpandedViewPinControllerTest.kt @@ -74,6 +74,7 @@ class BubbleExpandedViewPinControllerTest { @Before fun setUp() { ProtoLog.REQUIRE_PROTOLOGTOOL = false + ProtoLog.init() container = FrameLayout(context) val windowManager = context.getSystemService(WindowManager::class.java) positioner = BubblePositioner(context, windowManager) @@ -85,7 +86,7 @@ class BubbleExpandedViewPinControllerTest { isSmallTablet = false, isLandscape = true, isRtl = false, - insets = Insets.of(10, 20, 30, 40) + insets = Insets.of(10, 20, 30, 40), ) positioner.update(deviceConfig) positioner.bubbleBarTopOnScreen = @@ -407,12 +408,26 @@ class BubbleExpandedViewPinControllerTest { assertThat(testListener.locationReleases).containsExactly(RIGHT) } + /** Send drag start event when on left */ + @Test + fun start_onLeft_sendStartEventOnLeft() { + getInstrumentation().runOnMainSync { controller.onDragStart(initialLocationOnLeft = true) } + assertThat(testListener.locationStart).containsExactly(LEFT) + } + + /** Send drag start event when on right */ + @Test + fun start_onRight_sendStartEventOnRight() { + getInstrumentation().runOnMainSync { controller.onDragStart(initialLocationOnLeft = false) } + assertThat(testListener.locationStart).containsExactly(RIGHT) + } + private fun getExpectedDropTargetBoundsOnLeft(): Rect = Rect().also { positioner.getBubbleBarExpandedViewBounds( true /* onLeft */, false /* isOverflowExpanded */, - it + it, ) } @@ -421,7 +436,7 @@ class BubbleExpandedViewPinControllerTest { positioner.getBubbleBarExpandedViewBounds( false /* onLeft */, false /* isOverflowExpanded */, - it + it, ) } @@ -446,8 +461,14 @@ class BubbleExpandedViewPinControllerTest { } internal class TestLocationChangeListener : BaseBubblePinController.LocationChangeListener { + val locationStart = mutableListOf() val locationChanges = mutableListOf() val locationReleases = mutableListOf() + + override fun onStart(location: BubbleBarLocation) { + locationStart.add(location) + } + override fun onChange(location: BubbleBarLocation) { locationChanges.add(location) } diff --git a/libs/WindowManager/Shell/res/drawable/desktop_mode_ic_handle_menu_change_aspect_ratio.xml b/libs/WindowManager/Shell/res/drawable/desktop_mode_ic_handle_menu_change_aspect_ratio.xml new file mode 100644 index 0000000000000000000000000000000000000000..4442e9df76887d82f508e4755c3d5da5168235e4 --- /dev/null +++ b/libs/WindowManager/Shell/res/drawable/desktop_mode_ic_handle_menu_change_aspect_ratio.xml @@ -0,0 +1,25 @@ + + + + + diff --git a/libs/WindowManager/Shell/res/layout/bubble_bar_expanded_view.xml b/libs/WindowManager/Shell/res/layout/bubble_bar_expanded_view.xml index 501bedd50f554e89f8fe4927f8ccbbbcad6f5910..c2755ef6ccb67d10ced6cb371a601e3ff4fffe52 100644 --- a/libs/WindowManager/Shell/res/layout/bubble_bar_expanded_view.xml +++ b/libs/WindowManager/Shell/res/layout/bubble_bar_expanded_view.xml @@ -19,6 +19,7 @@ android:layout_height="wrap_content" android:layout_width="wrap_content" android:orientation="vertical" + android:clipChildren="false" android:id="@+id/bubble_expanded_view"> - + android:visibility="invisible" + tools:visibility="visible"> + +