diff options
461 files changed, 15024 insertions, 3644 deletions
diff --git a/AconfigFlags.bp b/AconfigFlags.bp index 2457e707ef57..c211b0202925 100644 --- a/AconfigFlags.bp +++ b/AconfigFlags.bp @@ -53,6 +53,7 @@ aconfig_srcjars = [ ":android.credentials.flags-aconfig-java{.generated_srcjars}", ":android.view.contentprotection.flags-aconfig-java{.generated_srcjars}", ":android.service.voice.flags-aconfig-java{.generated_srcjars}", + ":android.media.tv.flags-aconfig-java{.generated_srcjars}", ":aconfig_midi_flags_java_lib{.generated_srcjars}", ":android.service.autofill.flags-aconfig-java{.generated_srcjars}", ":com.android.net.flags-aconfig-java{.generated_srcjars}", @@ -379,6 +380,19 @@ java_aconfig_library { defaults: ["framework-minus-apex-aconfig-java-defaults"], } +// Media TV +aconfig_declarations { + name: "android.media.tv.flags-aconfig", + package: "android.media.tv.flags", + srcs: ["media/java/android/media/tv/flags/media_tv.aconfig"], +} + +java_aconfig_library { + name: "android.media.tv.flags-aconfig-java", + aconfig_declarations: "android.media.tv.flags-aconfig", + defaults: ["framework-minus-apex-aconfig-java-defaults"], +} + // Media Audio java_aconfig_library { name: "com.android.media.audio.flags-aconfig-java", @@ -570,6 +584,24 @@ java_aconfig_library { defaults: ["framework-minus-apex-aconfig-java-defaults"], } +// Media +aconfig_declarations { + name: "android.media.playback.flags-aconfig", + package: "com.android.media.playback.flags", + srcs: ["media/jni/playback_flags.aconfig"], +} + +cc_aconfig_library { + name: "android.media.playback.flags-aconfig-cc", + aconfig_declarations: "android.media.playback.flags-aconfig", +} + +java_aconfig_library { + name: "android.media.playback.flags-aconfig-java", + aconfig_declarations: "android.media.playback.flags-aconfig", + defaults: ["framework-minus-apex-aconfig-java-defaults"], +} + // VCN aconfig_declarations { name: "android.net.vcn.flags-aconfig", diff --git a/Android.bp b/Android.bp index 8c4d76919568..49386d44ede3 100644 --- a/Android.bp +++ b/Android.bp @@ -614,19 +614,6 @@ java_library { ], } -packages_to_document = [ - "android", - "dalvik", - "java", - "javax", - "junit", - "org.apache.http", - "org.json", - "org.w3c.dom", - "org.xml.sax", - "org.xmlpull", -] - filegroup { name: "android-non-updatable-stub-sources", srcs: [ @@ -641,142 +628,6 @@ filegroup { visibility: ["//frameworks/base/api"], } -// Defaults for all stubs that include the non-updatable framework. These defaults do not include -// module symbols, so will not compile correctly on their own. Users must add module APIs to the -// classpath (or sources) somehow. -stubs_defaults { - name: "android-non-updatable-stubs-defaults", - srcs: [":android-non-updatable-stub-sources"], - sdk_version: "none", - system_modules: "none", - java_version: "1.8", - arg_files: [":frameworks-base-core-AndroidManifest.xml"], - aidl: { - include_dirs: [ - "frameworks/av/aidl", - "frameworks/base/media/aidl", - "frameworks/base/telephony/java", - "frameworks/native/libs/permission/aidl", - "packages/modules/Bluetooth/framework/aidl-export", - "packages/modules/Connectivity/framework/aidl-export", - "packages/modules/Media/apex/aidl/stable", - "hardware/interfaces/biometrics/common/aidl", - "hardware/interfaces/biometrics/fingerprint/aidl", - "hardware/interfaces/graphics/common/aidl", - "hardware/interfaces/keymaster/aidl", - "system/hardware/interfaces/media/aidl", - ], - }, - // These are libs from framework-internal-utils that are required (i.e. being referenced) - // from framework-non-updatable-sources. Add more here when there's a need. - // DO NOT add the entire framework-internal-utils. It might cause unnecessary circular - // dependencies gets bigger. - libs: [ - "android.hardware.cas-V1.2-java", - "android.hardware.health-V1.0-java-constants", - "android.hardware.thermal-V1.0-java-constants", - "android.hardware.thermal-V2.0-java", - "android.hardware.tv.input-V1.0-java-constants", - "android.hardware.usb-V1.0-java-constants", - "android.hardware.usb-V1.1-java-constants", - "android.hardware.usb.gadget-V1.0-java", - "android.hardware.vibrator-V1.3-java", - "framework-protos", - ], - flags: [ - "--api-lint-ignore-prefix android.icu.", - "--api-lint-ignore-prefix java.", - "--api-lint-ignore-prefix junit.", - "--api-lint-ignore-prefix org.", - "--error NoSettingsProvider", - "--error UnhiddenSystemApi", - "--error UnflaggedApi", - "--force-convert-to-warning-nullability-annotations +*:-android.*:+android.icu.*:-dalvik.*", - "--hide BroadcastBehavior", - "--hide CallbackInterface", - "--hide DeprecationMismatch", - "--hide HiddenSuperclass", - "--hide MissingPermission", - "--hide RequiresPermission", - "--hide SdkConstant", - "--hide Todo", - "--hide-package android.audio.policy.configuration.V7_0", - "--hide-package com.android.server", - "--manifest $(location :frameworks-base-core-AndroidManifest.xml)", - ], - filter_packages: packages_to_document, - high_mem: true, // Lots of sources => high memory use, see b/170701554 - installable: false, - annotations_enabled: true, - previous_api: ":android.api.public.latest", - merge_annotations_dirs: ["metalava-manual"], - defaults_visibility: ["//frameworks/base/api"], - visibility: ["//frameworks/base/api"], -} - -// Defaults with module APIs in the classpath (mostly from prebuilts). -// Suitable for compiling android-non-updatable. -stubs_defaults { - name: "module-classpath-stubs-defaults", - aidl: { - include_dirs: [ - "packages/modules/Bluetooth/framework/aidl-export", - "packages/modules/Connectivity/framework/aidl-export", - "packages/modules/Media/apex/aidl/stable", - ], - }, - libs: [ - "art.module.public.api", - "sdk_module-lib_current_framework-tethering", - "sdk_module-lib_current_framework-connectivity-t", - "sdk_public_current_framework-bluetooth", - // There are a few classes from modules used by the core that - // need to be resolved by metalava. We use a prebuilt stub of the - // full sdk to ensure we can resolve them. If a new class gets added, - // the prebuilts/sdk/current needs to be updated. - "sdk_system_current_android", - // NOTE: The below can be removed once the prebuilt stub contains IKE. - "sdk_system_current_android.net.ipsec.ike", - ], -} - -// Defaults for the java_sdk_libraries of unbundled jars from framework. -// java_sdk_libraries using these defaults should also add themselves to the -// non_updatable_modules list in frameworks/base/api/api.go -java_defaults { - name: "framework-non-updatable-unbundled-defaults", - defaults: [ - "framework-non-updatable-lint-defaults", - "non-updatable-framework-module-defaults", - ], - public: { - libs: ["android_module_lib_stubs_current"], - }, - system: { - libs: ["android_module_lib_stubs_current"], - }, - module_lib: { - libs: ["android_module_lib_stubs_current"], - }, - test: { - libs: ["android_test_frameworks_core_stubs_current"], - }, - sdk_version: "core_platform", - stub_only_libs: ["framework-protos"], - impl_only_libs: ["framework-minus-apex-headers"], // the framework, including hidden API - impl_library_visibility: ["//frameworks/base"], - defaults_visibility: ["//frameworks/base/location"], - plugins: ["error_prone_android_framework"], - errorprone: { - javacflags: [ - "-Xep:AndroidFrameworkCompatChange:ERROR", - "-Xep:AndroidFrameworkUid:ERROR", - ], - }, - // Include manual annotations in API txt files - merge_annotations_dirs: ["metalava-manual"], -} - build = [ "AconfigFlags.bp", "ProtoLibraries.bp", diff --git a/apex/jobscheduler/framework/java/android/app/job/JobInfo.java b/apex/jobscheduler/framework/java/android/app/job/JobInfo.java index a92a01fe06f0..646e05c50a76 100644 --- a/apex/jobscheduler/framework/java/android/app/job/JobInfo.java +++ b/apex/jobscheduler/framework/java/android/app/job/JobInfo.java @@ -432,7 +432,6 @@ public class JobInfo implements Parcelable { @UnsupportedAppUsage private final ComponentName service; private final int constraintFlags; - private final int mPreferredConstraintFlags; private final TriggerContentUri[] triggerContentUris; private final long triggerContentUpdateDelay; private final long triggerContentMaxDelay; @@ -523,30 +522,6 @@ public class JobInfo implements Parcelable { } /** - * @hide - * @see JobInfo.Builder#setPrefersBatteryNotLow(boolean) - */ - public boolean isPreferBatteryNotLow() { - return (mPreferredConstraintFlags & CONSTRAINT_FLAG_BATTERY_NOT_LOW) != 0; - } - - /** - * @hide - * @see JobInfo.Builder#setPrefersCharging(boolean) - */ - public boolean isPreferCharging() { - return (mPreferredConstraintFlags & CONSTRAINT_FLAG_CHARGING) != 0; - } - - /** - * @hide - * @see JobInfo.Builder#setPrefersDeviceIdle(boolean) - */ - public boolean isPreferDeviceIdle() { - return (mPreferredConstraintFlags & CONSTRAINT_FLAG_DEVICE_IDLE) != 0; - } - - /** * @see JobInfo.Builder#setRequiresCharging(boolean) */ public boolean isRequireCharging() { @@ -582,13 +557,6 @@ public class JobInfo implements Parcelable { } /** - * @hide - */ - public int getPreferredConstraintFlags() { - return mPreferredConstraintFlags; - } - - /** * Which content: URIs must change for the job to be scheduled. Returns null * if there are none required. * @see JobInfo.Builder#addTriggerContentUri(TriggerContentUri) @@ -832,9 +800,6 @@ public class JobInfo implements Parcelable { if (constraintFlags != j.constraintFlags) { return false; } - if (mPreferredConstraintFlags != j.mPreferredConstraintFlags) { - return false; - } if (!Arrays.equals(triggerContentUris, j.triggerContentUris)) { return false; } @@ -915,7 +880,6 @@ public class JobInfo implements Parcelable { hashCode = 31 * hashCode + service.hashCode(); } hashCode = 31 * hashCode + constraintFlags; - hashCode = 31 * hashCode + mPreferredConstraintFlags; if (triggerContentUris != null) { hashCode = 31 * hashCode + Arrays.hashCode(triggerContentUris); } @@ -958,7 +922,6 @@ public class JobInfo implements Parcelable { } service = in.readParcelable(null); constraintFlags = in.readInt(); - mPreferredConstraintFlags = in.readInt(); triggerContentUris = in.createTypedArray(TriggerContentUri.CREATOR); triggerContentUpdateDelay = in.readLong(); triggerContentMaxDelay = in.readLong(); @@ -993,7 +956,6 @@ public class JobInfo implements Parcelable { clipGrantFlags = b.mClipGrantFlags; service = b.mJobService; constraintFlags = b.mConstraintFlags; - mPreferredConstraintFlags = b.mPreferredConstraintFlags; triggerContentUris = b.mTriggerContentUris != null ? b.mTriggerContentUris.toArray(new TriggerContentUri[b.mTriggerContentUris.size()]) : null; @@ -1037,7 +999,6 @@ public class JobInfo implements Parcelable { } out.writeParcelable(service, flags); out.writeInt(constraintFlags); - out.writeInt(mPreferredConstraintFlags); out.writeTypedArray(triggerContentUris, flags); out.writeLong(triggerContentUpdateDelay); out.writeLong(triggerContentMaxDelay); @@ -1185,7 +1146,6 @@ public class JobInfo implements Parcelable { private int mFlags; // Requirements. private int mConstraintFlags; - private int mPreferredConstraintFlags; private NetworkRequest mNetworkRequest; private long mNetworkDownloadBytes = NETWORK_BYTES_UNKNOWN; private long mNetworkUploadBytes = NETWORK_BYTES_UNKNOWN; @@ -1239,7 +1199,6 @@ public class JobInfo implements Parcelable { mBias = job.getBias(); mFlags = job.getFlags(); mConstraintFlags = job.getConstraintFlags(); - mPreferredConstraintFlags = job.getPreferredConstraintFlags(); mNetworkRequest = job.getRequiredNetwork(); mNetworkDownloadBytes = job.getEstimatedNetworkDownloadBytes(); mNetworkUploadBytes = job.getEstimatedNetworkUploadBytes(); @@ -1389,6 +1348,10 @@ public class JobInfo implements Parcelable { * {@link android.Manifest.permission#ACCESS_NETWORK_STATE} permission to * schedule a job that requires a network. * + * <p> Starting in Android version {@link android.os.Build.VERSION_CODES#UPSIDE_DOWN_CAKE}, + * {@link JobScheduler} may try to shift the execution of jobs requiring + * {@link #NETWORK_TYPE_ANY} to when there is access to an un-metered network. + * * <p class="note"> * When your job executes in * {@link JobService#onStartJob(JobParameters)}, be sure to use the @@ -1555,100 +1518,6 @@ public class JobInfo implements Parcelable { } /** - * Specify that this job would prefer to be run when the device's battery is not low. - * This defaults to {@code false}. - * - * <p>The system may attempt to delay this job until the device's battery is not low, - * but may choose to run it even if the device's battery is low. JobScheduler will not stop - * this job if this constraint is no longer satisfied after the job has started running. - * If this job must only run when the device's battery is not low, - * use {@link #setRequiresBatteryNotLow(boolean)} instead. - * - * <p> - * Because it doesn't make sense for a constraint to be both preferred and required, - * calling both this and {@link #setRequiresBatteryNotLow(boolean)} with {@code true} - * will result in an {@link java.lang.IllegalArgumentException} when - * {@link android.app.job.JobInfo.Builder#build()} is called. - * - * @param prefersBatteryNotLow Pass {@code true} to prefer that the device's battery level - * not be low in order to run the job. - * @return This object for method chaining - * @see JobInfo#isPreferBatteryNotLow() - * @hide - */ - @NonNull - public Builder setPrefersBatteryNotLow(boolean prefersBatteryNotLow) { - mPreferredConstraintFlags = - (mPreferredConstraintFlags & ~CONSTRAINT_FLAG_BATTERY_NOT_LOW) - | (prefersBatteryNotLow ? CONSTRAINT_FLAG_BATTERY_NOT_LOW : 0); - return this; - } - - /** - * Specify that this job would prefer to be run when the device is charging (or be a - * non-battery-powered device connected to permanent power, such as Android TV - * devices). This defaults to {@code false}. - * - * <p> - * The system may attempt to delay this job until the device is charging, but may - * choose to run it even if the device is not charging. JobScheduler will not stop - * this job if this constraint is no longer satisfied after the job has started running. - * If this job must only run when the device is charging, - * use {@link #setRequiresCharging(boolean)} instead. - * - * <p> - * Because it doesn't make sense for a constraint to be both preferred and required, - * calling both this and {@link #setRequiresCharging(boolean)} with {@code true} - * will result in an {@link java.lang.IllegalArgumentException} when - * {@link android.app.job.JobInfo.Builder#build()} is called. - * - * @param prefersCharging Pass {@code true} to prefer that the device be - * charging in order to run the job. - * @return This object for method chaining - * @see JobInfo#isPreferCharging() - * @hide - */ - @NonNull - public Builder setPrefersCharging(boolean prefersCharging) { - mPreferredConstraintFlags = (mPreferredConstraintFlags & ~CONSTRAINT_FLAG_CHARGING) - | (prefersCharging ? CONSTRAINT_FLAG_CHARGING : 0); - return this; - } - - /** - * Specify that this job would prefer to be run when the device is not in active use. - * This defaults to {@code false}. - * - * <p>The system may attempt to delay this job until the device is not in active use, - * but may choose to run it even if the device is not idle. JobScheduler will not stop - * this job if this constraint is no longer satisfied after the job has started running. - * If this job must only run when the device is not in active use, - * use {@link #setRequiresDeviceIdle(boolean)} instead. - * - * <p> - * Because it doesn't make sense for a constraint to be both preferred and required, - * calling both this and {@link #setRequiresDeviceIdle(boolean)} with {@code true} - * will result in an {@link java.lang.IllegalArgumentException} when - * {@link android.app.job.JobInfo.Builder#build()} is called. - * - * <p class="note">Despite the similar naming, this job constraint is <em>not</em> - * related to the system's "device idle" or "doze" states. This constraint only - * determines whether a job is allowed to run while the device is directly in use. - * - * @param prefersDeviceIdle Pass {@code true} to prefer that the device not be in active - * use when running this job. - * @return This object for method chaining - * @see JobInfo#isRequireDeviceIdle() - * @hide - */ - @NonNull - public Builder setPrefersDeviceIdle(boolean prefersDeviceIdle) { - mPreferredConstraintFlags = (mPreferredConstraintFlags & ~CONSTRAINT_FLAG_DEVICE_IDLE) - | (prefersDeviceIdle ? CONSTRAINT_FLAG_DEVICE_IDLE : 0); - return this; - } - - /** * Specify that to run this job, the device must be charging (or be a * non-battery-powered device connected to permanent power, such as Android TV * devices). This defaults to {@code false}. Setting this to {@code false} <b>DOES NOT</b> @@ -2306,29 +2175,6 @@ public class JobInfo implements Parcelable { } } - if ((constraintFlags & mPreferredConstraintFlags) != 0) { - // Something is marked as both preferred and required. Try to give a clear exception - // reason. - if ((constraintFlags & CONSTRAINT_FLAG_BATTERY_NOT_LOW) != 0 - && (mPreferredConstraintFlags & CONSTRAINT_FLAG_BATTERY_NOT_LOW) != 0) { - throw new IllegalArgumentException( - "battery-not-low constraint cannot be both preferred and required"); - } - if ((constraintFlags & CONSTRAINT_FLAG_CHARGING) != 0 - && (mPreferredConstraintFlags & CONSTRAINT_FLAG_CHARGING) != 0) { - throw new IllegalArgumentException( - "charging constraint cannot be both preferred and required"); - } - if ((constraintFlags & CONSTRAINT_FLAG_DEVICE_IDLE) != 0 - && (mPreferredConstraintFlags & CONSTRAINT_FLAG_DEVICE_IDLE) != 0) { - throw new IllegalArgumentException( - "device idle constraint cannot be both preferred and required"); - } - // Couldn't figure out what the overlap was. Just use a generic message. - throw new IllegalArgumentException( - "constraints cannot be both preferred and required"); - } - if (isUserInitiated) { if (hasEarlyConstraint) { throw new IllegalArgumentException("A user-initiated job cannot have a time delay"); @@ -2346,8 +2192,7 @@ public class JobInfo implements Parcelable { if (mPriority != PRIORITY_MAX) { throw new IllegalArgumentException("A user-initiated job must be max priority."); } - if ((constraintFlags & CONSTRAINT_FLAG_DEVICE_IDLE) != 0 - || (mPreferredConstraintFlags & CONSTRAINT_FLAG_DEVICE_IDLE) != 0) { + if ((constraintFlags & CONSTRAINT_FLAG_DEVICE_IDLE) != 0) { throw new IllegalArgumentException( "A user-initiated job cannot have a device-idle constraint"); } 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 1287cb4bb952..23b36e20b174 100644 --- a/apex/jobscheduler/service/java/com/android/server/job/JobSchedulerService.java +++ b/apex/jobscheduler/service/java/com/android/server/job/JobSchedulerService.java @@ -1820,7 +1820,11 @@ public class JobSchedulerService extends com.android.server.SystemService jobStatus.getEstimatedNetworkUploadBytes(), jobStatus.getWorkCount(), ActivityManager.processStateAmToProto(mUidProcStates.get(jobStatus.getUid())), - jobStatus.getNamespaceHash()); + jobStatus.getNamespaceHash(), + /* system_measured_source_download_bytes */0, + /* system_measured_source_upload_bytes */ 0, + /* system_measured_calling_download_bytes */0, + /* system_measured_calling_upload_bytes */ 0); // If the job is immediately ready to run, then we can just immediately // put it in the pending list and try to schedule it. This is especially @@ -2257,7 +2261,11 @@ public class JobSchedulerService extends com.android.server.SystemService cancelled.getEstimatedNetworkUploadBytes(), cancelled.getWorkCount(), ActivityManager.processStateAmToProto(mUidProcStates.get(cancelled.getUid())), - cancelled.getNamespaceHash()); + cancelled.getNamespaceHash(), + /* system_measured_source_download_bytes */ 0, + /* system_measured_source_upload_bytes */ 0, + /* system_measured_calling_download_bytes */0, + /* system_measured_calling_upload_bytes */ 0); } // If this is a replacement, bring in the new version of the job if (incomingJob != null) { diff --git a/apex/jobscheduler/service/java/com/android/server/job/JobServiceContext.java b/apex/jobscheduler/service/java/com/android/server/job/JobServiceContext.java index 79653f0e0a91..2d49cfb3b171 100644 --- a/apex/jobscheduler/service/java/com/android/server/job/JobServiceContext.java +++ b/apex/jobscheduler/service/java/com/android/server/job/JobServiceContext.java @@ -45,6 +45,7 @@ import android.content.Intent; import android.content.PermissionChecker; import android.content.ServiceConnection; import android.net.Network; +import android.net.TrafficStats; import android.net.Uri; import android.os.Binder; import android.os.Build; @@ -241,6 +242,14 @@ public final class JobServiceContext implements ServiceConnection { private int mDeathMarkInternalStopReason; private String mDeathMarkDebugReason; + private long mInitialDownloadedBytesFromSource; + + private long mInitialUploadedBytesFromSource; + + private long mInitialDownloadedBytesFromCalling; + + private long mInitialUploadedBytesFromCalling; + // Debugging: reason this job was last stopped. public String mStoppedReason; @@ -472,6 +481,14 @@ public final class JobServiceContext implements ServiceConnection { } mJobPackageTracker.noteActive(job); final int sourceUid = job.getSourceUid(); + + // Measure UID baseline traffic for deltas + mInitialDownloadedBytesFromSource = TrafficStats.getUidRxBytes(sourceUid); + mInitialUploadedBytesFromSource = TrafficStats.getUidTxBytes(sourceUid); + + mInitialDownloadedBytesFromCalling = TrafficStats.getUidRxBytes(job.getUid()); + mInitialUploadedBytesFromCalling = TrafficStats.getUidTxBytes(job.getUid()); + FrameworkStatsLog.write(FrameworkStatsLog.SCHEDULED_JOB_STATE_CHANGED, job.isProxyJob() ? new int[]{sourceUid, job.getUid()} : new int[]{sourceUid}, // Given that the source tag is set by the calling app, it should be connected @@ -517,7 +534,11 @@ public final class JobServiceContext implements ServiceConnection { job.getEstimatedNetworkUploadBytes(), job.getWorkCount(), ActivityManager.processStateAmToProto(mService.getUidProcState(job.getUid())), - job.getNamespaceHash()); + job.getNamespaceHash(), + /* system_measured_source_download_bytes */ 0, + /* system_measured_source_upload_bytes */ 0, + /* system_measured_calling_download_bytes */ 0, + /* system_measured_calling_upload_bytes */ 0); sEnqueuedJwiAtJobStart.logSampleWithUid(job.getUid(), job.getWorkCount()); final String sourcePackage = job.getSourcePackageName(); if (Trace.isTagEnabled(Trace.TRACE_TAG_SYSTEM_SERVER)) { @@ -1586,7 +1607,15 @@ public final class JobServiceContext implements ServiceConnection { completedJob.getWorkCount(), ActivityManager .processStateAmToProto(mService.getUidProcState(completedJob.getUid())), - completedJob.getNamespaceHash()); + completedJob.getNamespaceHash(), + TrafficStats.getUidRxBytes(completedJob.getSourceUid()) + - mInitialDownloadedBytesFromSource, + TrafficStats.getUidTxBytes(completedJob.getSourceUid()) + - mInitialUploadedBytesFromSource, + TrafficStats.getUidRxBytes(completedJob.getUid()) + - mInitialDownloadedBytesFromCalling, + TrafficStats.getUidTxBytes(completedJob.getUid()) + - mInitialUploadedBytesFromCalling); if (Trace.isTagEnabled(Trace.TRACE_TAG_SYSTEM_SERVER)) { Trace.asyncTraceForTrackEnd(Trace.TRACE_TAG_SYSTEM_SERVER, "JobScheduler", getId()); diff --git a/apex/jobscheduler/service/java/com/android/server/job/JobStore.java b/apex/jobscheduler/service/java/com/android/server/job/JobStore.java index 1fdf906fd4ea..d466f0d8912c 100644 --- a/apex/jobscheduler/service/java/com/android/server/job/JobStore.java +++ b/apex/jobscheduler/service/java/com/android/server/job/JobStore.java @@ -938,15 +938,6 @@ public final class JobStore { if (job.isRequireStorageNotLow()) { out.attribute(null, "storage-not-low", Boolean.toString(true)); } - if (job.isPreferBatteryNotLow()) { - out.attributeBoolean(null, "prefer-battery-not-low", true); - } - if (job.isPreferCharging()) { - out.attributeBoolean(null, "prefer-charging", true); - } - if (job.isPreferDeviceIdle()) { - out.attributeBoolean(null, "prefer-idle", true); - } out.endTag(null, XML_TAG_PARAMS_CONSTRAINTS); } @@ -1638,13 +1629,6 @@ public final class JobStore { if (val != null) { jobBuilder.setRequiresStorageNotLow(true); } - - jobBuilder.setPrefersBatteryNotLow( - parser.getAttributeBoolean(null, "prefer-battery-not-low", false)); - jobBuilder.setPrefersCharging( - parser.getAttributeBoolean(null, "prefer-charging", false)); - jobBuilder.setPrefersDeviceIdle( - parser.getAttributeBoolean(null, "prefer-idle", false)); } /** diff --git a/apex/jobscheduler/service/java/com/android/server/job/controllers/ConnectivityController.java b/apex/jobscheduler/service/java/com/android/server/job/controllers/ConnectivityController.java index 63eaa63db72e..ae4e99cfeef3 100644 --- a/apex/jobscheduler/service/java/com/android/server/job/controllers/ConnectivityController.java +++ b/apex/jobscheduler/service/java/com/android/server/job/controllers/ConnectivityController.java @@ -1263,9 +1263,10 @@ public final class ConnectivityController extends RestrictingController implemen final boolean changed = jobStatus.setConnectivityConstraintSatisfied(nowElapsed, satisfied); - jobStatus.setHasAccessToUnmetered(satisfied && capabilities != null - && capabilities.hasCapability(NET_CAPABILITY_NOT_METERED)); if (jobStatus.getPreferUnmetered()) { + jobStatus.setHasAccessToUnmetered(satisfied && capabilities != null + && capabilities.hasCapability(NET_CAPABILITY_NOT_METERED)); + jobStatus.setFlexibilityConstraintSatisfied(nowElapsed, mFlexibilityController.isFlexibilitySatisfiedLocked(jobStatus)); } diff --git a/apex/jobscheduler/service/java/com/android/server/job/controllers/FlexibilityController.java b/apex/jobscheduler/service/java/com/android/server/job/controllers/FlexibilityController.java index b9e3b76b0279..0e03ea1ebe7d 100644 --- a/apex/jobscheduler/service/java/com/android/server/job/controllers/FlexibilityController.java +++ b/apex/jobscheduler/service/java/com/android/server/job/controllers/FlexibilityController.java @@ -252,15 +252,15 @@ public final class FlexibilityController extends StateController { boolean isFlexibilitySatisfiedLocked(JobStatus js) { return !mFlexibilityEnabled || mService.getUidBias(js.getSourceUid()) == JobInfo.BIAS_TOP_APP - || getNumSatisfiedFlexibleConstraintsLocked(js) + || getNumSatisfiedRequiredConstraintsLocked(js) >= js.getNumRequiredFlexibleConstraints() || mService.isCurrentlyRunningLocked(js); } @VisibleForTesting @GuardedBy("mLock") - int getNumSatisfiedFlexibleConstraintsLocked(JobStatus js) { - return Integer.bitCount(mSatisfiedFlexibleConstraints & js.getPreferredConstraintFlags()) + int getNumSatisfiedRequiredConstraintsLocked(JobStatus js) { + return Integer.bitCount(mSatisfiedFlexibleConstraints) // Connectivity is job-specific, so must be handled separately. + (js.getHasAccessToUnmetered() ? 1 : 0); } 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 1fb54d59179b..cb6cc2bd58aa 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 @@ -16,6 +16,7 @@ package com.android.server.job.controllers; +import static android.net.NetworkCapabilities.NET_CAPABILITY_NOT_METERED; import static android.text.format.DateUtils.HOUR_IN_MILLIS; import static com.android.server.job.JobSchedulerService.ACTIVE_INDEX; @@ -24,6 +25,8 @@ import static com.android.server.job.JobSchedulerService.NEVER_INDEX; import static com.android.server.job.JobSchedulerService.RESTRICTED_INDEX; import static com.android.server.job.JobSchedulerService.WORKING_INDEX; import static com.android.server.job.JobSchedulerService.sElapsedRealtimeClock; +import static com.android.server.job.controllers.FlexibilityController.NUM_SYSTEM_WIDE_FLEXIBLE_CONSTRAINTS; +import static com.android.server.job.controllers.FlexibilityController.SYSTEM_WIDE_FLEXIBLE_CONSTRAINTS; import android.annotation.ElapsedRealtimeLong; import android.annotation.NonNull; @@ -124,11 +127,12 @@ public final class JobStatus { static final int CONSTRAINT_WITHIN_QUOTA = 1 << 24; // Implicit constraint static final int CONSTRAINT_PREFETCH = 1 << 23; static final int CONSTRAINT_BACKGROUND_NOT_RESTRICTED = 1 << 22; // Implicit constraint - static final int CONSTRAINT_FLEXIBLE = 1 << 21; + static final int CONSTRAINT_FLEXIBLE = 1 << 21; // Implicit constraint private static final int IMPLICIT_CONSTRAINTS = 0 | CONSTRAINT_BACKGROUND_NOT_RESTRICTED | CONSTRAINT_DEVICE_NOT_DOZING + | CONSTRAINT_FLEXIBLE | CONSTRAINT_TARE_WEALTH | CONSTRAINT_WITHIN_QUOTA; @@ -323,7 +327,6 @@ public final class JobStatus { // Constraints. final int requiredConstraints; - private final int mPreferredConstraints; private final int mRequiredConstraintsOfInterest; int satisfiedConstraints = 0; private int mSatisfiedConstraintsOfInterest = 0; @@ -668,26 +671,24 @@ public final class JobStatus { } mHasExemptedMediaUrisOnly = exemptedMediaUrisOnly; - mPreferredConstraints = job.getPreferredConstraintFlags(); - - // Exposing a preferredNetworkRequest API requires that we make sure that the preferred - // NetworkRequest is a subset of the required NetworkRequest. We currently don't have the - // code to ensure that, so disable this part for now. - // TODO(236261941): look into enabling flexible network constraint requests - mPreferUnmetered = false; - // && job.getRequiredNetwork() != null - // && !job.getRequiredNetwork().hasCapability(NET_CAPABILITY_NOT_METERED); + mPreferUnmetered = job.getRequiredNetwork() != null + && !job.getRequiredNetwork().hasCapability(NET_CAPABILITY_NOT_METERED); + final boolean lacksSomeFlexibleConstraints = + ((~requiredConstraints) & SYSTEM_WIDE_FLEXIBLE_CONSTRAINTS) != 0 + || mPreferUnmetered; final boolean satisfiesMinWindowException = (latestRunTimeElapsedMillis - earliestRunTimeElapsedMillis) >= MIN_WINDOW_FOR_FLEXIBILITY_MS; // The first time a job is rescheduled it will not be subject to flexible constraints. // Otherwise, every consecutive reschedule increases a jobs' flexibility deadline. - if (mPreferredConstraints != 0 && !isRequestedExpeditedJob() && !job.isUserInitiated() + if (!isRequestedExpeditedJob() && !job.isUserInitiated() && satisfiesMinWindowException - && (numFailures + numSystemStops) != 1) { - mNumRequiredFlexibleConstraints = Integer.bitCount(mPreferredConstraints); + && (numFailures + numSystemStops) != 1 + && lacksSomeFlexibleConstraints) { + mNumRequiredFlexibleConstraints = + NUM_SYSTEM_WIDE_FLEXIBLE_CONSTRAINTS + (mPreferUnmetered ? 1 : 0); requiredConstraints |= CONSTRAINT_FLEXIBLE; } else { mNumRequiredFlexibleConstraints = 0; @@ -1393,10 +1394,6 @@ public final class JobStatus { mInternalFlags = mInternalFlags & ~flags; } - int getPreferredConstraintFlags() { - return mPreferredConstraints; - } - public int getSatisfiedConstraintFlags() { return satisfiedConstraints; } @@ -2778,9 +2775,6 @@ public final class JobStatus { pw.print("Required constraints:"); dumpConstraints(pw, requiredConstraints); pw.println(); - pw.print("Preferred constraints:"); - dumpConstraints(pw, mPreferredConstraints); - pw.println(); pw.print("Dynamic constraints:"); dumpConstraints(pw, mDynamicConstraints); pw.println(); diff --git a/api/Android.bp b/api/Android.bp index d11ea7b26d29..de4435ebe4dd 100644 --- a/api/Android.bp +++ b/api/Android.bp @@ -251,6 +251,152 @@ java_genrule { cmd: "cat $(in) | md5sum | cut -d' ' -f1 > $(out)", } +packages_to_document = [ + "android", + "dalvik", + "java", + "javax", + "junit", + "org.apache.http", + "org.json", + "org.w3c.dom", + "org.xml.sax", + "org.xmlpull", +] + +// Defaults for all stubs that include the non-updatable framework. These defaults do not include +// module symbols, so will not compile correctly on their own. Users must add module APIs to the +// classpath (or sources) somehow. +stubs_defaults { + name: "android-non-updatable-stubs-defaults", + srcs: [":android-non-updatable-stub-sources"], + sdk_version: "none", + system_modules: "none", + java_version: "1.8", + arg_files: [":frameworks-base-core-AndroidManifest.xml"], + aidl: { + include_dirs: [ + "frameworks/av/aidl", + "frameworks/base/media/aidl", + "frameworks/base/telephony/java", + "frameworks/native/libs/permission/aidl", + "packages/modules/Bluetooth/framework/aidl-export", + "packages/modules/Connectivity/framework/aidl-export", + "packages/modules/Media/apex/aidl/stable", + "hardware/interfaces/biometrics/common/aidl", + "hardware/interfaces/biometrics/fingerprint/aidl", + "hardware/interfaces/graphics/common/aidl", + "hardware/interfaces/keymaster/aidl", + "system/hardware/interfaces/media/aidl", + ], + }, + // These are libs from framework-internal-utils that are required (i.e. being referenced) + // from framework-non-updatable-sources. Add more here when there's a need. + // DO NOT add the entire framework-internal-utils. It might cause unnecessary circular + // dependencies gets bigger. + libs: [ + "android.hardware.cas-V1.2-java", + "android.hardware.health-V1.0-java-constants", + "android.hardware.thermal-V1.0-java-constants", + "android.hardware.thermal-V2.0-java", + "android.hardware.tv.input-V1.0-java-constants", + "android.hardware.usb-V1.0-java-constants", + "android.hardware.usb-V1.1-java-constants", + "android.hardware.usb.gadget-V1.0-java", + "android.hardware.vibrator-V1.3-java", + "framework-protos", + ], + flags: [ + "--api-lint-ignore-prefix android.icu.", + "--api-lint-ignore-prefix java.", + "--api-lint-ignore-prefix junit.", + "--api-lint-ignore-prefix org.", + "--error NoSettingsProvider", + "--error UnhiddenSystemApi", + "--error UnflaggedApi", + "--force-convert-to-warning-nullability-annotations +*:-android.*:+android.icu.*:-dalvik.*", + // Disable CallbackInterface, as Java 8 default interface methods avoid the extensibility + // issue interfaces had previously. + "--hide CallbackInterface", + // Disable HiddenSuperclass, as Metalava handles this fine (it should be hidden by default) + "--hide HiddenSuperclass", + "--hide-package android.audio.policy.configuration.V7_0", + "--hide-package com.android.server", + "--manifest $(location :frameworks-base-core-AndroidManifest.xml)", + ], + filter_packages: packages_to_document, + high_mem: true, // Lots of sources => high memory use, see b/170701554 + installable: false, + annotations_enabled: true, + previous_api: ":android.api.public.latest", + merge_annotations_dirs: ["metalava-manual"], + defaults_visibility: ["//frameworks/base/api"], + visibility: ["//frameworks/base/api"], +} + +// Defaults with module APIs in the classpath (mostly from prebuilts). +// Suitable for compiling android-non-updatable. +stubs_defaults { + name: "module-classpath-stubs-defaults", + aidl: { + include_dirs: [ + "packages/modules/Bluetooth/framework/aidl-export", + "packages/modules/Connectivity/framework/aidl-export", + "packages/modules/Media/apex/aidl/stable", + ], + }, + libs: [ + "art.module.public.api", + "sdk_module-lib_current_framework-tethering", + "sdk_module-lib_current_framework-connectivity-t", + "sdk_public_current_framework-bluetooth", + // There are a few classes from modules used by the core that + // need to be resolved by metalava. We use a prebuilt stub of the + // full sdk to ensure we can resolve them. If a new class gets added, + // the prebuilts/sdk/current needs to be updated. + "sdk_system_current_android", + // NOTE: The below can be removed once the prebuilt stub contains IKE. + "sdk_system_current_android.net.ipsec.ike", + ], +} + +// Defaults for the java_sdk_libraries of unbundled jars from framework. +// java_sdk_libraries using these defaults should also add themselves to the +// non_updatable_modules list in frameworks/base/api/api.go +java_defaults { + name: "framework-non-updatable-unbundled-defaults", + defaults: [ + "framework-non-updatable-lint-defaults", + "non-updatable-framework-module-defaults", + ], + public: { + libs: ["android_module_lib_stubs_current"], + }, + system: { + libs: ["android_module_lib_stubs_current"], + }, + module_lib: { + libs: ["android_module_lib_stubs_current"], + }, + test: { + libs: ["android_test_frameworks_core_stubs_current"], + }, + sdk_version: "core_platform", + stub_only_libs: ["framework-protos"], + impl_only_libs: ["framework-minus-apex-headers"], // the framework, including hidden API + impl_library_visibility: ["//frameworks/base"], + defaults_visibility: ["//frameworks/base/location"], + plugins: ["error_prone_android_framework"], + errorprone: { + javacflags: [ + "-Xep:AndroidFrameworkCompatChange:ERROR", + "-Xep:AndroidFrameworkUid:ERROR", + ], + }, + // Include manual annotations in API txt files + merge_annotations_dirs: ["metalava-manual"], +} + build = [ "ApiDocs.bp", "StubLibraries.bp", diff --git a/api/ApiDocs.bp b/api/ApiDocs.bp index 5744bdfd4b28..bcfb68ffd04d 100644 --- a/api/ApiDocs.bp +++ b/api/ApiDocs.bp @@ -30,6 +30,18 @@ stubs_defaults { ":android-test-mock-sources", ":android-test-runner-sources", ], + flags: [ + // These errors are suppressed in the doc stubs as it isn't easy to suppress them. + // They remain unsuppressed/active in the "main" stubs build (the jar stubs). + // These can be removed when either a) all the issues have been fixed or + // b) these reporting of these issues is gated behind api lint being enabled in metalava. + "--hide BroadcastBehavior", + "--hide DeprecationMismatch", + "--hide MissingPermission", + "--hide RequiresPermission", + "--hide SdkConstant", + "--hide Todo", + ], create_doc_stubs: true, write_sdk_values: true, } diff --git a/core/api/current.txt b/core/api/current.txt index 99624695132e..c362e951e9b7 100644 --- a/core/api/current.txt +++ b/core/api/current.txt @@ -6727,7 +6727,7 @@ package android.app { field protected android.app.Notification.Builder mBuilder; } - public static final class Notification.TvExtender implements android.app.Notification.Extender { + @FlaggedApi("android.app.api_tvextender") public static final class Notification.TvExtender implements android.app.Notification.Extender { ctor public Notification.TvExtender(); ctor public Notification.TvExtender(@NonNull android.app.Notification); method @NonNull public android.app.Notification.Builder extend(@NonNull android.app.Notification.Builder); @@ -23842,14 +23842,14 @@ package android.media { 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 public static final int TYPE_REMOTE_AUDIO_VIDEO_RECEIVER = 1003; // 0x3eb - field public static final int TYPE_REMOTE_CAR = 1008; // 0x3f0 - field public static final int TYPE_REMOTE_COMPUTER = 1006; // 0x3ee - field public static final int TYPE_REMOTE_GAME_CONSOLE = 1007; // 0x3ef - field public static final int TYPE_REMOTE_SMARTPHONE = 1010; // 0x3f2 - field public static final int TYPE_REMOTE_SMARTWATCH = 1009; // 0x3f1 + field @FlaggedApi("com.android.media.flags.enable_new_media_route_2_info_types") public static final int TYPE_REMOTE_CAR = 1008; // 0x3f0 + field @FlaggedApi("com.android.media.flags.enable_new_media_route_2_info_types") public static final int TYPE_REMOTE_COMPUTER = 1006; // 0x3ee + field @FlaggedApi("com.android.media.flags.enable_new_media_route_2_info_types") public static final int TYPE_REMOTE_GAME_CONSOLE = 1007; // 0x3ef + field @FlaggedApi("com.android.media.flags.enable_new_media_route_2_info_types") public static final int TYPE_REMOTE_SMARTPHONE = 1010; // 0x3f2 + field @FlaggedApi("com.android.media.flags.enable_new_media_route_2_info_types") public static final int TYPE_REMOTE_SMARTWATCH = 1009; // 0x3f1 field public static final int TYPE_REMOTE_SPEAKER = 1002; // 0x3ea - field public static final int TYPE_REMOTE_TABLET = 1004; // 0x3ec - field public static final int TYPE_REMOTE_TABLET_DOCKED = 1005; // 0x3ed + field @FlaggedApi("com.android.media.flags.enable_new_media_route_2_info_types") public static final int TYPE_REMOTE_TABLET = 1004; // 0x3ec + field @FlaggedApi("com.android.media.flags.enable_new_media_route_2_info_types") public static final int TYPE_REMOTE_TABLET_DOCKED = 1005; // 0x3ed field public static final int TYPE_REMOTE_TV = 1001; // 0x3e9 field public static final int TYPE_UNKNOWN = 0; // 0x0 field public static final int TYPE_USB_ACCESSORY = 12; // 0xc @@ -42599,6 +42599,7 @@ package android.telecom { field public static final String EXTRA_CALL_DISCONNECT_CAUSE = "android.telecom.extra.CALL_DISCONNECT_CAUSE"; field public static final String EXTRA_CALL_DISCONNECT_MESSAGE = "android.telecom.extra.CALL_DISCONNECT_MESSAGE"; field public static final String EXTRA_CALL_DURATION = "android.telecom.extra.CALL_DURATION"; + field @FlaggedApi("com.android.server.telecom.flags.add_call_uri_for_missed_calls") public static final String EXTRA_CALL_LOG_URI = "android.telecom.extra.CALL_LOG_URI"; field public static final String EXTRA_CALL_NETWORK_TYPE = "android.telecom.extra.CALL_NETWORK_TYPE"; field public static final String EXTRA_CALL_SUBJECT = "android.telecom.extra.CALL_SUBJECT"; field public static final String EXTRA_CHANGE_DEFAULT_DIALER_PACKAGE_NAME = "android.telecom.extra.CHANGE_DEFAULT_DIALER_PACKAGE_NAME"; @@ -45537,6 +45538,7 @@ package android.telephony { field public static final int PURCHASE_PREMIUM_CAPABILITY_RESULT_THROTTLED = 2; // 0x2 field public static final int PURCHASE_PREMIUM_CAPABILITY_RESULT_TIMEOUT = 9; // 0x9 field public static final int PURCHASE_PREMIUM_CAPABILITY_RESULT_USER_CANCELED = 6; // 0x6 + field @FlaggedApi("com.android.internal.telephony.flags.slicing_additional_error_codes") public static final int PURCHASE_PREMIUM_CAPABILITY_RESULT_USER_DISABLED = 16; // 0x10 field public static final int SET_OPPORTUNISTIC_SUB_INACTIVE_SUBSCRIPTION = 2; // 0x2 field public static final int SET_OPPORTUNISTIC_SUB_NO_OPPORTUNISTIC_SUB_AVAILABLE = 3; // 0x3 field public static final int SET_OPPORTUNISTIC_SUB_REMOTE_SERVICE_EXCEPTION = 4; // 0x4 diff --git a/core/api/lint-baseline.txt b/core/api/lint-baseline.txt index afb10f5f234a..1e6aa498f417 100644 --- a/core/api/lint-baseline.txt +++ b/core/api/lint-baseline.txt @@ -1,4 +1,1168 @@ // Baseline format: 1.0 +BroadcastBehavior: android.app.AlarmManager#ACTION_NEXT_ALARM_CLOCK_CHANGED: + Field 'ACTION_NEXT_ALARM_CLOCK_CHANGED' is missing @BroadcastBehavior +BroadcastBehavior: android.app.AlarmManager#ACTION_SCHEDULE_EXACT_ALARM_PERMISSION_STATE_CHANGED: + Field 'ACTION_SCHEDULE_EXACT_ALARM_PERMISSION_STATE_CHANGED' is missing @BroadcastBehavior +BroadcastBehavior: android.app.admin.DevicePolicyManager#ACTION_APPLICATION_DELEGATION_SCOPES_CHANGED: + Field 'ACTION_APPLICATION_DELEGATION_SCOPES_CHANGED' is missing @BroadcastBehavior +BroadcastBehavior: android.app.admin.DevicePolicyManager#ACTION_MANAGED_PROFILE_PROVISIONED: + Field 'ACTION_MANAGED_PROFILE_PROVISIONED' is missing @BroadcastBehavior +BroadcastBehavior: android.content.Intent#ACTION_AIRPLANE_MODE_CHANGED: + Field 'ACTION_AIRPLANE_MODE_CHANGED' is missing @BroadcastBehavior +BroadcastBehavior: android.content.Intent#ACTION_APPLICATION_LOCALE_CHANGED: + Field 'ACTION_APPLICATION_LOCALE_CHANGED' is missing @BroadcastBehavior +BroadcastBehavior: android.content.Intent#ACTION_APPLICATION_RESTRICTIONS_CHANGED: + Field 'ACTION_APPLICATION_RESTRICTIONS_CHANGED' is missing @BroadcastBehavior +BroadcastBehavior: android.content.Intent#ACTION_BATTERY_CHANGED: + Field 'ACTION_BATTERY_CHANGED' is missing @BroadcastBehavior +BroadcastBehavior: android.content.Intent#ACTION_BATTERY_LOW: + Field 'ACTION_BATTERY_LOW' is missing @BroadcastBehavior +BroadcastBehavior: android.content.Intent#ACTION_BATTERY_OKAY: + Field 'ACTION_BATTERY_OKAY' is missing @BroadcastBehavior +BroadcastBehavior: android.content.Intent#ACTION_CAMERA_BUTTON: + Field 'ACTION_CAMERA_BUTTON' is missing @BroadcastBehavior +BroadcastBehavior: android.content.Intent#ACTION_CLOSE_SYSTEM_DIALOGS: + Field 'ACTION_CLOSE_SYSTEM_DIALOGS' is missing @BroadcastBehavior +BroadcastBehavior: android.content.Intent#ACTION_CONFIGURATION_CHANGED: + Field 'ACTION_CONFIGURATION_CHANGED' is missing @BroadcastBehavior +BroadcastBehavior: android.content.Intent#ACTION_DATE_CHANGED: + Field 'ACTION_DATE_CHANGED' is missing @BroadcastBehavior +BroadcastBehavior: android.content.Intent#ACTION_DEVICE_STORAGE_LOW: + Field 'ACTION_DEVICE_STORAGE_LOW' is missing @BroadcastBehavior +BroadcastBehavior: android.content.Intent#ACTION_DEVICE_STORAGE_OK: + Field 'ACTION_DEVICE_STORAGE_OK' is missing @BroadcastBehavior +BroadcastBehavior: android.content.Intent#ACTION_DOCK_EVENT: + Field 'ACTION_DOCK_EVENT' is missing @BroadcastBehavior +BroadcastBehavior: android.content.Intent#ACTION_DREAMING_STARTED: + Field 'ACTION_DREAMING_STARTED' is missing @BroadcastBehavior +BroadcastBehavior: android.content.Intent#ACTION_DREAMING_STOPPED: + Field 'ACTION_DREAMING_STOPPED' is missing @BroadcastBehavior +BroadcastBehavior: android.content.Intent#ACTION_EXTERNAL_APPLICATIONS_AVAILABLE: + Field 'ACTION_EXTERNAL_APPLICATIONS_AVAILABLE' is missing @BroadcastBehavior +BroadcastBehavior: android.content.Intent#ACTION_EXTERNAL_APPLICATIONS_UNAVAILABLE: + Field 'ACTION_EXTERNAL_APPLICATIONS_UNAVAILABLE' is missing @BroadcastBehavior +BroadcastBehavior: android.content.Intent#ACTION_GTALK_SERVICE_CONNECTED: + Field 'ACTION_GTALK_SERVICE_CONNECTED' is missing @BroadcastBehavior +BroadcastBehavior: android.content.Intent#ACTION_GTALK_SERVICE_DISCONNECTED: + Field 'ACTION_GTALK_SERVICE_DISCONNECTED' is missing @BroadcastBehavior +BroadcastBehavior: android.content.Intent#ACTION_HEADSET_PLUG: + Field 'ACTION_HEADSET_PLUG' is missing @BroadcastBehavior +BroadcastBehavior: android.content.Intent#ACTION_INPUT_METHOD_CHANGED: + Field 'ACTION_INPUT_METHOD_CHANGED' is missing @BroadcastBehavior +BroadcastBehavior: android.content.Intent#ACTION_LOCALE_CHANGED: + Field 'ACTION_LOCALE_CHANGED' is missing @BroadcastBehavior +BroadcastBehavior: android.content.Intent#ACTION_LOCKED_BOOT_COMPLETED: + Field 'ACTION_LOCKED_BOOT_COMPLETED' is missing @BroadcastBehavior +BroadcastBehavior: android.content.Intent#ACTION_MANAGE_PACKAGE_STORAGE: + Field 'ACTION_MANAGE_PACKAGE_STORAGE' is missing @BroadcastBehavior +BroadcastBehavior: android.content.Intent#ACTION_MEDIA_BAD_REMOVAL: + Field 'ACTION_MEDIA_BAD_REMOVAL' is missing @BroadcastBehavior +BroadcastBehavior: android.content.Intent#ACTION_MEDIA_BUTTON: + Field 'ACTION_MEDIA_BUTTON' is missing @BroadcastBehavior +BroadcastBehavior: android.content.Intent#ACTION_MEDIA_CHECKING: + Field 'ACTION_MEDIA_CHECKING' is missing @BroadcastBehavior +BroadcastBehavior: android.content.Intent#ACTION_MEDIA_EJECT: + Field 'ACTION_MEDIA_EJECT' is missing @BroadcastBehavior +BroadcastBehavior: android.content.Intent#ACTION_MEDIA_MOUNTED: + Field 'ACTION_MEDIA_MOUNTED' is missing @BroadcastBehavior +BroadcastBehavior: android.content.Intent#ACTION_MEDIA_NOFS: + Field 'ACTION_MEDIA_NOFS' is missing @BroadcastBehavior +BroadcastBehavior: android.content.Intent#ACTION_MEDIA_REMOVED: + Field 'ACTION_MEDIA_REMOVED' is missing @BroadcastBehavior +BroadcastBehavior: android.content.Intent#ACTION_MEDIA_SCANNER_FINISHED: + Field 'ACTION_MEDIA_SCANNER_FINISHED' is missing @BroadcastBehavior +BroadcastBehavior: android.content.Intent#ACTION_MEDIA_SCANNER_SCAN_FILE: + Field 'ACTION_MEDIA_SCANNER_SCAN_FILE' is missing @BroadcastBehavior +BroadcastBehavior: android.content.Intent#ACTION_MEDIA_SCANNER_STARTED: + Field 'ACTION_MEDIA_SCANNER_STARTED' is missing @BroadcastBehavior +BroadcastBehavior: android.content.Intent#ACTION_MEDIA_SHARED: + Field 'ACTION_MEDIA_SHARED' is missing @BroadcastBehavior +BroadcastBehavior: android.content.Intent#ACTION_MEDIA_UNMOUNTABLE: + Field 'ACTION_MEDIA_UNMOUNTABLE' is missing @BroadcastBehavior +BroadcastBehavior: android.content.Intent#ACTION_MEDIA_UNMOUNTED: + Field 'ACTION_MEDIA_UNMOUNTED' is missing @BroadcastBehavior +BroadcastBehavior: android.content.Intent#ACTION_MY_PACKAGE_REPLACED: + Field 'ACTION_MY_PACKAGE_REPLACED' is missing @BroadcastBehavior +BroadcastBehavior: android.content.Intent#ACTION_MY_PACKAGE_SUSPENDED: + Field 'ACTION_MY_PACKAGE_SUSPENDED' is missing @BroadcastBehavior +BroadcastBehavior: android.content.Intent#ACTION_MY_PACKAGE_UNSUSPENDED: + Field 'ACTION_MY_PACKAGE_UNSUSPENDED' is missing @BroadcastBehavior +BroadcastBehavior: android.content.Intent#ACTION_NEW_OUTGOING_CALL: + Field 'ACTION_NEW_OUTGOING_CALL' is missing @BroadcastBehavior +BroadcastBehavior: android.content.Intent#ACTION_PACKAGES_SUSPENDED: + Field 'ACTION_PACKAGES_SUSPENDED' is missing @BroadcastBehavior +BroadcastBehavior: android.content.Intent#ACTION_PACKAGES_UNSUSPENDED: + Field 'ACTION_PACKAGES_UNSUSPENDED' is missing @BroadcastBehavior +BroadcastBehavior: android.content.Intent#ACTION_PACKAGE_ADDED: + Field 'ACTION_PACKAGE_ADDED' is missing @BroadcastBehavior +BroadcastBehavior: android.content.Intent#ACTION_PACKAGE_CHANGED: + Field 'ACTION_PACKAGE_CHANGED' is missing @BroadcastBehavior +BroadcastBehavior: android.content.Intent#ACTION_PACKAGE_DATA_CLEARED: + Field 'ACTION_PACKAGE_DATA_CLEARED' is missing @BroadcastBehavior +BroadcastBehavior: android.content.Intent#ACTION_PACKAGE_FIRST_LAUNCH: + Field 'ACTION_PACKAGE_FIRST_LAUNCH' is missing @BroadcastBehavior +BroadcastBehavior: android.content.Intent#ACTION_PACKAGE_FULLY_REMOVED: + Field 'ACTION_PACKAGE_FULLY_REMOVED' is missing @BroadcastBehavior +BroadcastBehavior: android.content.Intent#ACTION_PACKAGE_INSTALL: + Field 'ACTION_PACKAGE_INSTALL' is missing @BroadcastBehavior +BroadcastBehavior: android.content.Intent#ACTION_PACKAGE_NEEDS_VERIFICATION: + Field 'ACTION_PACKAGE_NEEDS_VERIFICATION' is missing @BroadcastBehavior +BroadcastBehavior: android.content.Intent#ACTION_PACKAGE_REMOVED: + Field 'ACTION_PACKAGE_REMOVED' is missing @BroadcastBehavior +BroadcastBehavior: android.content.Intent#ACTION_PACKAGE_REPLACED: + Field 'ACTION_PACKAGE_REPLACED' is missing @BroadcastBehavior +BroadcastBehavior: android.content.Intent#ACTION_PACKAGE_RESTARTED: + Field 'ACTION_PACKAGE_RESTARTED' is missing @BroadcastBehavior +BroadcastBehavior: android.content.Intent#ACTION_PACKAGE_UNSTOPPED: + Field 'ACTION_PACKAGE_UNSTOPPED' is missing @BroadcastBehavior +BroadcastBehavior: android.content.Intent#ACTION_PACKAGE_VERIFIED: + Field 'ACTION_PACKAGE_VERIFIED' is missing @BroadcastBehavior +BroadcastBehavior: android.content.Intent#ACTION_POWER_CONNECTED: + Field 'ACTION_POWER_CONNECTED' is missing @BroadcastBehavior +BroadcastBehavior: android.content.Intent#ACTION_POWER_DISCONNECTED: + Field 'ACTION_POWER_DISCONNECTED' is missing @BroadcastBehavior +BroadcastBehavior: android.content.Intent#ACTION_PROVIDER_CHANGED: + Field 'ACTION_PROVIDER_CHANGED' is missing @BroadcastBehavior +BroadcastBehavior: android.content.Intent#ACTION_REBOOT: + Field 'ACTION_REBOOT' is missing @BroadcastBehavior +BroadcastBehavior: android.content.Intent#ACTION_SCREEN_OFF: + Field 'ACTION_SCREEN_OFF' is missing @BroadcastBehavior +BroadcastBehavior: android.content.Intent#ACTION_SCREEN_ON: + Field 'ACTION_SCREEN_ON' is missing @BroadcastBehavior +BroadcastBehavior: android.content.Intent#ACTION_SHUTDOWN: + Field 'ACTION_SHUTDOWN' is missing @BroadcastBehavior +BroadcastBehavior: android.content.Intent#ACTION_TIMEZONE_CHANGED: + Field 'ACTION_TIMEZONE_CHANGED' is missing @BroadcastBehavior +BroadcastBehavior: android.content.Intent#ACTION_TIME_CHANGED: + Field 'ACTION_TIME_CHANGED' is missing @BroadcastBehavior +BroadcastBehavior: android.content.Intent#ACTION_TIME_TICK: + Field 'ACTION_TIME_TICK' is missing @BroadcastBehavior +BroadcastBehavior: android.content.Intent#ACTION_UID_REMOVED: + Field 'ACTION_UID_REMOVED' is missing @BroadcastBehavior +BroadcastBehavior: android.content.Intent#ACTION_UMS_CONNECTED: + Field 'ACTION_UMS_CONNECTED' is missing @BroadcastBehavior +BroadcastBehavior: android.content.Intent#ACTION_UMS_DISCONNECTED: + Field 'ACTION_UMS_DISCONNECTED' is missing @BroadcastBehavior +BroadcastBehavior: android.content.Intent#ACTION_USER_PRESENT: + Field 'ACTION_USER_PRESENT' is missing @BroadcastBehavior +BroadcastBehavior: android.content.Intent#ACTION_USER_UNLOCKED: + Field 'ACTION_USER_UNLOCKED' is missing @BroadcastBehavior +BroadcastBehavior: android.content.Intent#ACTION_WALLPAPER_CHANGED: + Field 'ACTION_WALLPAPER_CHANGED' is missing @BroadcastBehavior +BroadcastBehavior: android.content.pm.PackageInstaller#ACTION_SESSION_COMMITTED: + Field 'ACTION_SESSION_COMMITTED' is missing @BroadcastBehavior +BroadcastBehavior: android.content.pm.PackageInstaller#ACTION_SESSION_UPDATED: + Field 'ACTION_SESSION_UPDATED' is missing @BroadcastBehavior +BroadcastBehavior: android.hardware.Camera#ACTION_NEW_PICTURE: + Field 'ACTION_NEW_PICTURE' is missing @BroadcastBehavior +BroadcastBehavior: android.hardware.Camera#ACTION_NEW_VIDEO: + Field 'ACTION_NEW_VIDEO' is missing @BroadcastBehavior +BroadcastBehavior: android.hardware.input.InputManager#ACTION_QUERY_KEYBOARD_LAYOUTS: + Field 'ACTION_QUERY_KEYBOARD_LAYOUTS' is missing @BroadcastBehavior +BroadcastBehavior: android.hardware.usb.UsbManager#ACTION_USB_ACCESSORY_DETACHED: + Field 'ACTION_USB_ACCESSORY_DETACHED' is missing @BroadcastBehavior +BroadcastBehavior: android.hardware.usb.UsbManager#ACTION_USB_DEVICE_DETACHED: + Field 'ACTION_USB_DEVICE_DETACHED' is missing @BroadcastBehavior +BroadcastBehavior: android.media.AudioManager#ACTION_HDMI_AUDIO_PLUG: + Field 'ACTION_HDMI_AUDIO_PLUG' is missing @BroadcastBehavior +BroadcastBehavior: android.media.AudioManager#ACTION_HEADSET_PLUG: + Field 'ACTION_HEADSET_PLUG' is missing @BroadcastBehavior +BroadcastBehavior: android.media.AudioManager#ACTION_MICROPHONE_MUTE_CHANGED: + Field 'ACTION_MICROPHONE_MUTE_CHANGED' is missing @BroadcastBehavior +BroadcastBehavior: android.media.AudioManager#ACTION_SPEAKERPHONE_STATE_CHANGED: + Field 'ACTION_SPEAKERPHONE_STATE_CHANGED' is missing @BroadcastBehavior +BroadcastBehavior: android.media.tv.TvContract#ACTION_INITIALIZE_PROGRAMS: + Field 'ACTION_INITIALIZE_PROGRAMS' is missing @BroadcastBehavior +BroadcastBehavior: android.media.tv.TvContract#ACTION_PREVIEW_PROGRAM_ADDED_TO_WATCH_NEXT: + Field 'ACTION_PREVIEW_PROGRAM_ADDED_TO_WATCH_NEXT' is missing @BroadcastBehavior +BroadcastBehavior: android.media.tv.TvContract#ACTION_PREVIEW_PROGRAM_BROWSABLE_DISABLED: + Field 'ACTION_PREVIEW_PROGRAM_BROWSABLE_DISABLED' is missing @BroadcastBehavior +BroadcastBehavior: android.media.tv.TvContract#ACTION_WATCH_NEXT_PROGRAM_BROWSABLE_DISABLED: + Field 'ACTION_WATCH_NEXT_PROGRAM_BROWSABLE_DISABLED' is missing @BroadcastBehavior +BroadcastBehavior: android.net.Proxy#PROXY_CHANGE_ACTION: + Field 'PROXY_CHANGE_ACTION' is missing @BroadcastBehavior +BroadcastBehavior: android.nfc.NfcAdapter#ACTION_ADAPTER_STATE_CHANGED: + Field 'ACTION_ADAPTER_STATE_CHANGED' is missing @BroadcastBehavior +BroadcastBehavior: android.nfc.NfcAdapter#ACTION_PREFERRED_PAYMENT_CHANGED: + Field 'ACTION_PREFERRED_PAYMENT_CHANGED' is missing @BroadcastBehavior +BroadcastBehavior: android.nfc.NfcAdapter#ACTION_TRANSACTION_DETECTED: + Field 'ACTION_TRANSACTION_DETECTED' is missing @BroadcastBehavior +BroadcastBehavior: android.os.DropBoxManager#ACTION_DROPBOX_ENTRY_ADDED: + Field 'ACTION_DROPBOX_ENTRY_ADDED' is missing @BroadcastBehavior +BroadcastBehavior: android.provider.CalendarContract#ACTION_EVENT_REMINDER: + Field 'ACTION_EVENT_REMINDER' is missing @BroadcastBehavior +BroadcastBehavior: android.provider.ContactsContract.SimContacts#ACTION_SIM_ACCOUNTS_CHANGED: + Field 'ACTION_SIM_ACCOUNTS_CHANGED' is missing @BroadcastBehavior +BroadcastBehavior: android.provider.Telephony.Sms.Intents#DATA_SMS_RECEIVED_ACTION: + Field 'DATA_SMS_RECEIVED_ACTION' is missing @BroadcastBehavior +BroadcastBehavior: android.provider.Telephony.Sms.Intents#SECRET_CODE_ACTION: + Field 'SECRET_CODE_ACTION' is missing @BroadcastBehavior +BroadcastBehavior: android.provider.Telephony.Sms.Intents#SIM_FULL_ACTION: + Field 'SIM_FULL_ACTION' is missing @BroadcastBehavior +BroadcastBehavior: android.provider.Telephony.Sms.Intents#SMS_CB_RECEIVED_ACTION: + Field 'SMS_CB_RECEIVED_ACTION' is missing @BroadcastBehavior +BroadcastBehavior: android.provider.Telephony.Sms.Intents#SMS_DELIVER_ACTION: + Field 'SMS_DELIVER_ACTION' is missing @BroadcastBehavior +BroadcastBehavior: android.provider.Telephony.Sms.Intents#SMS_RECEIVED_ACTION: + Field 'SMS_RECEIVED_ACTION' is missing @BroadcastBehavior +BroadcastBehavior: android.provider.Telephony.Sms.Intents#SMS_REJECTED_ACTION: + Field 'SMS_REJECTED_ACTION' is missing @BroadcastBehavior +BroadcastBehavior: android.provider.Telephony.Sms.Intents#SMS_SERVICE_CATEGORY_PROGRAM_DATA_RECEIVED_ACTION: + Field 'SMS_SERVICE_CATEGORY_PROGRAM_DATA_RECEIVED_ACTION' is missing @BroadcastBehavior +BroadcastBehavior: android.provider.Telephony.Sms.Intents#WAP_PUSH_DELIVER_ACTION: + Field 'WAP_PUSH_DELIVER_ACTION' is missing @BroadcastBehavior +BroadcastBehavior: android.provider.Telephony.Sms.Intents#WAP_PUSH_RECEIVED_ACTION: + Field 'WAP_PUSH_RECEIVED_ACTION' is missing @BroadcastBehavior +BroadcastBehavior: android.security.KeyChain#ACTION_KEYCHAIN_CHANGED: + Field 'ACTION_KEYCHAIN_CHANGED' is missing @BroadcastBehavior +BroadcastBehavior: android.security.KeyChain#ACTION_KEY_ACCESS_CHANGED: + Field 'ACTION_KEY_ACCESS_CHANGED' is missing @BroadcastBehavior +BroadcastBehavior: android.security.KeyChain#ACTION_STORAGE_CHANGED: + Field 'ACTION_STORAGE_CHANGED' is missing @BroadcastBehavior +BroadcastBehavior: android.security.KeyChain#ACTION_TRUST_STORE_CHANGED: + Field 'ACTION_TRUST_STORE_CHANGED' is missing @BroadcastBehavior +BroadcastBehavior: android.speech.tts.TextToSpeech#ACTION_TTS_QUEUE_PROCESSING_COMPLETED: + Field 'ACTION_TTS_QUEUE_PROCESSING_COMPLETED' is missing @BroadcastBehavior +BroadcastBehavior: android.speech.tts.TextToSpeech.Engine#ACTION_TTS_DATA_INSTALLED: + Field 'ACTION_TTS_DATA_INSTALLED' is missing @BroadcastBehavior +BroadcastBehavior: android.telephony.SubscriptionManager#ACTION_DEFAULT_SMS_SUBSCRIPTION_CHANGED: + Field 'ACTION_DEFAULT_SMS_SUBSCRIPTION_CHANGED' is missing @BroadcastBehavior +BroadcastBehavior: android.telephony.SubscriptionManager#ACTION_DEFAULT_SUBSCRIPTION_CHANGED: + Field 'ACTION_DEFAULT_SUBSCRIPTION_CHANGED' is missing @BroadcastBehavior +BroadcastBehavior: android.telephony.SubscriptionManager#ACTION_REFRESH_SUBSCRIPTION_PLANS: + Field 'ACTION_REFRESH_SUBSCRIPTION_PLANS' is missing @BroadcastBehavior +BroadcastBehavior: android.telephony.TelephonyManager#ACTION_CARRIER_SIGNAL_DEFAULT_NETWORK_AVAILABLE: + Field 'ACTION_CARRIER_SIGNAL_DEFAULT_NETWORK_AVAILABLE' is missing @BroadcastBehavior +BroadcastBehavior: android.telephony.TelephonyManager#ACTION_CARRIER_SIGNAL_PCO_VALUE: + Field 'ACTION_CARRIER_SIGNAL_PCO_VALUE' is missing @BroadcastBehavior +BroadcastBehavior: android.telephony.TelephonyManager#ACTION_CARRIER_SIGNAL_REDIRECTED: + Field 'ACTION_CARRIER_SIGNAL_REDIRECTED' is missing @BroadcastBehavior +BroadcastBehavior: android.telephony.TelephonyManager#ACTION_CARRIER_SIGNAL_REQUEST_NETWORK_FAILED: + Field 'ACTION_CARRIER_SIGNAL_REQUEST_NETWORK_FAILED' is missing @BroadcastBehavior +BroadcastBehavior: android.telephony.TelephonyManager#ACTION_CARRIER_SIGNAL_RESET: + Field 'ACTION_CARRIER_SIGNAL_RESET' is missing @BroadcastBehavior +BroadcastBehavior: android.telephony.TelephonyManager#ACTION_SECRET_CODE: + Field 'ACTION_SECRET_CODE' is missing @BroadcastBehavior +BroadcastBehavior: android.telephony.TelephonyManager#ACTION_SUBSCRIPTION_CARRIER_IDENTITY_CHANGED: + Field 'ACTION_SUBSCRIPTION_CARRIER_IDENTITY_CHANGED' is missing @BroadcastBehavior +BroadcastBehavior: android.telephony.TelephonyManager#ACTION_SUBSCRIPTION_SPECIFIC_CARRIER_IDENTITY_CHANGED: + Field 'ACTION_SUBSCRIPTION_SPECIFIC_CARRIER_IDENTITY_CHANGED' is missing @BroadcastBehavior +BroadcastBehavior: android.telephony.euicc.EuiccManager#ACTION_NOTIFY_CARRIER_SETUP_INCOMPLETE: + Field 'ACTION_NOTIFY_CARRIER_SETUP_INCOMPLETE' is missing @BroadcastBehavior + + +DeprecationMismatch: android.accounts.AccountManager#newChooseAccountIntent(android.accounts.Account, java.util.ArrayList<android.accounts.Account>, String[], boolean, String, String, String[], android.os.Bundle): + Method android.accounts.AccountManager.newChooseAccountIntent(android.accounts.Account, java.util.ArrayList<android.accounts.Account>, String[], boolean, String, String, String[], android.os.Bundle): @Deprecated annotation (present) and @deprecated doc tag (not present) do not match +DeprecationMismatch: android.app.Activity#enterPictureInPictureMode(): + Method android.app.Activity.enterPictureInPictureMode(): @Deprecated annotation (present) and @deprecated doc tag (not present) do not match +DeprecationMismatch: android.app.Instrumentation#startAllocCounting(): + Method android.app.Instrumentation.startAllocCounting(): @Deprecated annotation (present) and @deprecated doc tag (not present) do not match +DeprecationMismatch: android.app.Instrumentation#stopAllocCounting(): + Method android.app.Instrumentation.stopAllocCounting(): @Deprecated annotation (present) and @deprecated doc tag (not present) do not match +DeprecationMismatch: android.app.Notification#bigContentView: + Field Notification.bigContentView: @Deprecated annotation (present) and @deprecated doc tag (not present) do not match +DeprecationMismatch: android.app.Notification#contentView: + Field Notification.contentView: @Deprecated annotation (present) and @deprecated doc tag (not present) do not match +DeprecationMismatch: android.app.Notification#headsUpContentView: + Field Notification.headsUpContentView: @Deprecated annotation (present) and @deprecated doc tag (not present) do not match +DeprecationMismatch: android.app.Notification#tickerView: + Field Notification.tickerView: @Deprecated annotation (present) and @deprecated doc tag (not present) do not match +DeprecationMismatch: android.app.Notification.Action.Builder#Builder(int, CharSequence, android.app.PendingIntent): + Constructor android.app.Notification.Action.Builder.Builder(int, CharSequence, android.app.PendingIntent): @Deprecated annotation (present) and @deprecated doc tag (not present) do not match +DeprecationMismatch: android.app.Notification.Action.WearableExtender#getCancelLabel(): + Method android.app.Notification.Action.WearableExtender.getCancelLabel(): @Deprecated annotation (present) and @deprecated doc tag (not present) do not match +DeprecationMismatch: android.app.Notification.Action.WearableExtender#getConfirmLabel(): + Method android.app.Notification.Action.WearableExtender.getConfirmLabel(): @Deprecated annotation (present) and @deprecated doc tag (not present) do not match +DeprecationMismatch: android.app.Notification.Action.WearableExtender#getInProgressLabel(): + Method android.app.Notification.Action.WearableExtender.getInProgressLabel(): @Deprecated annotation (present) and @deprecated doc tag (not present) do not match +DeprecationMismatch: android.app.Notification.Action.WearableExtender#setCancelLabel(CharSequence): + Method android.app.Notification.Action.WearableExtender.setCancelLabel(CharSequence): @Deprecated annotation (present) and @deprecated doc tag (not present) do not match +DeprecationMismatch: android.app.Notification.Action.WearableExtender#setConfirmLabel(CharSequence): + Method android.app.Notification.Action.WearableExtender.setConfirmLabel(CharSequence): @Deprecated annotation (present) and @deprecated doc tag (not present) do not match +DeprecationMismatch: android.app.Notification.Action.WearableExtender#setInProgressLabel(CharSequence): + Method android.app.Notification.Action.WearableExtender.setInProgressLabel(CharSequence): @Deprecated annotation (present) and @deprecated doc tag (not present) do not match +DeprecationMismatch: android.app.Notification.Builder#setContent(android.widget.RemoteViews): + Method android.app.Notification.Builder.setContent(android.widget.RemoteViews): @Deprecated annotation (present) and @deprecated doc tag (not present) do not match +DeprecationMismatch: android.app.Notification.Builder#setTicker(CharSequence, android.widget.RemoteViews): + Method android.app.Notification.Builder.setTicker(CharSequence, android.widget.RemoteViews): @Deprecated annotation (present) and @deprecated doc tag (not present) do not match +DeprecationMismatch: android.app.Notification.WearableExtender#getContentIcon(): + Method android.app.Notification.WearableExtender.getContentIcon(): @Deprecated annotation (present) and @deprecated doc tag (not present) do not match +DeprecationMismatch: android.app.Notification.WearableExtender#getContentIconGravity(): + Method android.app.Notification.WearableExtender.getContentIconGravity(): @Deprecated annotation (present) and @deprecated doc tag (not present) do not match +DeprecationMismatch: android.app.Notification.WearableExtender#getCustomContentHeight(): + Method android.app.Notification.WearableExtender.getCustomContentHeight(): @Deprecated annotation (present) and @deprecated doc tag (not present) do not match +DeprecationMismatch: android.app.Notification.WearableExtender#getCustomSizePreset(): + Method android.app.Notification.WearableExtender.getCustomSizePreset(): @Deprecated annotation (present) and @deprecated doc tag (not present) do not match +DeprecationMismatch: android.app.Notification.WearableExtender#getGravity(): + Method android.app.Notification.WearableExtender.getGravity(): @Deprecated annotation (present) and @deprecated doc tag (not present) do not match +DeprecationMismatch: android.app.Notification.WearableExtender#getHintAvoidBackgroundClipping(): + Method android.app.Notification.WearableExtender.getHintAvoidBackgroundClipping(): @Deprecated annotation (present) and @deprecated doc tag (not present) do not match +DeprecationMismatch: android.app.Notification.WearableExtender#getHintHideIcon(): + Method android.app.Notification.WearableExtender.getHintHideIcon(): @Deprecated annotation (present) and @deprecated doc tag (not present) do not match +DeprecationMismatch: android.app.Notification.WearableExtender#getHintScreenTimeout(): + Method android.app.Notification.WearableExtender.getHintScreenTimeout(): @Deprecated annotation (present) and @deprecated doc tag (not present) do not match +DeprecationMismatch: android.app.Notification.WearableExtender#getHintShowBackgroundOnly(): + Method android.app.Notification.WearableExtender.getHintShowBackgroundOnly(): @Deprecated annotation (present) and @deprecated doc tag (not present) do not match +DeprecationMismatch: android.app.Notification.WearableExtender#setContentIcon(int): + Method android.app.Notification.WearableExtender.setContentIcon(int): @Deprecated annotation (present) and @deprecated doc tag (not present) do not match +DeprecationMismatch: android.app.Notification.WearableExtender#setContentIconGravity(int): + Method android.app.Notification.WearableExtender.setContentIconGravity(int): @Deprecated annotation (present) and @deprecated doc tag (not present) do not match +DeprecationMismatch: android.app.Notification.WearableExtender#setCustomContentHeight(int): + Method android.app.Notification.WearableExtender.setCustomContentHeight(int): @Deprecated annotation (present) and @deprecated doc tag (not present) do not match +DeprecationMismatch: android.app.Notification.WearableExtender#setCustomSizePreset(int): + Method android.app.Notification.WearableExtender.setCustomSizePreset(int): @Deprecated annotation (present) and @deprecated doc tag (not present) do not match +DeprecationMismatch: android.app.Notification.WearableExtender#setGravity(int): + Method android.app.Notification.WearableExtender.setGravity(int): @Deprecated annotation (present) and @deprecated doc tag (not present) do not match +DeprecationMismatch: android.app.Notification.WearableExtender#setHintAvoidBackgroundClipping(boolean): + Method android.app.Notification.WearableExtender.setHintAvoidBackgroundClipping(boolean): @Deprecated annotation (present) and @deprecated doc tag (not present) do not match +DeprecationMismatch: android.app.Notification.WearableExtender#setHintHideIcon(boolean): + Method android.app.Notification.WearableExtender.setHintHideIcon(boolean): @Deprecated annotation (present) and @deprecated doc tag (not present) do not match +DeprecationMismatch: android.app.Notification.WearableExtender#setHintScreenTimeout(int): + Method android.app.Notification.WearableExtender.setHintScreenTimeout(int): @Deprecated annotation (present) and @deprecated doc tag (not present) do not match +DeprecationMismatch: android.app.Notification.WearableExtender#setHintShowBackgroundOnly(boolean): + Method android.app.Notification.WearableExtender.setHintShowBackgroundOnly(boolean): @Deprecated annotation (present) and @deprecated doc tag (not present) do not match +DeprecationMismatch: android.graphics.ComposeShader#ComposeShader(android.graphics.Shader, android.graphics.Shader, android.graphics.Xfermode): + Constructor android.graphics.ComposeShader.ComposeShader(android.graphics.Shader, android.graphics.Shader, android.graphics.Xfermode): @Deprecated annotation (present) and @deprecated doc tag (not present) do not match +DeprecationMismatch: android.graphics.PixelFormat#A_8: + Field PixelFormat.A_8: @Deprecated annotation (present) and @deprecated doc tag (not present) do not match +DeprecationMismatch: android.graphics.PixelFormat#LA_88: + Field PixelFormat.LA_88: @Deprecated annotation (present) and @deprecated doc tag (not present) do not match +DeprecationMismatch: android.graphics.PixelFormat#L_8: + Field PixelFormat.L_8: @Deprecated annotation (present) and @deprecated doc tag (not present) do not match +DeprecationMismatch: android.graphics.PixelFormat#RGBA_4444: + Field PixelFormat.RGBA_4444: @Deprecated annotation (present) and @deprecated doc tag (not present) do not match +DeprecationMismatch: android.graphics.PixelFormat#RGBA_5551: + Field PixelFormat.RGBA_5551: @Deprecated annotation (present) and @deprecated doc tag (not present) do not match +DeprecationMismatch: android.graphics.PixelFormat#RGB_332: + Field PixelFormat.RGB_332: @Deprecated annotation (present) and @deprecated doc tag (not present) do not match +DeprecationMismatch: android.opengl.EGL14#eglCreatePixmapSurface(android.opengl.EGLDisplay, android.opengl.EGLConfig, int, int[], int): + Method android.opengl.EGL14.eglCreatePixmapSurface(android.opengl.EGLDisplay, android.opengl.EGLConfig, int, int[], int): @Deprecated annotation (present) and @deprecated doc tag (not present) do not match +DeprecationMismatch: android.opengl.GLES20#GL_STENCIL_INDEX: + Field GLES20.GL_STENCIL_INDEX: @Deprecated annotation (present) and @deprecated doc tag (not present) do not match +DeprecationMismatch: android.opengl.GLSurfaceView#surfaceRedrawNeeded(android.view.SurfaceHolder): + Method android.opengl.GLSurfaceView.surfaceRedrawNeeded(android.view.SurfaceHolder): @Deprecated annotation (present) and @deprecated doc tag (not present) do not match +DeprecationMismatch: android.os.UserManager#setUserRestrictions(android.os.Bundle): + Method android.os.UserManager.setUserRestrictions(android.os.Bundle): @Deprecated annotation (present) and @deprecated doc tag (not present) do not match +DeprecationMismatch: android.os.UserManager#setUserRestrictions(android.os.Bundle, android.os.UserHandle): + Method android.os.UserManager.setUserRestrictions(android.os.Bundle, android.os.UserHandle): @Deprecated annotation (present) and @deprecated doc tag (not present) do not match +DeprecationMismatch: android.provider.Contacts.People#markAsContacted(android.content.ContentResolver, long): + Method android.provider.Contacts.People.markAsContacted(android.content.ContentResolver, long): @Deprecated annotation (present) and @deprecated doc tag (not present) do not match +DeprecationMismatch: android.renderscript.Type.CubemapFace#POSITVE_X: + Field Type.CubemapFace.POSITVE_X: @Deprecated annotation (present) and @deprecated doc tag (not present) do not match +DeprecationMismatch: android.renderscript.Type.CubemapFace#POSITVE_Y: + Field Type.CubemapFace.POSITVE_Y: @Deprecated annotation (present) and @deprecated doc tag (not present) do not match +DeprecationMismatch: android.renderscript.Type.CubemapFace#POSITVE_Z: + Field Type.CubemapFace.POSITVE_Z: @Deprecated annotation (present) and @deprecated doc tag (not present) do not match +DeprecationMismatch: android.speech.tts.TextToSpeech#areDefaultsEnforced(): + Method android.speech.tts.TextToSpeech.areDefaultsEnforced(): @Deprecated annotation (present) and @deprecated doc tag (not present) do not match +DeprecationMismatch: android.telephony.PhoneStateListener#PhoneStateListener(java.util.concurrent.Executor): + Constructor android.telephony.PhoneStateListener.PhoneStateListener(java.util.concurrent.Executor): @Deprecated annotation (present) and @deprecated doc tag (not present) do not match +DeprecationMismatch: android.text.format.DateUtils#FORMAT_12HOUR: + Field DateUtils.FORMAT_12HOUR: @Deprecated annotation (present) and @deprecated doc tag (not present) do not match +DeprecationMismatch: android.text.format.DateUtils#FORMAT_24HOUR: + Field DateUtils.FORMAT_24HOUR: @Deprecated annotation (present) and @deprecated doc tag (not present) do not match +DeprecationMismatch: android.text.format.DateUtils#FORMAT_CAP_AMPM: + Field DateUtils.FORMAT_CAP_AMPM: @Deprecated annotation (present) and @deprecated doc tag (not present) do not match +DeprecationMismatch: android.text.format.DateUtils#FORMAT_CAP_MIDNIGHT: + Field DateUtils.FORMAT_CAP_MIDNIGHT: @Deprecated annotation (present) and @deprecated doc tag (not present) do not match +DeprecationMismatch: android.text.format.DateUtils#FORMAT_CAP_NOON: + Field DateUtils.FORMAT_CAP_NOON: @Deprecated annotation (present) and @deprecated doc tag (not present) do not match +DeprecationMismatch: android.text.format.DateUtils#FORMAT_CAP_NOON_MIDNIGHT: + Field DateUtils.FORMAT_CAP_NOON_MIDNIGHT: @Deprecated annotation (present) and @deprecated doc tag (not present) do not match +DeprecationMismatch: android.text.format.DateUtils#FORMAT_NO_NOON_MIDNIGHT: + Field DateUtils.FORMAT_NO_NOON_MIDNIGHT: @Deprecated annotation (present) and @deprecated doc tag (not present) do not match +DeprecationMismatch: android.view.ViewGroup.LayoutParams#FILL_PARENT: + Field ViewGroup.LayoutParams.FILL_PARENT: @Deprecated annotation (present) and @deprecated doc tag (not present) do not match +DeprecationMismatch: android.view.Window#setTitleColor(int): + Method android.view.Window.setTitleColor(int): @Deprecated annotation (present) and @deprecated doc tag (not present) do not match +DeprecationMismatch: android.view.accessibility.AccessibilityEvent#MAX_TEXT_LENGTH: + Field AccessibilityEvent.MAX_TEXT_LENGTH: @Deprecated annotation (present) and @deprecated doc tag (not present) do not match +DeprecationMismatch: android.webkit.WebSettings#getSaveFormData(): + Method android.webkit.WebSettings.getSaveFormData(): @Deprecated annotation (present) and @deprecated doc tag (not present) do not match +DeprecationMismatch: android.webkit.WebView#shouldDelayChildPressedState(): + Method android.webkit.WebView.shouldDelayChildPressedState(): @Deprecated annotation (present) and @deprecated doc tag (not present) do not match +DeprecationMismatch: android.webkit.WebViewDatabase#clearFormData(): + Method android.webkit.WebViewDatabase.clearFormData(): @Deprecated annotation (present) and @deprecated doc tag (not present) do not match +DeprecationMismatch: android.webkit.WebViewDatabase#hasFormData(): + Method android.webkit.WebViewDatabase.hasFormData(): @Deprecated annotation (present) and @deprecated doc tag (not present) do not match +DeprecationMismatch: javax.microedition.khronos.egl.EGL10#eglCreatePixmapSurface(javax.microedition.khronos.egl.EGLDisplay, javax.microedition.khronos.egl.EGLConfig, Object, int[]): + Method javax.microedition.khronos.egl.EGL10.eglCreatePixmapSurface(javax.microedition.khronos.egl.EGLDisplay, javax.microedition.khronos.egl.EGLConfig, Object, int[]): @Deprecated annotation (present) and @deprecated doc tag (not present) do not match + + +RequiresPermission: android.accounts.AccountManager#getAccountsByTypeAndFeatures(String, String[], android.accounts.AccountManagerCallback<android.accounts.Account[]>, android.os.Handler): + Method 'getAccountsByTypeAndFeatures' documentation mentions permissions without declaring @RequiresPermission +RequiresPermission: android.accounts.AccountManager#hasFeatures(android.accounts.Account, String[], android.accounts.AccountManagerCallback<java.lang.Boolean>, android.os.Handler): + Method 'hasFeatures' documentation mentions permissions without declaring @RequiresPermission +RequiresPermission: android.app.ActivityManager#getHistoricalProcessExitReasons(String, int, int): + Method 'getHistoricalProcessExitReasons' documentation mentions permissions without declaring @RequiresPermission +RequiresPermission: android.app.ActivityManager#getProcessesInErrorState(): + Method 'getProcessesInErrorState' documentation mentions permissions without declaring @RequiresPermission +RequiresPermission: android.app.AlarmManager#setAlarmClock(android.app.AlarmManager.AlarmClockInfo, android.app.PendingIntent): + Method 'setAlarmClock' documentation mentions permissions already declared by @RequiresPermission +RequiresPermission: android.app.AlarmManager#setExact(int, long, android.app.PendingIntent): + Method 'setExact' documentation mentions permissions already declared by @RequiresPermission +RequiresPermission: android.app.AlarmManager#setExactAndAllowWhileIdle(int, long, android.app.PendingIntent): + Method 'setExactAndAllowWhileIdle' documentation mentions permissions already declared by @RequiresPermission +RequiresPermission: android.app.AlarmManager#setTime(long): + Method 'setTime' documentation mentions permissions already declared by @RequiresPermission +RequiresPermission: android.app.AppOpsManager#isOpActive(String, int, String): + Method 'isOpActive' documentation mentions permissions without declaring @RequiresPermission +RequiresPermission: android.app.AppOpsManager#startWatchingActive(String[], java.util.concurrent.Executor, android.app.AppOpsManager.OnOpActiveChangedListener): + Method 'startWatchingActive' documentation mentions permissions without declaring @RequiresPermission +RequiresPermission: android.app.DownloadManager.Request#setDestinationInExternalPublicDir(String, String): + Method 'setDestinationInExternalPublicDir' documentation mentions permissions without declaring @RequiresPermission +RequiresPermission: android.app.DownloadManager.Request#setDestinationUri(android.net.Uri): + Method 'setDestinationUri' documentation mentions permissions without declaring @RequiresPermission +RequiresPermission: android.app.DownloadManager.Request#setNotificationVisibility(int): + Method 'setNotificationVisibility' documentation mentions permissions without declaring @RequiresPermission +RequiresPermission: android.app.DownloadManager.Request#setShowRunningNotification(boolean): + Method 'setShowRunningNotification' documentation mentions permissions without declaring @RequiresPermission +RequiresPermission: android.app.LocaleManager#getApplicationLocales(String): + Method 'getApplicationLocales' documentation mentions permissions already declared by @RequiresPermission +RequiresPermission: android.app.Notification.Builder#setFullScreenIntent(android.app.PendingIntent, boolean): + Method 'setFullScreenIntent' documentation mentions permissions without declaring @RequiresPermission +RequiresPermission: android.app.NotificationManager#canUseFullScreenIntent(): + Method 'canUseFullScreenIntent' documentation mentions permissions without declaring @RequiresPermission +RequiresPermission: android.app.Service#startForeground(int, android.app.Notification): + Method 'startForeground' documentation mentions permissions without declaring @RequiresPermission +RequiresPermission: android.app.StatusBarManager#canLaunchCaptureContentActivityForNote(android.app.Activity): + Method 'canLaunchCaptureContentActivityForNote' documentation mentions permissions already declared by @RequiresPermission +RequiresPermission: android.app.WallpaperInfo#getSettingsSliceUri(): + Method 'getSettingsSliceUri' documentation mentions permissions without declaring @RequiresPermission +RequiresPermission: android.app.WallpaperManager#clear(): + Method 'clear' documentation mentions permissions already declared by @RequiresPermission +RequiresPermission: android.app.WallpaperManager#getDrawable(): + Method 'getDrawable' documentation mentions permissions already declared by @RequiresPermission +RequiresPermission: android.app.WallpaperManager#getDrawable(int): + Method 'getDrawable' documentation mentions permissions already declared by @RequiresPermission +RequiresPermission: android.app.WallpaperManager#getFastDrawable(): + Method 'getFastDrawable' documentation mentions permissions already declared by @RequiresPermission +RequiresPermission: android.app.WallpaperManager#getFastDrawable(int): + Method 'getFastDrawable' documentation mentions permissions already declared by @RequiresPermission +RequiresPermission: android.app.WallpaperManager#getWallpaperFile(int): + Method 'getWallpaperFile' documentation mentions permissions already declared by @RequiresPermission +RequiresPermission: android.app.WallpaperManager#getWallpaperInfo(int): + Method 'getWallpaperInfo' documentation mentions permissions without declaring @RequiresPermission +RequiresPermission: android.app.WallpaperManager#peekDrawable(): + Method 'peekDrawable' documentation mentions permissions already declared by @RequiresPermission +RequiresPermission: android.app.WallpaperManager#peekDrawable(int): + Method 'peekDrawable' documentation mentions permissions already declared by @RequiresPermission +RequiresPermission: android.app.WallpaperManager#peekFastDrawable(): + Method 'peekFastDrawable' documentation mentions permissions already declared by @RequiresPermission +RequiresPermission: android.app.WallpaperManager#peekFastDrawable(int): + Method 'peekFastDrawable' documentation mentions permissions already declared by @RequiresPermission +RequiresPermission: android.app.WallpaperManager#setBitmap(android.graphics.Bitmap): + Method 'setBitmap' documentation mentions permissions already declared by @RequiresPermission +RequiresPermission: android.app.WallpaperManager#setBitmap(android.graphics.Bitmap, android.graphics.Rect, boolean): + Method 'setBitmap' documentation mentions permissions already declared by @RequiresPermission +RequiresPermission: android.app.WallpaperManager#setDisplayPadding(android.graphics.Rect): + Method 'setDisplayPadding' documentation mentions permissions already declared by @RequiresPermission +RequiresPermission: android.app.WallpaperManager#setResource(int): + Method 'setResource' documentation mentions permissions already declared by @RequiresPermission +RequiresPermission: android.app.WallpaperManager#setStream(java.io.InputStream): + Method 'setStream' documentation mentions permissions already declared by @RequiresPermission +RequiresPermission: android.app.WallpaperManager#setStream(java.io.InputStream, android.graphics.Rect, boolean): + Method 'setStream' documentation mentions permissions already declared by @RequiresPermission +RequiresPermission: android.app.WallpaperManager#suggestDesiredDimensions(int, int): + Method 'suggestDesiredDimensions' documentation mentions permissions without declaring @RequiresPermission +RequiresPermission: android.app.admin.DevicePolicyManager#addCrossProfileWidgetProvider(android.content.ComponentName, String): + Method 'addCrossProfileWidgetProvider' documentation mentions permissions already declared by @RequiresPermission +RequiresPermission: android.app.admin.DevicePolicyManager#addPersistentPreferredActivity(android.content.ComponentName, android.content.IntentFilter, android.content.ComponentName): + Method 'addPersistentPreferredActivity' documentation mentions permissions already declared by @RequiresPermission +RequiresPermission: android.app.admin.DevicePolicyManager#bindDeviceAdminServiceAsUser(android.content.ComponentName, android.content.Intent, android.content.ServiceConnection, int, android.os.UserHandle): + Method 'bindDeviceAdminServiceAsUser' documentation mentions permissions without declaring @RequiresPermission +RequiresPermission: android.app.admin.DevicePolicyManager#clearPackagePersistentPreferredActivities(android.content.ComponentName, String): + Method 'clearPackagePersistentPreferredActivities' documentation mentions permissions already declared by @RequiresPermission +RequiresPermission: android.app.admin.DevicePolicyManager#clearResetPasswordToken(android.content.ComponentName): + Method 'clearResetPasswordToken' documentation mentions permissions already declared by @RequiresPermission +RequiresPermission: android.app.admin.DevicePolicyManager#generateKeyPair(android.content.ComponentName, String, android.security.keystore.KeyGenParameterSpec, int): + Method 'generateKeyPair' documentation mentions permissions already declared by @RequiresPermission +RequiresPermission: android.app.admin.DevicePolicyManager#getCrossProfileWidgetProviders(android.content.ComponentName): + Method 'getCrossProfileWidgetProviders' documentation mentions permissions already declared by @RequiresPermission +RequiresPermission: android.app.admin.DevicePolicyManager#getLockTaskFeatures(android.content.ComponentName): + Method 'getLockTaskFeatures' documentation mentions permissions already declared by @RequiresPermission +RequiresPermission: android.app.admin.DevicePolicyManager#getLockTaskPackages(android.content.ComponentName): + Method 'getLockTaskPackages' documentation mentions permissions already declared by @RequiresPermission +RequiresPermission: android.app.admin.DevicePolicyManager#getNearbyAppStreamingPolicy(): + Method 'getNearbyAppStreamingPolicy' documentation mentions permissions already declared by @RequiresPermission +RequiresPermission: android.app.admin.DevicePolicyManager#getNearbyNotificationStreamingPolicy(): + Method 'getNearbyNotificationStreamingPolicy' documentation mentions permissions already declared by @RequiresPermission +RequiresPermission: android.app.admin.DevicePolicyManager#getOrganizationName(android.content.ComponentName): + Method 'getOrganizationName' documentation mentions permissions already declared by @RequiresPermission +RequiresPermission: android.app.admin.DevicePolicyManager#getPasswordComplexity(): + Method 'getPasswordComplexity' documentation mentions permissions already declared by @RequiresPermission +RequiresPermission: android.app.admin.DevicePolicyManager#getShortSupportMessage(android.content.ComponentName): + Method 'getShortSupportMessage' documentation mentions permissions already declared by @RequiresPermission +RequiresPermission: android.app.admin.DevicePolicyManager#getUserControlDisabledPackages(android.content.ComponentName): + Method 'getUserControlDisabledPackages' documentation mentions permissions already declared by @RequiresPermission +RequiresPermission: android.app.admin.DevicePolicyManager#hasKeyPair(String): + Method 'hasKeyPair' documentation mentions permissions already declared by @RequiresPermission +RequiresPermission: android.app.admin.DevicePolicyManager#installKeyPair(android.content.ComponentName, java.security.PrivateKey, java.security.cert.Certificate, String): + Method 'installKeyPair' documentation mentions permissions already declared by @RequiresPermission +RequiresPermission: android.app.admin.DevicePolicyManager#installKeyPair(android.content.ComponentName, java.security.PrivateKey, java.security.cert.Certificate[], String, boolean): + Method 'installKeyPair' documentation mentions permissions already declared by @RequiresPermission +RequiresPermission: android.app.admin.DevicePolicyManager#installKeyPair(android.content.ComponentName, java.security.PrivateKey, java.security.cert.Certificate[], String, int): + Method 'installKeyPair' documentation mentions permissions already declared by @RequiresPermission +RequiresPermission: android.app.admin.DevicePolicyManager#isPackageSuspended(android.content.ComponentName, String): + Method 'isPackageSuspended' documentation mentions permissions already declared by @RequiresPermission +RequiresPermission: android.app.admin.DevicePolicyManager#isResetPasswordTokenActive(android.content.ComponentName): + Method 'isResetPasswordTokenActive' documentation mentions permissions already declared by @RequiresPermission +RequiresPermission: android.app.admin.DevicePolicyManager#lockNow(int): + Method 'lockNow' documentation mentions permissions already declared by @RequiresPermission +RequiresPermission: android.app.admin.DevicePolicyManager#removeCrossProfileWidgetProvider(android.content.ComponentName, String): + Method 'removeCrossProfileWidgetProvider' documentation mentions permissions already declared by @RequiresPermission +RequiresPermission: android.app.admin.DevicePolicyManager#setAlwaysOnVpnPackage(android.content.ComponentName, String, boolean): + Method 'setAlwaysOnVpnPackage' documentation mentions permissions without declaring @RequiresPermission +RequiresPermission: android.app.admin.DevicePolicyManager#setLockTaskFeatures(android.content.ComponentName, int): + Method 'setLockTaskFeatures' documentation mentions permissions already declared by @RequiresPermission +RequiresPermission: android.app.admin.DevicePolicyManager#setLockTaskPackages(android.content.ComponentName, String[]): + Method 'setLockTaskPackages' documentation mentions permissions already declared by @RequiresPermission +RequiresPermission: android.app.admin.DevicePolicyManager#setPermittedInputMethods(android.content.ComponentName, java.util.List<java.lang.String>): + Method 'setPermittedInputMethods' documentation mentions permissions already declared by @RequiresPermission +RequiresPermission: android.app.admin.DevicePolicyManager#setUninstallBlocked(android.content.ComponentName, String, boolean): + Method 'setUninstallBlocked' documentation mentions permissions already declared by @RequiresPermission +RequiresPermission: android.app.admin.DevicePolicyManager#setUserControlDisabledPackages(android.content.ComponentName, java.util.List<java.lang.String>): + Method 'setUserControlDisabledPackages' documentation mentions permissions already declared by @RequiresPermission +RequiresPermission: android.app.admin.DevicePolicyManager#wipeData(int): + Method 'wipeData' documentation mentions permissions already declared by @RequiresPermission +RequiresPermission: android.app.admin.DevicePolicyManager#wipeData(int, CharSequence): + Method 'wipeData' documentation mentions permissions already declared by @RequiresPermission +RequiresPermission: android.app.admin.DevicePolicyManager#wipeDevice(int): + Method 'wipeDevice' documentation mentions permissions already declared by @RequiresPermission +RequiresPermission: android.app.admin.PolicyUpdateReceiver#onPolicyChanged(android.content.Context, String, android.os.Bundle, android.app.admin.TargetUser, android.app.admin.PolicyUpdateResult): + Method 'onPolicyChanged' documentation mentions permissions without declaring @RequiresPermission +RequiresPermission: android.app.admin.PolicyUpdateReceiver#onPolicySetResult(android.content.Context, String, android.os.Bundle, android.app.admin.TargetUser, android.app.admin.PolicyUpdateResult): + Method 'onPolicySetResult' documentation mentions permissions without declaring @RequiresPermission +RequiresPermission: android.app.backup.BackupManager#dataChanged(String): + Method 'dataChanged' documentation mentions permissions without declaring @RequiresPermission +RequiresPermission: android.app.job.JobInfo.Builder#setRequiredNetwork(android.net.NetworkRequest): + Method 'setRequiredNetwork' documentation mentions permissions without declaring @RequiresPermission +RequiresPermission: android.app.job.JobInfo.Builder#setRequiredNetworkType(int): + Method 'setRequiredNetworkType' documentation mentions permissions without declaring @RequiresPermission +RequiresPermission: android.app.job.JobInfo.Builder#setUserInitiated(boolean): + Method 'setUserInitiated' documentation mentions permissions already declared by @RequiresPermission +RequiresPermission: android.app.job.JobParameters#isUserInitiatedJob(): + Method 'isUserInitiatedJob' documentation mentions permissions without declaring @RequiresPermission +RequiresPermission: android.app.job.JobScheduler#canRunUserInitiatedJobs(): + Method 'canRunUserInitiatedJobs' documentation mentions permissions without declaring @RequiresPermission +RequiresPermission: android.app.usage.StorageStatsManager#queryExternalStatsForUser(java.util.UUID, android.os.UserHandle): + Method 'queryExternalStatsForUser' documentation mentions permissions without declaring @RequiresPermission +RequiresPermission: android.app.usage.StorageStatsManager#queryStatsForPackage(java.util.UUID, String, android.os.UserHandle): + Method 'queryStatsForPackage' documentation mentions permissions without declaring @RequiresPermission +RequiresPermission: android.app.usage.StorageStatsManager#queryStatsForUid(java.util.UUID, int): + Method 'queryStatsForUid' documentation mentions permissions without declaring @RequiresPermission +RequiresPermission: android.app.usage.StorageStatsManager#queryStatsForUser(java.util.UUID, android.os.UserHandle): + Method 'queryStatsForUser' documentation mentions permissions without declaring @RequiresPermission +RequiresPermission: android.app.usage.UsageStatsManager#isAppInactive(String): + Method 'isAppInactive' documentation mentions permissions without declaring @RequiresPermission +RequiresPermission: android.app.usage.UsageStatsManager#queryAndAggregateUsageStats(long, long): + Method 'queryAndAggregateUsageStats' documentation mentions permissions without declaring @RequiresPermission +RequiresPermission: android.app.usage.UsageStatsManager#queryConfigurations(int, long, long): + Method 'queryConfigurations' documentation mentions permissions without declaring @RequiresPermission +RequiresPermission: android.app.usage.UsageStatsManager#queryEventStats(int, long, long): + Method 'queryEventStats' documentation mentions permissions without declaring @RequiresPermission +RequiresPermission: android.app.usage.UsageStatsManager#queryEvents(long, long): + Method 'queryEvents' documentation mentions permissions without declaring @RequiresPermission +RequiresPermission: android.app.usage.UsageStatsManager#queryUsageStats(int, long, long): + Method 'queryUsageStats' documentation mentions permissions without declaring @RequiresPermission +RequiresPermission: android.appwidget.AppWidgetManager#bindAppWidgetIdIfAllowed(int, android.os.UserHandle, android.content.ComponentName, android.os.Bundle): + Method 'bindAppWidgetIdIfAllowed' documentation mentions permissions without declaring @RequiresPermission +RequiresPermission: android.companion.CompanionDeviceManager#startObservingDevicePresence(String): + Method 'startObservingDevicePresence' documentation mentions permissions already declared by @RequiresPermission +RequiresPermission: android.companion.CompanionDeviceManager#stopObservingDevicePresence(String): + Method 'stopObservingDevicePresence' documentation mentions permissions already declared by @RequiresPermission +RequiresPermission: android.content.ContentResolver#addPeriodicSync(android.accounts.Account, String, android.os.Bundle, long): + Method 'addPeriodicSync' documentation mentions permissions without declaring @RequiresPermission +RequiresPermission: android.content.ContentResolver#cancelSync(android.content.SyncRequest): + Method 'cancelSync' documentation mentions permissions without declaring @RequiresPermission +RequiresPermission: android.content.ContentResolver#getCurrentSync(): + Method 'getCurrentSync' documentation mentions permissions without declaring @RequiresPermission +RequiresPermission: android.content.ContentResolver#getCurrentSyncs(): + Method 'getCurrentSyncs' documentation mentions permissions without declaring @RequiresPermission +RequiresPermission: android.content.ContentResolver#getIsSyncable(android.accounts.Account, String): + Method 'getIsSyncable' documentation mentions permissions without declaring @RequiresPermission +RequiresPermission: android.content.ContentResolver#getMasterSyncAutomatically(): + Method 'getMasterSyncAutomatically' documentation mentions permissions without declaring @RequiresPermission +RequiresPermission: android.content.ContentResolver#getPeriodicSyncs(android.accounts.Account, String): + Method 'getPeriodicSyncs' documentation mentions permissions without declaring @RequiresPermission +RequiresPermission: android.content.ContentResolver#getSyncAutomatically(android.accounts.Account, String): + Method 'getSyncAutomatically' documentation mentions permissions without declaring @RequiresPermission +RequiresPermission: android.content.ContentResolver#isSyncActive(android.accounts.Account, String): + Method 'isSyncActive' documentation mentions permissions without declaring @RequiresPermission +RequiresPermission: android.content.ContentResolver#isSyncPending(android.accounts.Account, String): + Method 'isSyncPending' documentation mentions permissions without declaring @RequiresPermission +RequiresPermission: android.content.ContentResolver#removePeriodicSync(android.accounts.Account, String, android.os.Bundle): + Method 'removePeriodicSync' documentation mentions permissions without declaring @RequiresPermission +RequiresPermission: android.content.ContentResolver#setIsSyncable(android.accounts.Account, String, int): + Method 'setIsSyncable' documentation mentions permissions without declaring @RequiresPermission +RequiresPermission: android.content.ContentResolver#setMasterSyncAutomatically(boolean): + Method 'setMasterSyncAutomatically' documentation mentions permissions without declaring @RequiresPermission +RequiresPermission: android.content.ContentResolver#setSyncAutomatically(android.accounts.Account, String, boolean): + Method 'setSyncAutomatically' documentation mentions permissions without declaring @RequiresPermission +RequiresPermission: android.content.Context#bindServiceAsUser(android.content.Intent, android.content.ServiceConnection, int, android.os.UserHandle): + Method 'bindServiceAsUser' documentation mentions permissions already declared by @RequiresPermission +RequiresPermission: android.content.Context#clearWallpaper(): + Method 'clearWallpaper' documentation mentions permissions without declaring @RequiresPermission +RequiresPermission: android.content.Context#getExternalCacheDir(): + Method 'getExternalCacheDir' documentation mentions permissions without declaring @RequiresPermission +RequiresPermission: android.content.Context#getExternalCacheDirs(): + Method 'getExternalCacheDirs' documentation mentions permissions without declaring @RequiresPermission +RequiresPermission: android.content.Context#getExternalFilesDir(String): + Method 'getExternalFilesDir' documentation mentions permissions without declaring @RequiresPermission +RequiresPermission: android.content.Context#getExternalFilesDirs(String): + Method 'getExternalFilesDirs' documentation mentions permissions without declaring @RequiresPermission +RequiresPermission: android.content.Context#getExternalMediaDirs(): + Method 'getExternalMediaDirs' documentation mentions permissions without declaring @RequiresPermission +RequiresPermission: android.content.Context#getObbDir(): + Method 'getObbDir' documentation mentions permissions without declaring @RequiresPermission +RequiresPermission: android.content.Context#getObbDirs(): + Method 'getObbDirs' documentation mentions permissions without declaring @RequiresPermission +RequiresPermission: android.content.Context#removeStickyBroadcastAsUser(android.content.Intent, android.os.UserHandle): + Method 'removeStickyBroadcastAsUser' documentation mentions permissions already declared by @RequiresPermission +RequiresPermission: android.content.Context#setWallpaper(android.graphics.Bitmap): + Method 'setWallpaper' documentation mentions permissions without declaring @RequiresPermission +RequiresPermission: android.content.Context#setWallpaper(java.io.InputStream): + Method 'setWallpaper' documentation mentions permissions without declaring @RequiresPermission +RequiresPermission: android.content.pm.CrossProfileApps#canRequestInteractAcrossProfiles(): + Method 'canRequestInteractAcrossProfiles' documentation mentions permissions without declaring @RequiresPermission +RequiresPermission: android.content.pm.CrossProfileApps#startActivity(android.content.Intent, android.os.UserHandle, android.app.Activity): + Method 'startActivity' documentation mentions permissions already declared by @RequiresPermission +RequiresPermission: android.content.pm.CrossProfileApps#startActivity(android.content.Intent, android.os.UserHandle, android.app.Activity, android.os.Bundle): + Method 'startActivity' documentation mentions permissions already declared by @RequiresPermission +RequiresPermission: android.content.pm.LauncherApps#getAllPackageInstallerSessions(): + Method 'getAllPackageInstallerSessions' documentation mentions permissions without declaring @RequiresPermission +RequiresPermission: android.content.pm.LauncherApps#registerPackageInstallerSessionCallback(java.util.concurrent.Executor, android.content.pm.PackageInstaller.SessionCallback): + Method 'registerPackageInstallerSessionCallback' documentation mentions permissions without declaring @RequiresPermission +RequiresPermission: android.content.pm.LauncherApps.Callback#onPackagesSuspended(String[], android.os.UserHandle, android.os.Bundle): + Method 'onPackagesSuspended' documentation mentions permissions without declaring @RequiresPermission +RequiresPermission: android.content.pm.PackageInstaller#getAllSessions(): + Method 'getAllSessions' documentation mentions permissions without declaring @RequiresPermission +RequiresPermission: android.content.pm.PackageInstaller#getSessionInfo(int): + Method 'getSessionInfo' documentation mentions permissions without declaring @RequiresPermission +RequiresPermission: android.content.pm.PackageInstaller#getStagedSessions(): + Method 'getStagedSessions' documentation mentions permissions without declaring @RequiresPermission +RequiresPermission: android.content.pm.PackageInstaller#registerSessionCallback(android.content.pm.PackageInstaller.SessionCallback): + Method 'registerSessionCallback' documentation mentions permissions without declaring @RequiresPermission +RequiresPermission: android.content.pm.PackageInstaller.Session#requestUserPreapproval(android.content.pm.PackageInstaller.PreapprovalDetails, android.content.IntentSender): + Method 'requestUserPreapproval' documentation mentions permissions without declaring @RequiresPermission +RequiresPermission: android.content.pm.PackageInstaller.SessionParams#setInstallerPackageName(String): + Method 'setInstallerPackageName' documentation mentions permissions without declaring @RequiresPermission +RequiresPermission: android.content.pm.PackageInstaller.SessionParams#setPermissionState(String, int): + Method 'setPermissionState' documentation mentions permissions already declared by @RequiresPermission +RequiresPermission: android.content.pm.PackageInstaller.SessionParams#setRequestUpdateOwnership(boolean): + Method 'setRequestUpdateOwnership' documentation mentions permissions already declared by @RequiresPermission +RequiresPermission: android.content.pm.PackageInstaller.SessionParams#setRequireUserAction(int): + Method 'setRequireUserAction' documentation mentions permissions without declaring @RequiresPermission +RequiresPermission: android.content.pm.PackageManager#canRequestPackageInstalls(): + Method 'canRequestPackageInstalls' documentation mentions permissions without declaring @RequiresPermission +RequiresPermission: android.content.pm.PackageManager#getSuspendedPackageAppExtras(): + Method 'getSuspendedPackageAppExtras' documentation mentions permissions without declaring @RequiresPermission +RequiresPermission: android.content.pm.PackageManager#isAutoRevokeWhitelisted(String): + Method 'isAutoRevokeWhitelisted' documentation mentions permissions already declared by @RequiresPermission +RequiresPermission: android.content.pm.PackageManager#isPackageSuspended(): + Method 'isPackageSuspended' documentation mentions permissions without declaring @RequiresPermission +RequiresPermission: android.hardware.Sensor#getHighestDirectReportRateLevel(): + Method 'getHighestDirectReportRateLevel' documentation mentions permissions without declaring @RequiresPermission +RequiresPermission: android.hardware.Sensor#getMinDelay(): + Method 'getMinDelay' documentation mentions permissions without declaring @RequiresPermission +RequiresPermission: android.hardware.camera2.CameraCharacteristics#getKeysNeedingPermission(): + Method 'getKeysNeedingPermission' documentation mentions permissions without declaring @RequiresPermission +RequiresPermission: android.hardware.usb.UsbManager#hasPermission(android.hardware.usb.UsbDevice): + Method 'hasPermission' documentation mentions permissions without declaring @RequiresPermission +RequiresPermission: android.hardware.usb.UsbManager#requestPermission(android.hardware.usb.UsbDevice, android.app.PendingIntent): + Method 'requestPermission' documentation mentions permissions without declaring @RequiresPermission +RequiresPermission: android.media.AudioAttributes.Builder#setHapticChannelsMuted(boolean): + Method 'setHapticChannelsMuted' documentation mentions permissions without declaring @RequiresPermission +RequiresPermission: android.media.MediaExtractor#setDataSource(String): + Method 'setDataSource' documentation mentions permissions without declaring @RequiresPermission +RequiresPermission: android.media.MediaExtractor#setDataSource(String, java.util.Map<java.lang.String,java.lang.String>): + Method 'setDataSource' documentation mentions permissions without declaring @RequiresPermission +RequiresPermission: android.media.MediaExtractor#setDataSource(android.content.Context, android.net.Uri, java.util.Map<java.lang.String,java.lang.String>): + Method 'setDataSource' documentation mentions permissions without declaring @RequiresPermission +RequiresPermission: android.media.MediaPlayer#setWakeMode(android.content.Context, int): + Method 'setWakeMode' documentation mentions permissions without declaring @RequiresPermission +RequiresPermission: android.media.RingtoneManager#getCursor(): + Method 'getCursor' documentation mentions permissions without declaring @RequiresPermission +RequiresPermission: android.media.RingtoneManager#getValidRingtoneUri(android.content.Context): + Method 'getValidRingtoneUri' documentation mentions permissions without declaring @RequiresPermission +RequiresPermission: android.media.audiofx.HapticGenerator#setEnabled(boolean): + Method 'setEnabled' documentation mentions permissions without declaring @RequiresPermission +RequiresPermission: android.media.projection.MediaProjection#createVirtualDisplay(String, int, int, int, int, android.view.Surface, android.hardware.display.VirtualDisplay.Callback, android.os.Handler): + Method 'createVirtualDisplay' documentation mentions permissions without declaring @RequiresPermission +RequiresPermission: android.media.projection.MediaProjectionManager#getMediaProjection(int, android.content.Intent): + Method 'getMediaProjection' documentation mentions permissions without declaring @RequiresPermission +RequiresPermission: android.media.session.MediaSessionManager#addOnActiveSessionsChangedListener(android.media.session.MediaSessionManager.OnActiveSessionsChangedListener, android.content.ComponentName): + Method 'addOnActiveSessionsChangedListener' documentation mentions permissions without declaring @RequiresPermission +RequiresPermission: android.media.session.MediaSessionManager#addOnActiveSessionsChangedListener(android.media.session.MediaSessionManager.OnActiveSessionsChangedListener, android.content.ComponentName, android.os.Handler): + Method 'addOnActiveSessionsChangedListener' documentation mentions permissions without declaring @RequiresPermission +RequiresPermission: android.media.session.MediaSessionManager#addOnMediaKeyEventSessionChangedListener(java.util.concurrent.Executor, android.media.session.MediaSessionManager.OnMediaKeyEventSessionChangedListener): + Method 'addOnMediaKeyEventSessionChangedListener' documentation mentions permissions without declaring @RequiresPermission +RequiresPermission: android.media.session.MediaSessionManager#getActiveSessions(android.content.ComponentName): + Method 'getActiveSessions' documentation mentions permissions without declaring @RequiresPermission +RequiresPermission: android.media.session.MediaSessionManager#getMediaKeyEventSession(): + Method 'getMediaKeyEventSession' documentation mentions permissions without declaring @RequiresPermission +RequiresPermission: android.media.session.MediaSessionManager#getMediaKeyEventSessionPackageName(): + Method 'getMediaKeyEventSessionPackageName' documentation mentions permissions without declaring @RequiresPermission +RequiresPermission: android.media.session.MediaSessionManager#isTrustedForMediaControl(android.media.session.MediaSessionManager.RemoteUserInfo): + Method 'isTrustedForMediaControl' documentation mentions permissions without declaring @RequiresPermission +RequiresPermission: android.net.sip.SipAudioCall#setSpeakerMode(boolean): + Method 'setSpeakerMode' documentation mentions permissions without declaring @RequiresPermission +RequiresPermission: android.net.sip.SipAudioCall#startAudio(): + Method 'startAudio' documentation mentions permissions without declaring @RequiresPermission +RequiresPermission: android.nfc.NfcAdapter#disableForegroundDispatch(android.app.Activity): + Method 'disableForegroundDispatch' documentation mentions permissions without declaring @RequiresPermission +RequiresPermission: android.nfc.NfcAdapter#enableForegroundDispatch(android.app.Activity, android.app.PendingIntent, android.content.IntentFilter[], String[][]): + Method 'enableForegroundDispatch' documentation mentions permissions without declaring @RequiresPermission +RequiresPermission: android.nfc.cardemulation.CardEmulation#isDefaultServiceForAid(android.content.ComponentName, String): + Method 'isDefaultServiceForAid' documentation mentions permissions without declaring @RequiresPermission +RequiresPermission: android.nfc.cardemulation.CardEmulation#isDefaultServiceForCategory(android.content.ComponentName, String): + Method 'isDefaultServiceForCategory' documentation mentions permissions without declaring @RequiresPermission +RequiresPermission: android.nfc.cardemulation.CardEmulation#setOffHostForService(android.content.ComponentName, String): + Method 'setOffHostForService' documentation mentions permissions already declared by @RequiresPermission +RequiresPermission: android.nfc.tech.IsoDep#getTimeout(): + Method 'getTimeout' documentation mentions permissions without declaring @RequiresPermission +RequiresPermission: android.nfc.tech.IsoDep#setTimeout(int): + Method 'setTimeout' documentation mentions permissions without declaring @RequiresPermission +RequiresPermission: android.nfc.tech.IsoDep#transceive(byte[]): + Method 'transceive' documentation mentions permissions without declaring @RequiresPermission +RequiresPermission: android.nfc.tech.MifareClassic#authenticateSectorWithKeyA(int, byte[]): + Method 'authenticateSectorWithKeyA' documentation mentions permissions without declaring @RequiresPermission +RequiresPermission: android.nfc.tech.MifareClassic#authenticateSectorWithKeyB(int, byte[]): + Method 'authenticateSectorWithKeyB' documentation mentions permissions without declaring @RequiresPermission +RequiresPermission: android.nfc.tech.MifareClassic#decrement(int, int): + Method 'decrement' documentation mentions permissions without declaring @RequiresPermission +RequiresPermission: android.nfc.tech.MifareClassic#getTimeout(): + Method 'getTimeout' documentation mentions permissions without declaring @RequiresPermission +RequiresPermission: android.nfc.tech.MifareClassic#increment(int, int): + Method 'increment' documentation mentions permissions without declaring @RequiresPermission +RequiresPermission: android.nfc.tech.MifareClassic#readBlock(int): + Method 'readBlock' documentation mentions permissions without declaring @RequiresPermission +RequiresPermission: android.nfc.tech.MifareClassic#restore(int): + Method 'restore' documentation mentions permissions without declaring @RequiresPermission +RequiresPermission: android.nfc.tech.MifareClassic#setTimeout(int): + Method 'setTimeout' documentation mentions permissions without declaring @RequiresPermission +RequiresPermission: android.nfc.tech.MifareClassic#transceive(byte[]): + Method 'transceive' documentation mentions permissions without declaring @RequiresPermission +RequiresPermission: android.nfc.tech.MifareClassic#transfer(int): + Method 'transfer' documentation mentions permissions without declaring @RequiresPermission +RequiresPermission: android.nfc.tech.MifareClassic#writeBlock(int, byte[]): + Method 'writeBlock' documentation mentions permissions without declaring @RequiresPermission +RequiresPermission: android.nfc.tech.MifareUltralight#getTimeout(): + Method 'getTimeout' documentation mentions permissions without declaring @RequiresPermission +RequiresPermission: android.nfc.tech.MifareUltralight#readPages(int): + Method 'readPages' documentation mentions permissions without declaring @RequiresPermission +RequiresPermission: android.nfc.tech.MifareUltralight#setTimeout(int): + Method 'setTimeout' documentation mentions permissions without declaring @RequiresPermission +RequiresPermission: android.nfc.tech.MifareUltralight#transceive(byte[]): + Method 'transceive' documentation mentions permissions without declaring @RequiresPermission +RequiresPermission: android.nfc.tech.MifareUltralight#writePage(int, byte[]): + Method 'writePage' documentation mentions permissions without declaring @RequiresPermission +RequiresPermission: android.nfc.tech.Ndef#getNdefMessage(): + Method 'getNdefMessage' documentation mentions permissions without declaring @RequiresPermission +RequiresPermission: android.nfc.tech.Ndef#isWritable(): + Method 'isWritable' documentation mentions permissions without declaring @RequiresPermission +RequiresPermission: android.nfc.tech.Ndef#makeReadOnly(): + Method 'makeReadOnly' documentation mentions permissions without declaring @RequiresPermission +RequiresPermission: android.nfc.tech.Ndef#writeNdefMessage(android.nfc.NdefMessage): + Method 'writeNdefMessage' documentation mentions permissions without declaring @RequiresPermission +RequiresPermission: android.nfc.tech.NdefFormatable#format(android.nfc.NdefMessage): + Method 'format' documentation mentions permissions without declaring @RequiresPermission +RequiresPermission: android.nfc.tech.NdefFormatable#formatReadOnly(android.nfc.NdefMessage): + Method 'formatReadOnly' documentation mentions permissions without declaring @RequiresPermission +RequiresPermission: android.nfc.tech.NfcA#getTimeout(): + Method 'getTimeout' documentation mentions permissions without declaring @RequiresPermission +RequiresPermission: android.nfc.tech.NfcA#setTimeout(int): + Method 'setTimeout' documentation mentions permissions without declaring @RequiresPermission +RequiresPermission: android.nfc.tech.NfcA#transceive(byte[]): + Method 'transceive' documentation mentions permissions without declaring @RequiresPermission +RequiresPermission: android.nfc.tech.NfcB#transceive(byte[]): + Method 'transceive' documentation mentions permissions without declaring @RequiresPermission +RequiresPermission: android.nfc.tech.NfcF#getTimeout(): + Method 'getTimeout' documentation mentions permissions without declaring @RequiresPermission +RequiresPermission: android.nfc.tech.NfcF#setTimeout(int): + Method 'setTimeout' documentation mentions permissions without declaring @RequiresPermission +RequiresPermission: android.nfc.tech.NfcF#transceive(byte[]): + Method 'transceive' documentation mentions permissions without declaring @RequiresPermission +RequiresPermission: android.nfc.tech.NfcV#transceive(byte[]): + Method 'transceive' documentation mentions permissions without declaring @RequiresPermission +RequiresPermission: android.nfc.tech.TagTechnology#close(): + Method 'close' documentation mentions permissions without declaring @RequiresPermission +RequiresPermission: android.nfc.tech.TagTechnology#connect(): + Method 'connect' documentation mentions permissions without declaring @RequiresPermission +RequiresPermission: android.os.BugreportManager#cancelBugreport(): + Method 'cancelBugreport' documentation mentions permissions without declaring @RequiresPermission +RequiresPermission: android.os.Build#getSerial(): + Method 'getSerial' documentation mentions permissions already declared by @RequiresPermission +RequiresPermission: android.os.Debug#dumpService(String, java.io.FileDescriptor, String[]): + Method 'dumpService' documentation mentions permissions without declaring @RequiresPermission +RequiresPermission: android.os.DropBoxManager#getNextEntry(String, long): + Method 'getNextEntry' documentation mentions permissions already declared by @RequiresPermission +RequiresPermission: android.os.Environment#getExternalStorageDirectory(): + Method 'getExternalStorageDirectory' documentation mentions permissions without declaring @RequiresPermission +RequiresPermission: android.os.Environment#isExternalStorageManager(): + Method 'isExternalStorageManager' documentation mentions permissions without declaring @RequiresPermission +RequiresPermission: android.os.Environment#isExternalStorageManager(java.io.File): + Method 'isExternalStorageManager' documentation mentions permissions without declaring @RequiresPermission +RequiresPermission: android.os.PowerManager#newWakeLock(int, String): + Method 'newWakeLock' documentation mentions permissions without declaring @RequiresPermission +RequiresPermission: android.os.PowerManager#reboot(String): + Method 'reboot' documentation mentions permissions already declared by @RequiresPermission +RequiresPermission: android.os.RecoverySystem#rebootWipeUserData(android.content.Context): + Method 'rebootWipeUserData' documentation mentions permissions without declaring @RequiresPermission +RequiresPermission: android.os.StrictMode.VmPolicy.Builder#detectFileUriExposure(): + Method 'detectFileUriExposure' documentation mentions permissions without declaring @RequiresPermission +RequiresPermission: android.os.UserManager#getUserRestrictions(android.os.UserHandle): + Method 'getUserRestrictions' documentation mentions permissions already declared by @RequiresPermission +RequiresPermission: android.os.UserManager#isUserUnlocked(android.os.UserHandle): + Method 'isUserUnlocked' documentation mentions permissions already declared by @RequiresPermission +RequiresPermission: android.os.UserManager#requestQuietModeEnabled(boolean, android.os.UserHandle): + Method 'requestQuietModeEnabled' documentation mentions permissions already declared by @RequiresPermission +RequiresPermission: android.os.UserManager#setUserRestriction(String, boolean): + Method 'setUserRestriction' documentation mentions permissions already declared by @RequiresPermission +RequiresPermission: android.os.health.SystemHealthManager#takeUidSnapshot(int): + Method 'takeUidSnapshot' documentation mentions permissions without declaring @RequiresPermission +RequiresPermission: android.os.health.SystemHealthManager#takeUidSnapshots(int[]): + Method 'takeUidSnapshots' documentation mentions permissions without declaring @RequiresPermission +RequiresPermission: android.os.storage.StorageManager#getManageSpaceActivityIntent(String, int): + Method 'getManageSpaceActivityIntent' documentation mentions permissions already declared by @RequiresPermission +RequiresPermission: android.os.storage.StorageVolume#createAccessIntent(String): + Method 'createAccessIntent' documentation mentions permissions without declaring @RequiresPermission +RequiresPermission: android.provider.Settings#canDrawOverlays(android.content.Context): + Method 'canDrawOverlays' documentation mentions permissions without declaring @RequiresPermission +RequiresPermission: android.provider.Settings.System#canWrite(android.content.Context): + Method 'canWrite' documentation mentions permissions without declaring @RequiresPermission +RequiresPermission: android.security.KeyChain#removeCredentialManagementApp(android.content.Context): + Method 'removeCredentialManagementApp' documentation mentions permissions already declared by @RequiresPermission +RequiresPermission: android.service.credentials.BeginCreateCredentialResponse.Builder#setRemoteCreateEntry(android.service.credentials.RemoteEntry): + Method 'setRemoteCreateEntry' documentation mentions permissions already declared by @RequiresPermission +RequiresPermission: android.service.credentials.BeginGetCredentialResponse.Builder#setRemoteCredentialEntry(android.service.credentials.RemoteEntry): + Method 'setRemoteCredentialEntry' documentation mentions permissions already declared by @RequiresPermission +RequiresPermission: android.service.credentials.CallingAppInfo#getOrigin(): + Method 'getOrigin' documentation mentions permissions without declaring @RequiresPermission +RequiresPermission: android.telecom.Call.Details#getContactDisplayName(): + Method 'getContactDisplayName' documentation mentions permissions without declaring @RequiresPermission +RequiresPermission: android.telecom.Call.Details#getContactPhotoUri(): + Method 'getContactPhotoUri' documentation mentions permissions without declaring @RequiresPermission +RequiresPermission: android.telecom.TelecomManager#acceptHandover(android.net.Uri, int, android.telecom.PhoneAccountHandle): + Method 'acceptHandover' documentation mentions permissions without declaring @RequiresPermission +RequiresPermission: android.telecom.TelecomManager#addNewIncomingCall(android.telecom.PhoneAccountHandle, android.os.Bundle): + Method 'addNewIncomingCall' documentation mentions permissions without declaring @RequiresPermission +RequiresPermission: android.telecom.TelecomManager#addNewIncomingConference(android.telecom.PhoneAccountHandle, android.os.Bundle): + Method 'addNewIncomingConference' documentation mentions permissions without declaring @RequiresPermission +RequiresPermission: android.telecom.TelecomManager#getLine1Number(android.telecom.PhoneAccountHandle): + Method 'getLine1Number' documentation mentions permissions already declared by @RequiresPermission +RequiresPermission: android.telecom.TelecomManager#getOwnSelfManagedPhoneAccounts(): + Method 'getOwnSelfManagedPhoneAccounts' documentation mentions permissions already declared by @RequiresPermission +RequiresPermission: android.telecom.TelecomManager#getPhoneAccount(android.telecom.PhoneAccountHandle): + Method 'getPhoneAccount' documentation mentions permissions without declaring @RequiresPermission +RequiresPermission: android.telecom.TelecomManager#getSelfManagedPhoneAccounts(): + Method 'getSelfManagedPhoneAccounts' documentation mentions permissions already declared by @RequiresPermission +RequiresPermission: android.telecom.TelecomManager#hasManageOngoingCallsPermission(): + Method 'hasManageOngoingCallsPermission' documentation mentions permissions without declaring @RequiresPermission +RequiresPermission: android.telecom.TelecomManager#placeCall(android.net.Uri, android.os.Bundle): + Method 'placeCall' documentation mentions permissions already declared by @RequiresPermission +RequiresPermission: android.telecom.TelecomManager#showInCallScreen(boolean): + Method 'showInCallScreen' documentation mentions permissions already declared by @RequiresPermission +RequiresPermission: android.telecom.TelecomManager#silenceRinger(): + Method 'silenceRinger' documentation mentions permissions already declared by @RequiresPermission +RequiresPermission: android.telephony.CarrierConfigManager#getConfig(): + Method 'getConfig' documentation mentions permissions already declared by @RequiresPermission +RequiresPermission: android.telephony.CarrierConfigManager#getConfig(java.lang.String...): + Method 'getConfig' documentation mentions permissions already declared by @RequiresPermission +RequiresPermission: android.telephony.CarrierConfigManager#getConfigByComponentForSubId(String, int): + Method 'getConfigByComponentForSubId' documentation mentions permissions already declared by @RequiresPermission +RequiresPermission: android.telephony.CarrierConfigManager#getConfigForSubId(int): + Method 'getConfigForSubId' documentation mentions permissions already declared by @RequiresPermission +RequiresPermission: android.telephony.CarrierConfigManager#getConfigForSubId(int, java.lang.String...): + Method 'getConfigForSubId' documentation mentions permissions already declared by @RequiresPermission +RequiresPermission: android.telephony.CarrierConfigManager#notifyConfigChangedForSubId(int): + Method 'notifyConfigChangedForSubId' documentation mentions permissions already declared by @RequiresPermission +RequiresPermission: android.telephony.CellLocation#requestLocationUpdate(): + Method 'requestLocationUpdate' documentation mentions permissions without declaring @RequiresPermission +RequiresPermission: android.telephony.NetworkRegistrationInfo#getCellIdentity(): + Method 'getCellIdentity' documentation mentions permissions without declaring @RequiresPermission +RequiresPermission: android.telephony.PhoneStateListener#onActiveDataSubscriptionIdChanged(int): + Method 'onActiveDataSubscriptionIdChanged' documentation mentions permissions already declared by @RequiresPermission +RequiresPermission: android.telephony.PhoneStateListener#onCallStateChanged(int, String): + Method 'onCallStateChanged' documentation mentions permissions already declared by @RequiresPermission +RequiresPermission: android.telephony.PhoneStateListener#onDisplayInfoChanged(android.telephony.TelephonyDisplayInfo): + Method 'onDisplayInfoChanged' documentation mentions permissions already declared by @RequiresPermission +RequiresPermission: android.telephony.PhoneStateListener#onPreciseDataConnectionStateChanged(android.telephony.PreciseDataConnectionState): + Method 'onPreciseDataConnectionStateChanged' documentation mentions permissions already declared by @RequiresPermission +RequiresPermission: android.telephony.PhoneStateListener#onServiceStateChanged(android.telephony.ServiceState): + Method 'onServiceStateChanged' documentation mentions permissions without declaring @RequiresPermission +RequiresPermission: android.telephony.ServiceState#getCdmaNetworkId(): + Method 'getCdmaNetworkId' documentation mentions permissions already declared by @RequiresPermission +RequiresPermission: android.telephony.ServiceState#getCdmaSystemId(): + Method 'getCdmaSystemId' documentation mentions permissions already declared by @RequiresPermission +RequiresPermission: android.telephony.ServiceState#getOperatorAlphaLong(): + Method 'getOperatorAlphaLong' documentation mentions permissions already declared by @RequiresPermission +RequiresPermission: android.telephony.ServiceState#getOperatorAlphaShort(): + Method 'getOperatorAlphaShort' documentation mentions permissions already declared by @RequiresPermission +RequiresPermission: android.telephony.ServiceState#getOperatorNumeric(): + Method 'getOperatorNumeric' documentation mentions permissions already declared by @RequiresPermission +RequiresPermission: android.telephony.SmsManager#getSmscAddress(): + Method 'getSmscAddress' documentation mentions permissions already declared by @RequiresPermission +RequiresPermission: android.telephony.SmsManager#injectSmsPdu(byte[], String, android.app.PendingIntent): + Method 'injectSmsPdu' documentation mentions permissions without declaring @RequiresPermission +RequiresPermission: android.telephony.SmsManager#sendDataMessage(String, String, short, byte[], android.app.PendingIntent, android.app.PendingIntent): + Method 'sendDataMessage' documentation mentions permissions without declaring @RequiresPermission +RequiresPermission: android.telephony.SmsManager#sendMultipartTextMessage(String, String, java.util.ArrayList<java.lang.String>, java.util.ArrayList<android.app.PendingIntent>, java.util.ArrayList<android.app.PendingIntent>): + Method 'sendMultipartTextMessage' documentation mentions permissions without declaring @RequiresPermission +RequiresPermission: android.telephony.SmsManager#sendTextMessage(String, String, String, android.app.PendingIntent, android.app.PendingIntent): + Method 'sendTextMessage' documentation mentions permissions without declaring @RequiresPermission +RequiresPermission: android.telephony.SmsManager#sendTextMessageWithoutPersisting(String, String, String, android.app.PendingIntent, android.app.PendingIntent): + Method 'sendTextMessageWithoutPersisting' documentation mentions permissions already declared by @RequiresPermission +RequiresPermission: android.telephony.SmsManager#setSmscAddress(String): + Method 'setSmscAddress' documentation mentions permissions already declared by @RequiresPermission +RequiresPermission: android.telephony.SubscriptionManager#addSubscriptionsIntoGroup(java.util.List<java.lang.Integer>, android.os.ParcelUuid): + Method 'addSubscriptionsIntoGroup' documentation mentions permissions already declared by @RequiresPermission +RequiresPermission: android.telephony.SubscriptionManager#createSubscriptionGroup(java.util.List<java.lang.Integer>): + Method 'createSubscriptionGroup' documentation mentions permissions already declared by @RequiresPermission +RequiresPermission: android.telephony.SubscriptionManager#getActiveSubscriptionInfo(int): + Method 'getActiveSubscriptionInfo' documentation mentions permissions already declared by @RequiresPermission +RequiresPermission: android.telephony.SubscriptionManager#getActiveSubscriptionInfoForSimSlotIndex(int): + Method 'getActiveSubscriptionInfoForSimSlotIndex' documentation mentions permissions already declared by @RequiresPermission +RequiresPermission: android.telephony.SubscriptionManager#getActiveSubscriptionInfoList(): + Method 'getActiveSubscriptionInfoList' documentation mentions permissions already declared by @RequiresPermission +RequiresPermission: android.telephony.SubscriptionManager#getCompleteActiveSubscriptionInfoList(): + Method 'getCompleteActiveSubscriptionInfoList' documentation mentions permissions without declaring @RequiresPermission +RequiresPermission: android.telephony.SubscriptionManager#getOpportunisticSubscriptions(): + Method 'getOpportunisticSubscriptions' documentation mentions permissions already declared by @RequiresPermission +RequiresPermission: android.telephony.SubscriptionManager#getSubscriptionsInGroup(android.os.ParcelUuid): + Method 'getSubscriptionsInGroup' documentation mentions permissions already declared by @RequiresPermission +RequiresPermission: android.telephony.SubscriptionManager#removeSubscriptionsFromGroup(java.util.List<java.lang.Integer>, android.os.ParcelUuid): + Method 'removeSubscriptionsFromGroup' documentation mentions permissions already declared by @RequiresPermission +RequiresPermission: android.telephony.SubscriptionManager#setOpportunistic(boolean, int): + Method 'setOpportunistic' documentation mentions permissions already declared by @RequiresPermission +RequiresPermission: android.telephony.TelephonyCallback.ActiveDataSubscriptionIdListener#onActiveDataSubscriptionIdChanged(int): + Method 'onActiveDataSubscriptionIdChanged' documentation mentions permissions already declared by @RequiresPermission +RequiresPermission: android.telephony.TelephonyCallback.BarringInfoListener#onBarringInfoChanged(android.telephony.BarringInfo): + Method 'onBarringInfoChanged' documentation mentions permissions already declared by @RequiresPermission +RequiresPermission: android.telephony.TelephonyCallback.CallForwardingIndicatorListener#onCallForwardingIndicatorChanged(boolean): + Method 'onCallForwardingIndicatorChanged' documentation mentions permissions already declared by @RequiresPermission +RequiresPermission: android.telephony.TelephonyCallback.EmergencyNumberListListener#onEmergencyNumberListChanged(java.util.Map<java.lang.Integer,java.util.List<android.telephony.emergency.EmergencyNumber>>): + Method 'onEmergencyNumberListChanged' documentation mentions permissions already declared by @RequiresPermission +RequiresPermission: android.telephony.TelephonyCallback.ImsCallDisconnectCauseListener#onImsCallDisconnectCauseChanged(android.telephony.ims.ImsReasonInfo): + Method 'onImsCallDisconnectCauseChanged' documentation mentions permissions already declared by @RequiresPermission +RequiresPermission: android.telephony.TelephonyCallback.MessageWaitingIndicatorListener#onMessageWaitingIndicatorChanged(boolean): + Method 'onMessageWaitingIndicatorChanged' documentation mentions permissions already declared by @RequiresPermission +RequiresPermission: android.telephony.TelephonyCallback.PhysicalChannelConfigListener#onPhysicalChannelConfigChanged(java.util.List<android.telephony.PhysicalChannelConfig>): + Method 'onPhysicalChannelConfigChanged' documentation mentions permissions already declared by @RequiresPermission +RequiresPermission: android.telephony.TelephonyCallback.PreciseDataConnectionStateListener#onPreciseDataConnectionStateChanged(android.telephony.PreciseDataConnectionState): + Method 'onPreciseDataConnectionStateChanged' documentation mentions permissions already declared by @RequiresPermission +RequiresPermission: android.telephony.TelephonyCallback.RegistrationFailedListener#onRegistrationFailed(android.telephony.CellIdentity, String, int, int, int): + Method 'onRegistrationFailed' documentation mentions permissions already declared by @RequiresPermission +RequiresPermission: android.telephony.TelephonyCallback.ServiceStateListener#onServiceStateChanged(android.telephony.ServiceState): + Method 'onServiceStateChanged' documentation mentions permissions without declaring @RequiresPermission +RequiresPermission: android.telephony.TelephonyManager#clearSignalStrengthUpdateRequest(android.telephony.SignalStrengthUpdateRequest): + Method 'clearSignalStrengthUpdateRequest' documentation mentions permissions already declared by @RequiresPermission +RequiresPermission: android.telephony.TelephonyManager#doesSwitchMultiSimConfigTriggerReboot(): + Method 'doesSwitchMultiSimConfigTriggerReboot' documentation mentions permissions already declared by @RequiresPermission +RequiresPermission: android.telephony.TelephonyManager#getAllowedNetworkTypesForReason(int): + Method 'getAllowedNetworkTypesForReason' documentation mentions permissions already declared by @RequiresPermission +RequiresPermission: android.telephony.TelephonyManager#getCallState(): + Method 'getCallState' documentation mentions permissions already declared by @RequiresPermission +RequiresPermission: android.telephony.TelephonyManager#getCallStateForSubscription(): + Method 'getCallStateForSubscription' documentation mentions permissions already declared by @RequiresPermission +RequiresPermission: android.telephony.TelephonyManager#getCarrierConfig(): + Method 'getCarrierConfig' documentation mentions permissions already declared by @RequiresPermission +RequiresPermission: android.telephony.TelephonyManager#getCarrierRestrictionStatus(java.util.concurrent.Executor, java.util.function.Consumer<java.lang.Integer>): + Method 'getCarrierRestrictionStatus' documentation mentions permissions already declared by @RequiresPermission +RequiresPermission: android.telephony.TelephonyManager#getDataNetworkType(): + Method 'getDataNetworkType' documentation mentions permissions already declared by @RequiresPermission +RequiresPermission: android.telephony.TelephonyManager#getDeviceId(): + Method 'getDeviceId' documentation mentions permissions already declared by @RequiresPermission +RequiresPermission: android.telephony.TelephonyManager#getDeviceId(int): + Method 'getDeviceId' documentation mentions permissions already declared by @RequiresPermission +RequiresPermission: android.telephony.TelephonyManager#getEmergencyNumberList(): + Method 'getEmergencyNumberList' documentation mentions permissions already declared by @RequiresPermission +RequiresPermission: android.telephony.TelephonyManager#getEmergencyNumberList(int): + Method 'getEmergencyNumberList' documentation mentions permissions already declared by @RequiresPermission +RequiresPermission: android.telephony.TelephonyManager#getEquivalentHomePlmns(): + Method 'getEquivalentHomePlmns' documentation mentions permissions already declared by @RequiresPermission +RequiresPermission: android.telephony.TelephonyManager#getForbiddenPlmns(): + Method 'getForbiddenPlmns' documentation mentions permissions already declared by @RequiresPermission +RequiresPermission: android.telephony.TelephonyManager#getGroupIdLevel1(): + Method 'getGroupIdLevel1' documentation mentions permissions already declared by @RequiresPermission +RequiresPermission: android.telephony.TelephonyManager#getImei(int): + Method 'getImei' documentation mentions permissions already declared by @RequiresPermission +RequiresPermission: android.telephony.TelephonyManager#getLine1Number(): + Method 'getLine1Number' documentation mentions permissions already declared by @RequiresPermission +RequiresPermission: android.telephony.TelephonyManager#getManualNetworkSelectionPlmn(): + Method 'getManualNetworkSelectionPlmn' documentation mentions permissions already declared by @RequiresPermission +RequiresPermission: android.telephony.TelephonyManager#getMeid(): + Method 'getMeid' documentation mentions permissions already declared by @RequiresPermission +RequiresPermission: android.telephony.TelephonyManager#getMeid(int): + Method 'getMeid' documentation mentions permissions already declared by @RequiresPermission +RequiresPermission: android.telephony.TelephonyManager#getNai(): + Method 'getNai' documentation mentions permissions already declared by @RequiresPermission +RequiresPermission: android.telephony.TelephonyManager#getNetworkSelectionMode(): + Method 'getNetworkSelectionMode' documentation mentions permissions already declared by @RequiresPermission +RequiresPermission: android.telephony.TelephonyManager#getNetworkSlicingConfiguration(java.util.concurrent.Executor, android.os.OutcomeReceiver<android.telephony.data.NetworkSlicingConfig,android.telephony.TelephonyManager.NetworkSlicingException>): + Method 'getNetworkSlicingConfiguration' documentation mentions permissions already declared by @RequiresPermission +RequiresPermission: android.telephony.TelephonyManager#getPhoneAccountHandle(): + Method 'getPhoneAccountHandle' documentation mentions permissions already declared by @RequiresPermission +RequiresPermission: android.telephony.TelephonyManager#getPreferredOpportunisticDataSubscription(): + Method 'getPreferredOpportunisticDataSubscription' documentation mentions permissions already declared by @RequiresPermission +RequiresPermission: android.telephony.TelephonyManager#getServiceState(): + Method 'getServiceState' documentation mentions permissions already declared by @RequiresPermission +RequiresPermission: android.telephony.TelephonyManager#getServiceState(int): + Method 'getServiceState' documentation mentions permissions already declared by @RequiresPermission +RequiresPermission: android.telephony.TelephonyManager#getSimSerialNumber(): + Method 'getSimSerialNumber' documentation mentions permissions already declared by @RequiresPermission +RequiresPermission: android.telephony.TelephonyManager#getSubscriberId(): + Method 'getSubscriberId' documentation mentions permissions already declared by @RequiresPermission +RequiresPermission: android.telephony.TelephonyManager#getSupportedRadioAccessFamily(): + Method 'getSupportedRadioAccessFamily' documentation mentions permissions already declared by @RequiresPermission +RequiresPermission: android.telephony.TelephonyManager#getVisualVoicemailPackageName(): + Method 'getVisualVoicemailPackageName' documentation mentions permissions already declared by @RequiresPermission +RequiresPermission: android.telephony.TelephonyManager#getVoiceMailAlphaTag(): + Method 'getVoiceMailAlphaTag' documentation mentions permissions already declared by @RequiresPermission +RequiresPermission: android.telephony.TelephonyManager#getVoiceMailNumber(): + Method 'getVoiceMailNumber' documentation mentions permissions already declared by @RequiresPermission +RequiresPermission: android.telephony.TelephonyManager#getVoiceNetworkType(): + Method 'getVoiceNetworkType' documentation mentions permissions already declared by @RequiresPermission +RequiresPermission: android.telephony.TelephonyManager#iccCloseLogicalChannel(int): + Method 'iccCloseLogicalChannel' documentation mentions permissions without declaring @RequiresPermission +RequiresPermission: android.telephony.TelephonyManager#iccExchangeSimIO(int, int, int, int, int, String): + Method 'iccExchangeSimIO' documentation mentions permissions without declaring @RequiresPermission +RequiresPermission: android.telephony.TelephonyManager#iccOpenLogicalChannel(String): + Method 'iccOpenLogicalChannel' documentation mentions permissions without declaring @RequiresPermission +RequiresPermission: android.telephony.TelephonyManager#iccOpenLogicalChannel(String, int): + Method 'iccOpenLogicalChannel' documentation mentions permissions without declaring @RequiresPermission +RequiresPermission: android.telephony.TelephonyManager#iccTransmitApduBasicChannel(int, int, int, int, int, String): + Method 'iccTransmitApduBasicChannel' documentation mentions permissions without declaring @RequiresPermission +RequiresPermission: android.telephony.TelephonyManager#iccTransmitApduLogicalChannel(int, int, int, int, int, int, String): + Method 'iccTransmitApduLogicalChannel' documentation mentions permissions without declaring @RequiresPermission +RequiresPermission: android.telephony.TelephonyManager#isDataEnabled(): + Method 'isDataEnabled' documentation mentions permissions already declared by @RequiresPermission +RequiresPermission: android.telephony.TelephonyManager#isDataEnabledForReason(int): + Method 'isDataEnabledForReason' documentation mentions permissions already declared by @RequiresPermission +RequiresPermission: android.telephony.TelephonyManager#isDataRoamingEnabled(): + Method 'isDataRoamingEnabled' documentation mentions permissions already declared by @RequiresPermission +RequiresPermission: android.telephony.TelephonyManager#isManualNetworkSelectionAllowed(): + Method 'isManualNetworkSelectionAllowed' documentation mentions permissions already declared by @RequiresPermission +RequiresPermission: android.telephony.TelephonyManager#isModemEnabledForSlot(int): + Method 'isModemEnabledForSlot' documentation mentions permissions already declared by @RequiresPermission +RequiresPermission: android.telephony.TelephonyManager#isMultiSimSupported(): + Method 'isMultiSimSupported' documentation mentions permissions already declared by @RequiresPermission +RequiresPermission: android.telephony.TelephonyManager#isPremiumCapabilityAvailableForPurchase(int): + Method 'isPremiumCapabilityAvailableForPurchase' documentation mentions permissions already declared by @RequiresPermission +RequiresPermission: android.telephony.TelephonyManager#purchasePremiumCapability(int, java.util.concurrent.Executor, java.util.function.Consumer<java.lang.Integer>): + Method 'purchasePremiumCapability' documentation mentions permissions already declared by @RequiresPermission +RequiresPermission: android.telephony.TelephonyManager#rebootModem(): + Method 'rebootModem' documentation mentions permissions already declared by @RequiresPermission +RequiresPermission: android.telephony.TelephonyManager#requestNetworkScan(android.telephony.NetworkScanRequest, java.util.concurrent.Executor, android.telephony.TelephonyScanManager.NetworkScanCallback): + Method 'requestNetworkScan' documentation mentions permissions already declared by @RequiresPermission +RequiresPermission: android.telephony.TelephonyManager#requestNetworkScan(int, android.telephony.NetworkScanRequest, java.util.concurrent.Executor, android.telephony.TelephonyScanManager.NetworkScanCallback): + Method 'requestNetworkScan' documentation mentions permissions already declared by @RequiresPermission +RequiresPermission: android.telephony.TelephonyManager#sendEnvelopeWithStatus(String): + Method 'sendEnvelopeWithStatus' documentation mentions permissions without declaring @RequiresPermission +RequiresPermission: android.telephony.TelephonyManager#sendUssdRequest(String, android.telephony.TelephonyManager.UssdResponseCallback, android.os.Handler): + Method 'sendUssdRequest' documentation mentions permissions already declared by @RequiresPermission +RequiresPermission: android.telephony.TelephonyManager#sendVisualVoicemailSms(String, int, String, android.app.PendingIntent): + Method 'sendVisualVoicemailSms' documentation mentions permissions without declaring @RequiresPermission +RequiresPermission: android.telephony.TelephonyManager#setAllowedNetworkTypesForReason(int, long): + Method 'setAllowedNetworkTypesForReason' documentation mentions permissions already declared by @RequiresPermission +RequiresPermission: android.telephony.TelephonyManager#setDataEnabled(boolean): + Method 'setDataEnabled' documentation mentions permissions already declared by @RequiresPermission +RequiresPermission: android.telephony.TelephonyManager#setDataEnabledForReason(int, boolean): + Method 'setDataEnabledForReason' documentation mentions permissions already declared by @RequiresPermission +RequiresPermission: android.telephony.TelephonyManager#setForbiddenPlmns(java.util.List<java.lang.String>): + Method 'setForbiddenPlmns' documentation mentions permissions already declared by @RequiresPermission +RequiresPermission: android.telephony.TelephonyManager#setNetworkSelectionModeAutomatic(): + Method 'setNetworkSelectionModeAutomatic' documentation mentions permissions already declared by @RequiresPermission +RequiresPermission: android.telephony.TelephonyManager#setNetworkSelectionModeManual(String, boolean): + Method 'setNetworkSelectionModeManual' documentation mentions permissions already declared by @RequiresPermission +RequiresPermission: android.telephony.TelephonyManager#setNetworkSelectionModeManual(String, boolean, int): + Method 'setNetworkSelectionModeManual' documentation mentions permissions already declared by @RequiresPermission +RequiresPermission: android.telephony.TelephonyManager#setPreferredOpportunisticDataSubscription(int, boolean, java.util.concurrent.Executor, java.util.function.Consumer<java.lang.Integer>): + Method 'setPreferredOpportunisticDataSubscription' documentation mentions permissions without declaring @RequiresPermission +RequiresPermission: android.telephony.TelephonyManager#setSignalStrengthUpdateRequest(android.telephony.SignalStrengthUpdateRequest): + Method 'setSignalStrengthUpdateRequest' documentation mentions permissions already declared by @RequiresPermission +RequiresPermission: android.telephony.TelephonyManager#setVoicemailRingtoneUri(android.telecom.PhoneAccountHandle, android.net.Uri): + Method 'setVoicemailRingtoneUri' documentation mentions permissions without declaring @RequiresPermission +RequiresPermission: android.telephony.TelephonyManager#setVoicemailVibrationEnabled(android.telecom.PhoneAccountHandle, boolean): + Method 'setVoicemailVibrationEnabled' documentation mentions permissions without declaring @RequiresPermission +RequiresPermission: android.telephony.TelephonyManager#switchMultiSimConfig(int): + Method 'switchMultiSimConfig' documentation mentions permissions already declared by @RequiresPermission +RequiresPermission: android.telephony.TelephonyManager#updateAvailableNetworks(java.util.List<android.telephony.AvailableNetworkInfo>, java.util.concurrent.Executor, java.util.function.Consumer<java.lang.Integer>): + Method 'updateAvailableNetworks' documentation mentions permissions without declaring @RequiresPermission +RequiresPermission: android.telephony.euicc.EuiccManager#deleteSubscription(int, android.app.PendingIntent): + Method 'deleteSubscription' documentation mentions permissions already declared by @RequiresPermission +RequiresPermission: android.telephony.euicc.EuiccManager#downloadSubscription(android.telephony.euicc.DownloadableSubscription, boolean, android.app.PendingIntent): + Method 'downloadSubscription' documentation mentions permissions already declared by @RequiresPermission +RequiresPermission: android.telephony.euicc.EuiccManager#switchToSubscription(int, android.app.PendingIntent): + Method 'switchToSubscription' documentation mentions permissions already declared by @RequiresPermission +RequiresPermission: android.telephony.euicc.EuiccManager#switchToSubscription(int, int, android.app.PendingIntent): + Method 'switchToSubscription' documentation mentions permissions already declared by @RequiresPermission +RequiresPermission: android.telephony.euicc.EuiccManager#updateSubscriptionNickname(int, String, android.app.PendingIntent): + Method 'updateSubscriptionNickname' documentation mentions permissions already declared by @RequiresPermission +RequiresPermission: android.telephony.ims.ImsMmTelManager#getRegistrationTransportType(java.util.concurrent.Executor, java.util.function.Consumer<java.lang.Integer>): + Method 'getRegistrationTransportType' documentation mentions permissions already declared by @RequiresPermission +RequiresPermission: android.telephony.ims.ImsMmTelManager#getVoWiFiModeSetting(): + Method 'getVoWiFiModeSetting' documentation mentions permissions already declared by @RequiresPermission +RequiresPermission: android.telephony.ims.ImsMmTelManager#isAdvancedCallingSettingEnabled(): + Method 'isAdvancedCallingSettingEnabled' documentation mentions permissions already declared by @RequiresPermission +RequiresPermission: android.telephony.ims.ImsMmTelManager#isCrossSimCallingEnabled(): + Method 'isCrossSimCallingEnabled' documentation mentions permissions already declared by @RequiresPermission +RequiresPermission: android.telephony.ims.ImsMmTelManager#isTtyOverVolteEnabled(): + Method 'isTtyOverVolteEnabled' documentation mentions permissions already declared by @RequiresPermission +RequiresPermission: android.telephony.ims.ImsMmTelManager#isVoWiFiRoamingSettingEnabled(): + Method 'isVoWiFiRoamingSettingEnabled' documentation mentions permissions already declared by @RequiresPermission +RequiresPermission: android.telephony.ims.ImsMmTelManager#isVoWiFiSettingEnabled(): + Method 'isVoWiFiSettingEnabled' documentation mentions permissions already declared by @RequiresPermission +RequiresPermission: android.telephony.ims.ImsMmTelManager#isVtSettingEnabled(): + Method 'isVtSettingEnabled' documentation mentions permissions already declared by @RequiresPermission +RequiresPermission: android.telephony.ims.ImsMmTelManager#registerImsRegistrationCallback(java.util.concurrent.Executor, android.telephony.ims.RegistrationManager.RegistrationCallback): + Method 'registerImsRegistrationCallback' documentation mentions permissions already declared by @RequiresPermission +RequiresPermission: android.telephony.ims.ImsMmTelManager#registerImsStateCallback(java.util.concurrent.Executor, android.telephony.ims.ImsStateCallback): + Method 'registerImsStateCallback' documentation mentions permissions already declared by @RequiresPermission +RequiresPermission: android.telephony.ims.ImsMmTelManager#registerMmTelCapabilityCallback(java.util.concurrent.Executor, android.telephony.ims.ImsMmTelManager.CapabilityCallback): + Method 'registerMmTelCapabilityCallback' documentation mentions permissions already declared by @RequiresPermission +RequiresPermission: android.telephony.ims.ImsMmTelManager#unregisterImsRegistrationCallback(android.telephony.ims.RegistrationManager.RegistrationCallback): + Method 'unregisterImsRegistrationCallback' documentation mentions permissions already declared by @RequiresPermission +RequiresPermission: android.telephony.ims.ImsMmTelManager#unregisterMmTelCapabilityCallback(android.telephony.ims.ImsMmTelManager.CapabilityCallback): + Method 'unregisterMmTelCapabilityCallback' documentation mentions permissions already declared by @RequiresPermission +RequiresPermission: android.telephony.ims.ImsRcsManager#getRegistrationState(java.util.concurrent.Executor, java.util.function.Consumer<java.lang.Integer>): + Method 'getRegistrationState' documentation mentions permissions already declared by @RequiresPermission +RequiresPermission: android.telephony.ims.ImsRcsManager#getRegistrationTransportType(java.util.concurrent.Executor, java.util.function.Consumer<java.lang.Integer>): + Method 'getRegistrationTransportType' documentation mentions permissions already declared by @RequiresPermission +RequiresPermission: android.telephony.ims.ImsRcsManager#registerImsRegistrationCallback(java.util.concurrent.Executor, android.telephony.ims.RegistrationManager.RegistrationCallback): + Method 'registerImsRegistrationCallback' documentation mentions permissions already declared by @RequiresPermission +RequiresPermission: android.telephony.ims.ImsRcsManager#registerImsStateCallback(java.util.concurrent.Executor, android.telephony.ims.ImsStateCallback): + Method 'registerImsStateCallback' documentation mentions permissions already declared by @RequiresPermission +RequiresPermission: android.telephony.ims.ImsRcsManager#unregisterImsRegistrationCallback(android.telephony.ims.RegistrationManager.RegistrationCallback): + Method 'unregisterImsRegistrationCallback' documentation mentions permissions already declared by @RequiresPermission +RequiresPermission: android.telephony.ims.ProvisioningManager#getProvisioningStatusForCapability(int, int): + Method 'getProvisioningStatusForCapability' documentation mentions permissions already declared by @RequiresPermission +RequiresPermission: android.telephony.ims.ProvisioningManager#getRcsProvisioningStatusForCapability(int, int): + Method 'getRcsProvisioningStatusForCapability' documentation mentions permissions already declared by @RequiresPermission +RequiresPermission: android.telephony.ims.ProvisioningManager#isProvisioningRequiredForCapability(int, int): + Method 'isProvisioningRequiredForCapability' documentation mentions permissions already declared by @RequiresPermission +RequiresPermission: android.telephony.ims.ProvisioningManager#isRcsProvisioningRequiredForCapability(int, int): + Method 'isRcsProvisioningRequiredForCapability' documentation mentions permissions already declared by @RequiresPermission +RequiresPermission: android.telephony.ims.ProvisioningManager#registerFeatureProvisioningChangedCallback(java.util.concurrent.Executor, android.telephony.ims.ProvisioningManager.FeatureProvisioningCallback): + Method 'registerFeatureProvisioningChangedCallback' documentation mentions permissions already declared by @RequiresPermission +RequiresPermission: android.telephony.ims.ProvisioningManager#setProvisioningStatusForCapability(int, int, boolean): + Method 'setProvisioningStatusForCapability' documentation mentions permissions already declared by @RequiresPermission +RequiresPermission: android.telephony.ims.ProvisioningManager#setRcsProvisioningStatusForCapability(int, int, boolean): + Method 'setRcsProvisioningStatusForCapability' documentation mentions permissions already declared by @RequiresPermission +RequiresPermission: android.view.inputmethod.InputMethodManager#setCurrentInputMethodSubtype(android.view.inputmethod.InputMethodSubtype): + Method 'setCurrentInputMethodSubtype' documentation mentions permissions already declared by @RequiresPermission +RequiresPermission: android.webkit.WebSettings#setBlockNetworkLoads(boolean): + Method 'setBlockNetworkLoads' documentation mentions permissions without declaring @RequiresPermission +RequiresPermission: android.webkit.WebSettings#setGeolocationEnabled(boolean): + Method 'setGeolocationEnabled' documentation mentions permissions without declaring @RequiresPermission + + +Todo: android.hardware.camera2.params.StreamConfigurationMap: + Documentation mentions 'TODO' +Todo: android.provider.ContactsContract.RawContacts#newEntityIterator(android.database.Cursor): + Documentation mentions 'TODO' + + UnflaggedApi: android.accessibilityservice.AccessibilityService#OVERLAY_RESULT_INTERNAL_ERROR: New API must be flagged with @FlaggedApi: field android.accessibilityservice.AccessibilityService.OVERLAY_RESULT_INTERNAL_ERROR UnflaggedApi: android.accessibilityservice.AccessibilityService#OVERLAY_RESULT_INVALID: diff --git a/core/api/module-lib-lint-baseline.txt b/core/api/module-lib-lint-baseline.txt index 163383515548..e49d6e3ac9c7 100644 --- a/core/api/module-lib-lint-baseline.txt +++ b/core/api/module-lib-lint-baseline.txt @@ -1,4 +1,1714 @@ // Baseline format: 1.0 +BroadcastBehavior: android.app.AlarmManager#ACTION_NEXT_ALARM_CLOCK_CHANGED: + Field 'ACTION_NEXT_ALARM_CLOCK_CHANGED' is missing @BroadcastBehavior +BroadcastBehavior: android.app.AlarmManager#ACTION_SCHEDULE_EXACT_ALARM_PERMISSION_STATE_CHANGED: + Field 'ACTION_SCHEDULE_EXACT_ALARM_PERMISSION_STATE_CHANGED' is missing @BroadcastBehavior +BroadcastBehavior: android.app.NotificationManager#ACTION_CLOSE_NOTIFICATION_HANDLER_PANEL: + Field 'ACTION_CLOSE_NOTIFICATION_HANDLER_PANEL' is missing @BroadcastBehavior +BroadcastBehavior: android.app.admin.DevicePolicyManager#ACTION_APPLICATION_DELEGATION_SCOPES_CHANGED: + Field 'ACTION_APPLICATION_DELEGATION_SCOPES_CHANGED' is missing @BroadcastBehavior +BroadcastBehavior: android.app.admin.DevicePolicyManager#ACTION_MANAGED_PROFILE_PROVISIONED: + Field 'ACTION_MANAGED_PROFILE_PROVISIONED' is missing @BroadcastBehavior +BroadcastBehavior: android.content.Intent#ACTION_AIRPLANE_MODE_CHANGED: + Field 'ACTION_AIRPLANE_MODE_CHANGED' is missing @BroadcastBehavior +BroadcastBehavior: android.content.Intent#ACTION_APPLICATION_LOCALE_CHANGED: + Field 'ACTION_APPLICATION_LOCALE_CHANGED' is missing @BroadcastBehavior +BroadcastBehavior: android.content.Intent#ACTION_APPLICATION_RESTRICTIONS_CHANGED: + Field 'ACTION_APPLICATION_RESTRICTIONS_CHANGED' is missing @BroadcastBehavior +BroadcastBehavior: android.content.Intent#ACTION_BATTERY_CHANGED: + Field 'ACTION_BATTERY_CHANGED' is missing @BroadcastBehavior +BroadcastBehavior: android.content.Intent#ACTION_BATTERY_LEVEL_CHANGED: + Field 'ACTION_BATTERY_LEVEL_CHANGED' is missing @BroadcastBehavior +BroadcastBehavior: android.content.Intent#ACTION_BATTERY_LOW: + Field 'ACTION_BATTERY_LOW' is missing @BroadcastBehavior +BroadcastBehavior: android.content.Intent#ACTION_BATTERY_OKAY: + Field 'ACTION_BATTERY_OKAY' is missing @BroadcastBehavior +BroadcastBehavior: android.content.Intent#ACTION_CAMERA_BUTTON: + Field 'ACTION_CAMERA_BUTTON' is missing @BroadcastBehavior +BroadcastBehavior: android.content.Intent#ACTION_CLOSE_SYSTEM_DIALOGS: + Field 'ACTION_CLOSE_SYSTEM_DIALOGS' is missing @BroadcastBehavior +BroadcastBehavior: android.content.Intent#ACTION_CONFIGURATION_CHANGED: + Field 'ACTION_CONFIGURATION_CHANGED' is missing @BroadcastBehavior +BroadcastBehavior: android.content.Intent#ACTION_DATE_CHANGED: + Field 'ACTION_DATE_CHANGED' is missing @BroadcastBehavior +BroadcastBehavior: android.content.Intent#ACTION_DEVICE_CUSTOMIZATION_READY: + Field 'ACTION_DEVICE_CUSTOMIZATION_READY' is missing @BroadcastBehavior +BroadcastBehavior: android.content.Intent#ACTION_DEVICE_STORAGE_LOW: + Field 'ACTION_DEVICE_STORAGE_LOW' is missing @BroadcastBehavior +BroadcastBehavior: android.content.Intent#ACTION_DEVICE_STORAGE_OK: + Field 'ACTION_DEVICE_STORAGE_OK' is missing @BroadcastBehavior +BroadcastBehavior: android.content.Intent#ACTION_DOCK_EVENT: + Field 'ACTION_DOCK_EVENT' is missing @BroadcastBehavior +BroadcastBehavior: android.content.Intent#ACTION_DOMAINS_NEED_VERIFICATION: + Field 'ACTION_DOMAINS_NEED_VERIFICATION' is missing @BroadcastBehavior +BroadcastBehavior: android.content.Intent#ACTION_DREAMING_STARTED: + Field 'ACTION_DREAMING_STARTED' is missing @BroadcastBehavior +BroadcastBehavior: android.content.Intent#ACTION_DREAMING_STOPPED: + Field 'ACTION_DREAMING_STOPPED' is missing @BroadcastBehavior +BroadcastBehavior: android.content.Intent#ACTION_EXTERNAL_APPLICATIONS_AVAILABLE: + Field 'ACTION_EXTERNAL_APPLICATIONS_AVAILABLE' is missing @BroadcastBehavior +BroadcastBehavior: android.content.Intent#ACTION_EXTERNAL_APPLICATIONS_UNAVAILABLE: + Field 'ACTION_EXTERNAL_APPLICATIONS_UNAVAILABLE' is missing @BroadcastBehavior +BroadcastBehavior: android.content.Intent#ACTION_GLOBAL_BUTTON: + Field 'ACTION_GLOBAL_BUTTON' is missing @BroadcastBehavior +BroadcastBehavior: android.content.Intent#ACTION_GTALK_SERVICE_CONNECTED: + Field 'ACTION_GTALK_SERVICE_CONNECTED' is missing @BroadcastBehavior +BroadcastBehavior: android.content.Intent#ACTION_GTALK_SERVICE_DISCONNECTED: + Field 'ACTION_GTALK_SERVICE_DISCONNECTED' is missing @BroadcastBehavior +BroadcastBehavior: android.content.Intent#ACTION_HEADSET_PLUG: + Field 'ACTION_HEADSET_PLUG' is missing @BroadcastBehavior +BroadcastBehavior: android.content.Intent#ACTION_INPUT_METHOD_CHANGED: + Field 'ACTION_INPUT_METHOD_CHANGED' is missing @BroadcastBehavior +BroadcastBehavior: android.content.Intent#ACTION_INSTALL_INSTANT_APP_PACKAGE: + Field 'ACTION_INSTALL_INSTANT_APP_PACKAGE' is missing @BroadcastBehavior +BroadcastBehavior: android.content.Intent#ACTION_INSTANT_APP_RESOLVER_SETTINGS: + Field 'ACTION_INSTANT_APP_RESOLVER_SETTINGS' is missing @BroadcastBehavior +BroadcastBehavior: android.content.Intent#ACTION_INTENT_FILTER_NEEDS_VERIFICATION: + Field 'ACTION_INTENT_FILTER_NEEDS_VERIFICATION' is missing @BroadcastBehavior +BroadcastBehavior: android.content.Intent#ACTION_LOAD_DATA: + Field 'ACTION_LOAD_DATA' is missing @BroadcastBehavior +BroadcastBehavior: android.content.Intent#ACTION_LOCALE_CHANGED: + Field 'ACTION_LOCALE_CHANGED' is missing @BroadcastBehavior +BroadcastBehavior: android.content.Intent#ACTION_LOCKED_BOOT_COMPLETED: + Field 'ACTION_LOCKED_BOOT_COMPLETED' is missing @BroadcastBehavior +BroadcastBehavior: android.content.Intent#ACTION_MANAGE_PACKAGE_STORAGE: + Field 'ACTION_MANAGE_PACKAGE_STORAGE' is missing @BroadcastBehavior +BroadcastBehavior: android.content.Intent#ACTION_MEDIA_BAD_REMOVAL: + Field 'ACTION_MEDIA_BAD_REMOVAL' is missing @BroadcastBehavior +BroadcastBehavior: android.content.Intent#ACTION_MEDIA_BUTTON: + Field 'ACTION_MEDIA_BUTTON' is missing @BroadcastBehavior +BroadcastBehavior: android.content.Intent#ACTION_MEDIA_CHECKING: + Field 'ACTION_MEDIA_CHECKING' is missing @BroadcastBehavior +BroadcastBehavior: android.content.Intent#ACTION_MEDIA_EJECT: + Field 'ACTION_MEDIA_EJECT' is missing @BroadcastBehavior +BroadcastBehavior: android.content.Intent#ACTION_MEDIA_MOUNTED: + Field 'ACTION_MEDIA_MOUNTED' is missing @BroadcastBehavior +BroadcastBehavior: android.content.Intent#ACTION_MEDIA_NOFS: + Field 'ACTION_MEDIA_NOFS' is missing @BroadcastBehavior +BroadcastBehavior: android.content.Intent#ACTION_MEDIA_REMOVED: + Field 'ACTION_MEDIA_REMOVED' is missing @BroadcastBehavior +BroadcastBehavior: android.content.Intent#ACTION_MEDIA_SCANNER_FINISHED: + Field 'ACTION_MEDIA_SCANNER_FINISHED' is missing @BroadcastBehavior +BroadcastBehavior: android.content.Intent#ACTION_MEDIA_SCANNER_SCAN_FILE: + Field 'ACTION_MEDIA_SCANNER_SCAN_FILE' is missing @BroadcastBehavior +BroadcastBehavior: android.content.Intent#ACTION_MEDIA_SCANNER_STARTED: + Field 'ACTION_MEDIA_SCANNER_STARTED' is missing @BroadcastBehavior +BroadcastBehavior: android.content.Intent#ACTION_MEDIA_SHARED: + Field 'ACTION_MEDIA_SHARED' is missing @BroadcastBehavior +BroadcastBehavior: android.content.Intent#ACTION_MEDIA_UNMOUNTABLE: + Field 'ACTION_MEDIA_UNMOUNTABLE' is missing @BroadcastBehavior +BroadcastBehavior: android.content.Intent#ACTION_MEDIA_UNMOUNTED: + Field 'ACTION_MEDIA_UNMOUNTED' is missing @BroadcastBehavior +BroadcastBehavior: android.content.Intent#ACTION_MY_PACKAGE_REPLACED: + Field 'ACTION_MY_PACKAGE_REPLACED' is missing @BroadcastBehavior +BroadcastBehavior: android.content.Intent#ACTION_MY_PACKAGE_SUSPENDED: + Field 'ACTION_MY_PACKAGE_SUSPENDED' is missing @BroadcastBehavior +BroadcastBehavior: android.content.Intent#ACTION_MY_PACKAGE_UNSUSPENDED: + Field 'ACTION_MY_PACKAGE_UNSUSPENDED' is missing @BroadcastBehavior +BroadcastBehavior: android.content.Intent#ACTION_NEW_OUTGOING_CALL: + Field 'ACTION_NEW_OUTGOING_CALL' is missing @BroadcastBehavior +BroadcastBehavior: android.content.Intent#ACTION_PACKAGES_SUSPENDED: + Field 'ACTION_PACKAGES_SUSPENDED' is missing @BroadcastBehavior +BroadcastBehavior: android.content.Intent#ACTION_PACKAGES_UNSUSPENDED: + Field 'ACTION_PACKAGES_UNSUSPENDED' is missing @BroadcastBehavior +BroadcastBehavior: android.content.Intent#ACTION_PACKAGE_ADDED: + Field 'ACTION_PACKAGE_ADDED' is missing @BroadcastBehavior +BroadcastBehavior: android.content.Intent#ACTION_PACKAGE_CHANGED: + Field 'ACTION_PACKAGE_CHANGED' is missing @BroadcastBehavior +BroadcastBehavior: android.content.Intent#ACTION_PACKAGE_DATA_CLEARED: + Field 'ACTION_PACKAGE_DATA_CLEARED' is missing @BroadcastBehavior +BroadcastBehavior: android.content.Intent#ACTION_PACKAGE_FIRST_LAUNCH: + Field 'ACTION_PACKAGE_FIRST_LAUNCH' is missing @BroadcastBehavior +BroadcastBehavior: android.content.Intent#ACTION_PACKAGE_FULLY_REMOVED: + Field 'ACTION_PACKAGE_FULLY_REMOVED' is missing @BroadcastBehavior +BroadcastBehavior: android.content.Intent#ACTION_PACKAGE_INSTALL: + Field 'ACTION_PACKAGE_INSTALL' is missing @BroadcastBehavior +BroadcastBehavior: android.content.Intent#ACTION_PACKAGE_NEEDS_INTEGRITY_VERIFICATION: + Field 'ACTION_PACKAGE_NEEDS_INTEGRITY_VERIFICATION' is missing @BroadcastBehavior +BroadcastBehavior: android.content.Intent#ACTION_PACKAGE_NEEDS_VERIFICATION: + Field 'ACTION_PACKAGE_NEEDS_VERIFICATION' is missing @BroadcastBehavior +BroadcastBehavior: android.content.Intent#ACTION_PACKAGE_REMOVED: + Field 'ACTION_PACKAGE_REMOVED' is missing @BroadcastBehavior +BroadcastBehavior: android.content.Intent#ACTION_PACKAGE_REPLACED: + Field 'ACTION_PACKAGE_REPLACED' is missing @BroadcastBehavior +BroadcastBehavior: android.content.Intent#ACTION_PACKAGE_RESTARTED: + Field 'ACTION_PACKAGE_RESTARTED' is missing @BroadcastBehavior +BroadcastBehavior: android.content.Intent#ACTION_PACKAGE_UNSTOPPED: + Field 'ACTION_PACKAGE_UNSTOPPED' is missing @BroadcastBehavior +BroadcastBehavior: android.content.Intent#ACTION_PACKAGE_UNSUSPENDED_MANUALLY: + Field 'ACTION_PACKAGE_UNSUSPENDED_MANUALLY' is missing @BroadcastBehavior +BroadcastBehavior: android.content.Intent#ACTION_PACKAGE_VERIFIED: + Field 'ACTION_PACKAGE_VERIFIED' is missing @BroadcastBehavior +BroadcastBehavior: android.content.Intent#ACTION_POWER_CONNECTED: + Field 'ACTION_POWER_CONNECTED' is missing @BroadcastBehavior +BroadcastBehavior: android.content.Intent#ACTION_POWER_DISCONNECTED: + Field 'ACTION_POWER_DISCONNECTED' is missing @BroadcastBehavior +BroadcastBehavior: android.content.Intent#ACTION_PRE_BOOT_COMPLETED: + Field 'ACTION_PRE_BOOT_COMPLETED' is missing @BroadcastBehavior +BroadcastBehavior: android.content.Intent#ACTION_PROVIDER_CHANGED: + Field 'ACTION_PROVIDER_CHANGED' is missing @BroadcastBehavior +BroadcastBehavior: android.content.Intent#ACTION_QUERY_PACKAGE_RESTART: + Field 'ACTION_QUERY_PACKAGE_RESTART' is missing @BroadcastBehavior +BroadcastBehavior: android.content.Intent#ACTION_REBOOT: + Field 'ACTION_REBOOT' is missing @BroadcastBehavior +BroadcastBehavior: android.content.Intent#ACTION_RESOLVE_INSTANT_APP_PACKAGE: + Field 'ACTION_RESOLVE_INSTANT_APP_PACKAGE' is missing @BroadcastBehavior +BroadcastBehavior: android.content.Intent#ACTION_ROLLBACK_COMMITTED: + Field 'ACTION_ROLLBACK_COMMITTED' is missing @BroadcastBehavior +BroadcastBehavior: android.content.Intent#ACTION_SCREEN_OFF: + Field 'ACTION_SCREEN_OFF' is missing @BroadcastBehavior +BroadcastBehavior: android.content.Intent#ACTION_SCREEN_ON: + Field 'ACTION_SCREEN_ON' is missing @BroadcastBehavior +BroadcastBehavior: android.content.Intent#ACTION_SHOW_SUSPENDED_APP_DETAILS: + Field 'ACTION_SHOW_SUSPENDED_APP_DETAILS' is missing @BroadcastBehavior +BroadcastBehavior: android.content.Intent#ACTION_SHUTDOWN: + Field 'ACTION_SHUTDOWN' is missing @BroadcastBehavior +BroadcastBehavior: android.content.Intent#ACTION_SIM_STATE_CHANGED: + Field 'ACTION_SIM_STATE_CHANGED' is missing @BroadcastBehavior +BroadcastBehavior: android.content.Intent#ACTION_SPLIT_CONFIGURATION_CHANGED: + Field 'ACTION_SPLIT_CONFIGURATION_CHANGED' is missing @BroadcastBehavior +BroadcastBehavior: android.content.Intent#ACTION_TIMEZONE_CHANGED: + Field 'ACTION_TIMEZONE_CHANGED' is missing @BroadcastBehavior +BroadcastBehavior: android.content.Intent#ACTION_TIME_CHANGED: + Field 'ACTION_TIME_CHANGED' is missing @BroadcastBehavior +BroadcastBehavior: android.content.Intent#ACTION_TIME_TICK: + Field 'ACTION_TIME_TICK' is missing @BroadcastBehavior +BroadcastBehavior: android.content.Intent#ACTION_UID_REMOVED: + Field 'ACTION_UID_REMOVED' is missing @BroadcastBehavior +BroadcastBehavior: android.content.Intent#ACTION_UMS_CONNECTED: + Field 'ACTION_UMS_CONNECTED' is missing @BroadcastBehavior +BroadcastBehavior: android.content.Intent#ACTION_UMS_DISCONNECTED: + Field 'ACTION_UMS_DISCONNECTED' is missing @BroadcastBehavior +BroadcastBehavior: android.content.Intent#ACTION_UNARCHIVE_PACKAGE: + Field 'ACTION_UNARCHIVE_PACKAGE' is missing @BroadcastBehavior +BroadcastBehavior: android.content.Intent#ACTION_USER_PRESENT: + Field 'ACTION_USER_PRESENT' is missing @BroadcastBehavior +BroadcastBehavior: android.content.Intent#ACTION_USER_UNLOCKED: + Field 'ACTION_USER_UNLOCKED' is missing @BroadcastBehavior +BroadcastBehavior: android.content.Intent#ACTION_WALLPAPER_CHANGED: + Field 'ACTION_WALLPAPER_CHANGED' is missing @BroadcastBehavior +BroadcastBehavior: android.content.pm.PackageInstaller#ACTION_SESSION_COMMITTED: + Field 'ACTION_SESSION_COMMITTED' is missing @BroadcastBehavior +BroadcastBehavior: android.content.pm.PackageInstaller#ACTION_SESSION_UPDATED: + Field 'ACTION_SESSION_UPDATED' is missing @BroadcastBehavior +BroadcastBehavior: android.hardware.Camera#ACTION_NEW_PICTURE: + Field 'ACTION_NEW_PICTURE' is missing @BroadcastBehavior +BroadcastBehavior: android.hardware.Camera#ACTION_NEW_VIDEO: + Field 'ACTION_NEW_VIDEO' is missing @BroadcastBehavior +BroadcastBehavior: android.hardware.hdmi.HdmiControlManager#ACTION_OSD_MESSAGE: + Field 'ACTION_OSD_MESSAGE' is missing @BroadcastBehavior +BroadcastBehavior: android.hardware.input.InputManager#ACTION_QUERY_KEYBOARD_LAYOUTS: + Field 'ACTION_QUERY_KEYBOARD_LAYOUTS' is missing @BroadcastBehavior +BroadcastBehavior: android.hardware.usb.UsbManager#ACTION_USB_ACCESSORY_DETACHED: + Field 'ACTION_USB_ACCESSORY_DETACHED' is missing @BroadcastBehavior +BroadcastBehavior: android.hardware.usb.UsbManager#ACTION_USB_ACCESSORY_HANDSHAKE: + Field 'ACTION_USB_ACCESSORY_HANDSHAKE' is missing @BroadcastBehavior +BroadcastBehavior: android.hardware.usb.UsbManager#ACTION_USB_DEVICE_DETACHED: + Field 'ACTION_USB_DEVICE_DETACHED' is missing @BroadcastBehavior +BroadcastBehavior: android.hardware.usb.UsbManager#ACTION_USB_PORT_CHANGED: + Field 'ACTION_USB_PORT_CHANGED' is missing @BroadcastBehavior +BroadcastBehavior: android.hardware.usb.UsbManager#ACTION_USB_PORT_COMPLIANCE_CHANGED: + Field 'ACTION_USB_PORT_COMPLIANCE_CHANGED' is missing @BroadcastBehavior +BroadcastBehavior: android.hardware.usb.UsbManager#ACTION_USB_STATE: + Field 'ACTION_USB_STATE' is missing @BroadcastBehavior +BroadcastBehavior: android.media.AudioManager#ACTION_HDMI_AUDIO_PLUG: + Field 'ACTION_HDMI_AUDIO_PLUG' is missing @BroadcastBehavior +BroadcastBehavior: android.media.AudioManager#ACTION_HEADSET_PLUG: + Field 'ACTION_HEADSET_PLUG' is missing @BroadcastBehavior +BroadcastBehavior: android.media.AudioManager#ACTION_MICROPHONE_MUTE_CHANGED: + Field 'ACTION_MICROPHONE_MUTE_CHANGED' is missing @BroadcastBehavior +BroadcastBehavior: android.media.AudioManager#ACTION_SPEAKERPHONE_STATE_CHANGED: + Field 'ACTION_SPEAKERPHONE_STATE_CHANGED' is missing @BroadcastBehavior +BroadcastBehavior: android.media.tv.TvContract#ACTION_CHANNEL_BROWSABLE_REQUESTED: + Field 'ACTION_CHANNEL_BROWSABLE_REQUESTED' is missing @BroadcastBehavior +BroadcastBehavior: android.media.tv.TvContract#ACTION_INITIALIZE_PROGRAMS: + Field 'ACTION_INITIALIZE_PROGRAMS' is missing @BroadcastBehavior +BroadcastBehavior: android.media.tv.TvContract#ACTION_PREVIEW_PROGRAM_ADDED_TO_WATCH_NEXT: + Field 'ACTION_PREVIEW_PROGRAM_ADDED_TO_WATCH_NEXT' is missing @BroadcastBehavior +BroadcastBehavior: android.media.tv.TvContract#ACTION_PREVIEW_PROGRAM_BROWSABLE_DISABLED: + Field 'ACTION_PREVIEW_PROGRAM_BROWSABLE_DISABLED' is missing @BroadcastBehavior +BroadcastBehavior: android.media.tv.TvContract#ACTION_WATCH_NEXT_PROGRAM_BROWSABLE_DISABLED: + Field 'ACTION_WATCH_NEXT_PROGRAM_BROWSABLE_DISABLED' is missing @BroadcastBehavior +BroadcastBehavior: android.net.NetworkScoreManager#ACTION_SCORER_CHANGED: + Field 'ACTION_SCORER_CHANGED' is missing @BroadcastBehavior +BroadcastBehavior: android.net.NetworkScoreManager#ACTION_SCORE_NETWORKS: + Field 'ACTION_SCORE_NETWORKS' is missing @BroadcastBehavior +BroadcastBehavior: android.net.Proxy#PROXY_CHANGE_ACTION: + Field 'PROXY_CHANGE_ACTION' is missing @BroadcastBehavior +BroadcastBehavior: android.nfc.NfcAdapter#ACTION_ADAPTER_STATE_CHANGED: + Field 'ACTION_ADAPTER_STATE_CHANGED' is missing @BroadcastBehavior +BroadcastBehavior: android.nfc.NfcAdapter#ACTION_PREFERRED_PAYMENT_CHANGED: + Field 'ACTION_PREFERRED_PAYMENT_CHANGED' is missing @BroadcastBehavior +BroadcastBehavior: android.nfc.NfcAdapter#ACTION_REQUIRE_UNLOCK_FOR_NFC: + Field 'ACTION_REQUIRE_UNLOCK_FOR_NFC' is missing @BroadcastBehavior +BroadcastBehavior: android.nfc.NfcAdapter#ACTION_TRANSACTION_DETECTED: + Field 'ACTION_TRANSACTION_DETECTED' is missing @BroadcastBehavior +BroadcastBehavior: android.os.DropBoxManager#ACTION_DROPBOX_ENTRY_ADDED: + Field 'ACTION_DROPBOX_ENTRY_ADDED' is missing @BroadcastBehavior +BroadcastBehavior: android.provider.CalendarContract#ACTION_EVENT_REMINDER: + Field 'ACTION_EVENT_REMINDER' is missing @BroadcastBehavior +BroadcastBehavior: android.provider.ContactsContract.SimContacts#ACTION_SIM_ACCOUNTS_CHANGED: + Field 'ACTION_SIM_ACCOUNTS_CHANGED' is missing @BroadcastBehavior +BroadcastBehavior: android.provider.Telephony.Sms.Intents#ACTION_SMS_EMERGENCY_CB_RECEIVED: + Field 'ACTION_SMS_EMERGENCY_CB_RECEIVED' is missing @BroadcastBehavior +BroadcastBehavior: android.provider.Telephony.Sms.Intents#DATA_SMS_RECEIVED_ACTION: + Field 'DATA_SMS_RECEIVED_ACTION' is missing @BroadcastBehavior +BroadcastBehavior: android.provider.Telephony.Sms.Intents#SECRET_CODE_ACTION: + Field 'SECRET_CODE_ACTION' is missing @BroadcastBehavior +BroadcastBehavior: android.provider.Telephony.Sms.Intents#SIM_FULL_ACTION: + Field 'SIM_FULL_ACTION' is missing @BroadcastBehavior +BroadcastBehavior: android.provider.Telephony.Sms.Intents#SMS_CB_RECEIVED_ACTION: + Field 'SMS_CB_RECEIVED_ACTION' is missing @BroadcastBehavior +BroadcastBehavior: android.provider.Telephony.Sms.Intents#SMS_DELIVER_ACTION: + Field 'SMS_DELIVER_ACTION' is missing @BroadcastBehavior +BroadcastBehavior: android.provider.Telephony.Sms.Intents#SMS_RECEIVED_ACTION: + Field 'SMS_RECEIVED_ACTION' is missing @BroadcastBehavior +BroadcastBehavior: android.provider.Telephony.Sms.Intents#SMS_REJECTED_ACTION: + Field 'SMS_REJECTED_ACTION' is missing @BroadcastBehavior +BroadcastBehavior: android.provider.Telephony.Sms.Intents#SMS_SERVICE_CATEGORY_PROGRAM_DATA_RECEIVED_ACTION: + Field 'SMS_SERVICE_CATEGORY_PROGRAM_DATA_RECEIVED_ACTION' is missing @BroadcastBehavior +BroadcastBehavior: android.provider.Telephony.Sms.Intents#WAP_PUSH_DELIVER_ACTION: + Field 'WAP_PUSH_DELIVER_ACTION' is missing @BroadcastBehavior +BroadcastBehavior: android.provider.Telephony.Sms.Intents#WAP_PUSH_RECEIVED_ACTION: + Field 'WAP_PUSH_RECEIVED_ACTION' is missing @BroadcastBehavior +BroadcastBehavior: android.security.KeyChain#ACTION_KEYCHAIN_CHANGED: + Field 'ACTION_KEYCHAIN_CHANGED' is missing @BroadcastBehavior +BroadcastBehavior: android.security.KeyChain#ACTION_KEY_ACCESS_CHANGED: + Field 'ACTION_KEY_ACCESS_CHANGED' is missing @BroadcastBehavior +BroadcastBehavior: android.security.KeyChain#ACTION_STORAGE_CHANGED: + Field 'ACTION_STORAGE_CHANGED' is missing @BroadcastBehavior +BroadcastBehavior: android.security.KeyChain#ACTION_TRUST_STORE_CHANGED: + Field 'ACTION_TRUST_STORE_CHANGED' is missing @BroadcastBehavior +BroadcastBehavior: android.service.euicc.EuiccService#ACTION_DELETE_SUBSCRIPTION_PRIVILEGED: + Field 'ACTION_DELETE_SUBSCRIPTION_PRIVILEGED' is missing @BroadcastBehavior +BroadcastBehavior: android.service.euicc.EuiccService#ACTION_RENAME_SUBSCRIPTION_PRIVILEGED: + Field 'ACTION_RENAME_SUBSCRIPTION_PRIVILEGED' is missing @BroadcastBehavior +BroadcastBehavior: android.service.euicc.EuiccService#ACTION_START_EUICC_ACTIVATION: + Field 'ACTION_START_EUICC_ACTIVATION' is missing @BroadcastBehavior +BroadcastBehavior: android.service.euicc.EuiccService#ACTION_TOGGLE_SUBSCRIPTION_PRIVILEGED: + Field 'ACTION_TOGGLE_SUBSCRIPTION_PRIVILEGED' is missing @BroadcastBehavior +BroadcastBehavior: android.speech.tts.TextToSpeech#ACTION_TTS_QUEUE_PROCESSING_COMPLETED: + Field 'ACTION_TTS_QUEUE_PROCESSING_COMPLETED' is missing @BroadcastBehavior +BroadcastBehavior: android.speech.tts.TextToSpeech.Engine#ACTION_TTS_DATA_INSTALLED: + Field 'ACTION_TTS_DATA_INSTALLED' is missing @BroadcastBehavior +BroadcastBehavior: android.telephony.SubscriptionManager#ACTION_DEFAULT_SMS_SUBSCRIPTION_CHANGED: + Field 'ACTION_DEFAULT_SMS_SUBSCRIPTION_CHANGED' is missing @BroadcastBehavior +BroadcastBehavior: android.telephony.SubscriptionManager#ACTION_DEFAULT_SUBSCRIPTION_CHANGED: + Field 'ACTION_DEFAULT_SUBSCRIPTION_CHANGED' is missing @BroadcastBehavior +BroadcastBehavior: android.telephony.SubscriptionManager#ACTION_REFRESH_SUBSCRIPTION_PLANS: + Field 'ACTION_REFRESH_SUBSCRIPTION_PLANS' is missing @BroadcastBehavior +BroadcastBehavior: android.telephony.SubscriptionManager#ACTION_SUBSCRIPTION_PLANS_CHANGED: + Field 'ACTION_SUBSCRIPTION_PLANS_CHANGED' is missing @BroadcastBehavior +BroadcastBehavior: android.telephony.TelephonyManager#ACTION_CARRIER_SIGNAL_DEFAULT_NETWORK_AVAILABLE: + Field 'ACTION_CARRIER_SIGNAL_DEFAULT_NETWORK_AVAILABLE' is missing @BroadcastBehavior +BroadcastBehavior: android.telephony.TelephonyManager#ACTION_CARRIER_SIGNAL_PCO_VALUE: + Field 'ACTION_CARRIER_SIGNAL_PCO_VALUE' is missing @BroadcastBehavior +BroadcastBehavior: android.telephony.TelephonyManager#ACTION_CARRIER_SIGNAL_REDIRECTED: + Field 'ACTION_CARRIER_SIGNAL_REDIRECTED' is missing @BroadcastBehavior +BroadcastBehavior: android.telephony.TelephonyManager#ACTION_CARRIER_SIGNAL_REQUEST_NETWORK_FAILED: + Field 'ACTION_CARRIER_SIGNAL_REQUEST_NETWORK_FAILED' is missing @BroadcastBehavior +BroadcastBehavior: android.telephony.TelephonyManager#ACTION_CARRIER_SIGNAL_RESET: + Field 'ACTION_CARRIER_SIGNAL_RESET' is missing @BroadcastBehavior +BroadcastBehavior: android.telephony.TelephonyManager#ACTION_DEFAULT_DATA_SUBSCRIPTION_CHANGED: + Field 'ACTION_DEFAULT_DATA_SUBSCRIPTION_CHANGED' is missing @BroadcastBehavior +BroadcastBehavior: android.telephony.TelephonyManager#ACTION_DEFAULT_VOICE_SUBSCRIPTION_CHANGED: + Field 'ACTION_DEFAULT_VOICE_SUBSCRIPTION_CHANGED' is missing @BroadcastBehavior +BroadcastBehavior: android.telephony.TelephonyManager#ACTION_EMERGENCY_CALLBACK_MODE_CHANGED: + Field 'ACTION_EMERGENCY_CALLBACK_MODE_CHANGED' is missing @BroadcastBehavior +BroadcastBehavior: android.telephony.TelephonyManager#ACTION_EMERGENCY_CALL_STATE_CHANGED: + Field 'ACTION_EMERGENCY_CALL_STATE_CHANGED' is missing @BroadcastBehavior +BroadcastBehavior: android.telephony.TelephonyManager#ACTION_REQUEST_OMADM_CONFIGURATION_UPDATE: + Field 'ACTION_REQUEST_OMADM_CONFIGURATION_UPDATE' is missing @BroadcastBehavior +BroadcastBehavior: android.telephony.TelephonyManager#ACTION_SECRET_CODE: + Field 'ACTION_SECRET_CODE' is missing @BroadcastBehavior +BroadcastBehavior: android.telephony.TelephonyManager#ACTION_SHOW_NOTICE_ECM_BLOCK_OTHERS: + Field 'ACTION_SHOW_NOTICE_ECM_BLOCK_OTHERS' is missing @BroadcastBehavior +BroadcastBehavior: android.telephony.TelephonyManager#ACTION_SIM_APPLICATION_STATE_CHANGED: + Field 'ACTION_SIM_APPLICATION_STATE_CHANGED' is missing @BroadcastBehavior +BroadcastBehavior: android.telephony.TelephonyManager#ACTION_SIM_CARD_STATE_CHANGED: + Field 'ACTION_SIM_CARD_STATE_CHANGED' is missing @BroadcastBehavior +BroadcastBehavior: android.telephony.TelephonyManager#ACTION_SIM_SLOT_STATUS_CHANGED: + Field 'ACTION_SIM_SLOT_STATUS_CHANGED' is missing @BroadcastBehavior +BroadcastBehavior: android.telephony.TelephonyManager#ACTION_SUBSCRIPTION_CARRIER_IDENTITY_CHANGED: + Field 'ACTION_SUBSCRIPTION_CARRIER_IDENTITY_CHANGED' is missing @BroadcastBehavior +BroadcastBehavior: android.telephony.TelephonyManager#ACTION_SUBSCRIPTION_SPECIFIC_CARRIER_IDENTITY_CHANGED: + Field 'ACTION_SUBSCRIPTION_SPECIFIC_CARRIER_IDENTITY_CHANGED' is missing @BroadcastBehavior +BroadcastBehavior: android.telephony.euicc.EuiccManager#ACTION_NOTIFY_CARRIER_SETUP_INCOMPLETE: + Field 'ACTION_NOTIFY_CARRIER_SETUP_INCOMPLETE' is missing @BroadcastBehavior +BroadcastBehavior: android.telephony.euicc.EuiccManager#ACTION_OTA_STATUS_CHANGED: + Field 'ACTION_OTA_STATUS_CHANGED' is missing @BroadcastBehavior + + +DeprecationMismatch: android.accounts.AccountManager#newChooseAccountIntent(android.accounts.Account, java.util.ArrayList<android.accounts.Account>, String[], boolean, String, String, String[], android.os.Bundle): + Method android.accounts.AccountManager.newChooseAccountIntent(android.accounts.Account, java.util.ArrayList<android.accounts.Account>, String[], boolean, String, String, String[], android.os.Bundle): @Deprecated annotation (present) and @deprecated doc tag (not present) do not match +DeprecationMismatch: android.app.Activity#enterPictureInPictureMode(): + Method android.app.Activity.enterPictureInPictureMode(): @Deprecated annotation (present) and @deprecated doc tag (not present) do not match +DeprecationMismatch: android.app.Instrumentation#startAllocCounting(): + Method android.app.Instrumentation.startAllocCounting(): @Deprecated annotation (present) and @deprecated doc tag (not present) do not match +DeprecationMismatch: android.app.Instrumentation#stopAllocCounting(): + Method android.app.Instrumentation.stopAllocCounting(): @Deprecated annotation (present) and @deprecated doc tag (not present) do not match +DeprecationMismatch: android.app.Notification#bigContentView: + Field Notification.bigContentView: @Deprecated annotation (present) and @deprecated doc tag (not present) do not match +DeprecationMismatch: android.app.Notification#contentView: + Field Notification.contentView: @Deprecated annotation (present) and @deprecated doc tag (not present) do not match +DeprecationMismatch: android.app.Notification#headsUpContentView: + Field Notification.headsUpContentView: @Deprecated annotation (present) and @deprecated doc tag (not present) do not match +DeprecationMismatch: android.app.Notification#tickerView: + Field Notification.tickerView: @Deprecated annotation (present) and @deprecated doc tag (not present) do not match +DeprecationMismatch: android.app.Notification.Action.Builder#Builder(int, CharSequence, android.app.PendingIntent): + Constructor android.app.Notification.Action.Builder.Builder(int, CharSequence, android.app.PendingIntent): @Deprecated annotation (present) and @deprecated doc tag (not present) do not match +DeprecationMismatch: android.app.Notification.Action.WearableExtender#getCancelLabel(): + Method android.app.Notification.Action.WearableExtender.getCancelLabel(): @Deprecated annotation (present) and @deprecated doc tag (not present) do not match +DeprecationMismatch: android.app.Notification.Action.WearableExtender#getConfirmLabel(): + Method android.app.Notification.Action.WearableExtender.getConfirmLabel(): @Deprecated annotation (present) and @deprecated doc tag (not present) do not match +DeprecationMismatch: android.app.Notification.Action.WearableExtender#getInProgressLabel(): + Method android.app.Notification.Action.WearableExtender.getInProgressLabel(): @Deprecated annotation (present) and @deprecated doc tag (not present) do not match +DeprecationMismatch: android.app.Notification.Action.WearableExtender#setCancelLabel(CharSequence): + Method android.app.Notification.Action.WearableExtender.setCancelLabel(CharSequence): @Deprecated annotation (present) and @deprecated doc tag (not present) do not match +DeprecationMismatch: android.app.Notification.Action.WearableExtender#setConfirmLabel(CharSequence): + Method android.app.Notification.Action.WearableExtender.setConfirmLabel(CharSequence): @Deprecated annotation (present) and @deprecated doc tag (not present) do not match +DeprecationMismatch: android.app.Notification.Action.WearableExtender#setInProgressLabel(CharSequence): + Method android.app.Notification.Action.WearableExtender.setInProgressLabel(CharSequence): @Deprecated annotation (present) and @deprecated doc tag (not present) do not match +DeprecationMismatch: android.app.Notification.Builder#setContent(android.widget.RemoteViews): + Method android.app.Notification.Builder.setContent(android.widget.RemoteViews): @Deprecated annotation (present) and @deprecated doc tag (not present) do not match +DeprecationMismatch: android.app.Notification.Builder#setTicker(CharSequence, android.widget.RemoteViews): + Method android.app.Notification.Builder.setTicker(CharSequence, android.widget.RemoteViews): @Deprecated annotation (present) and @deprecated doc tag (not present) do not match +DeprecationMismatch: android.app.Notification.WearableExtender#getContentIcon(): + Method android.app.Notification.WearableExtender.getContentIcon(): @Deprecated annotation (present) and @deprecated doc tag (not present) do not match +DeprecationMismatch: android.app.Notification.WearableExtender#getContentIconGravity(): + Method android.app.Notification.WearableExtender.getContentIconGravity(): @Deprecated annotation (present) and @deprecated doc tag (not present) do not match +DeprecationMismatch: android.app.Notification.WearableExtender#getCustomContentHeight(): + Method android.app.Notification.WearableExtender.getCustomContentHeight(): @Deprecated annotation (present) and @deprecated doc tag (not present) do not match +DeprecationMismatch: android.app.Notification.WearableExtender#getCustomSizePreset(): + Method android.app.Notification.WearableExtender.getCustomSizePreset(): @Deprecated annotation (present) and @deprecated doc tag (not present) do not match +DeprecationMismatch: android.app.Notification.WearableExtender#getGravity(): + Method android.app.Notification.WearableExtender.getGravity(): @Deprecated annotation (present) and @deprecated doc tag (not present) do not match +DeprecationMismatch: android.app.Notification.WearableExtender#getHintAvoidBackgroundClipping(): + Method android.app.Notification.WearableExtender.getHintAvoidBackgroundClipping(): @Deprecated annotation (present) and @deprecated doc tag (not present) do not match +DeprecationMismatch: android.app.Notification.WearableExtender#getHintHideIcon(): + Method android.app.Notification.WearableExtender.getHintHideIcon(): @Deprecated annotation (present) and @deprecated doc tag (not present) do not match +DeprecationMismatch: android.app.Notification.WearableExtender#getHintScreenTimeout(): + Method android.app.Notification.WearableExtender.getHintScreenTimeout(): @Deprecated annotation (present) and @deprecated doc tag (not present) do not match +DeprecationMismatch: android.app.Notification.WearableExtender#getHintShowBackgroundOnly(): + Method android.app.Notification.WearableExtender.getHintShowBackgroundOnly(): @Deprecated annotation (present) and @deprecated doc tag (not present) do not match +DeprecationMismatch: android.app.Notification.WearableExtender#setContentIcon(int): + Method android.app.Notification.WearableExtender.setContentIcon(int): @Deprecated annotation (present) and @deprecated doc tag (not present) do not match +DeprecationMismatch: android.app.Notification.WearableExtender#setContentIconGravity(int): + Method android.app.Notification.WearableExtender.setContentIconGravity(int): @Deprecated annotation (present) and @deprecated doc tag (not present) do not match +DeprecationMismatch: android.app.Notification.WearableExtender#setCustomContentHeight(int): + Method android.app.Notification.WearableExtender.setCustomContentHeight(int): @Deprecated annotation (present) and @deprecated doc tag (not present) do not match +DeprecationMismatch: android.app.Notification.WearableExtender#setCustomSizePreset(int): + Method android.app.Notification.WearableExtender.setCustomSizePreset(int): @Deprecated annotation (present) and @deprecated doc tag (not present) do not match +DeprecationMismatch: android.app.Notification.WearableExtender#setGravity(int): + Method android.app.Notification.WearableExtender.setGravity(int): @Deprecated annotation (present) and @deprecated doc tag (not present) do not match +DeprecationMismatch: android.app.Notification.WearableExtender#setHintAvoidBackgroundClipping(boolean): + Method android.app.Notification.WearableExtender.setHintAvoidBackgroundClipping(boolean): @Deprecated annotation (present) and @deprecated doc tag (not present) do not match +DeprecationMismatch: android.app.Notification.WearableExtender#setHintHideIcon(boolean): + Method android.app.Notification.WearableExtender.setHintHideIcon(boolean): @Deprecated annotation (present) and @deprecated doc tag (not present) do not match +DeprecationMismatch: android.app.Notification.WearableExtender#setHintScreenTimeout(int): + Method android.app.Notification.WearableExtender.setHintScreenTimeout(int): @Deprecated annotation (present) and @deprecated doc tag (not present) do not match +DeprecationMismatch: android.app.Notification.WearableExtender#setHintShowBackgroundOnly(boolean): + Method android.app.Notification.WearableExtender.setHintShowBackgroundOnly(boolean): @Deprecated annotation (present) and @deprecated doc tag (not present) do not match +DeprecationMismatch: android.app.backup.BackupManager#selectBackupTransport(String): + Method android.app.backup.BackupManager.selectBackupTransport(String): @Deprecated annotation (present) and @deprecated doc tag (not present) do not match +DeprecationMismatch: android.content.Context#BIND_ALLOW_FOREGROUND_SERVICE_STARTS_FROM_BACKGROUND: + Field Context.BIND_ALLOW_FOREGROUND_SERVICE_STARTS_FROM_BACKGROUND: @Deprecated annotation (present) and @deprecated doc tag (not present) do not match +DeprecationMismatch: android.content.Context#WIFI_RTT_SERVICE: + Field Context.WIFI_RTT_SERVICE: @Deprecated annotation (present) and @deprecated doc tag (not present) do not match +DeprecationMismatch: android.graphics.ComposeShader#ComposeShader(android.graphics.Shader, android.graphics.Shader, android.graphics.Xfermode): + Constructor android.graphics.ComposeShader.ComposeShader(android.graphics.Shader, android.graphics.Shader, android.graphics.Xfermode): @Deprecated annotation (present) and @deprecated doc tag (not present) do not match +DeprecationMismatch: android.graphics.PixelFormat#A_8: + Field PixelFormat.A_8: @Deprecated annotation (present) and @deprecated doc tag (not present) do not match +DeprecationMismatch: android.graphics.PixelFormat#LA_88: + Field PixelFormat.LA_88: @Deprecated annotation (present) and @deprecated doc tag (not present) do not match +DeprecationMismatch: android.graphics.PixelFormat#L_8: + Field PixelFormat.L_8: @Deprecated annotation (present) and @deprecated doc tag (not present) do not match +DeprecationMismatch: android.graphics.PixelFormat#RGBA_4444: + Field PixelFormat.RGBA_4444: @Deprecated annotation (present) and @deprecated doc tag (not present) do not match +DeprecationMismatch: android.graphics.PixelFormat#RGBA_5551: + Field PixelFormat.RGBA_5551: @Deprecated annotation (present) and @deprecated doc tag (not present) do not match +DeprecationMismatch: android.graphics.PixelFormat#RGB_332: + Field PixelFormat.RGB_332: @Deprecated annotation (present) and @deprecated doc tag (not present) do not match +DeprecationMismatch: android.hardware.hdmi.HdmiControlManager#RESULT_ALREADY_IN_PROGRESS: + Field HdmiControlManager.RESULT_ALREADY_IN_PROGRESS: @Deprecated annotation (present) and @deprecated doc tag (not present) do not match +DeprecationMismatch: android.media.tv.tuner.frontend.IsdbtFrontendSettings.Builder#setCodeRate(int): + Method android.media.tv.tuner.frontend.IsdbtFrontendSettings.Builder.setCodeRate(int): @Deprecated annotation (present) and @deprecated doc tag (not present) do not match +DeprecationMismatch: android.media.tv.tuner.frontend.IsdbtFrontendSettings.Builder#setModulation(int): + Method android.media.tv.tuner.frontend.IsdbtFrontendSettings.Builder.setModulation(int): @Deprecated annotation (present) and @deprecated doc tag (not present) do not match +DeprecationMismatch: android.opengl.EGL14#eglCreatePixmapSurface(android.opengl.EGLDisplay, android.opengl.EGLConfig, int, int[], int): + Method android.opengl.EGL14.eglCreatePixmapSurface(android.opengl.EGLDisplay, android.opengl.EGLConfig, int, int[], int): @Deprecated annotation (present) and @deprecated doc tag (not present) do not match +DeprecationMismatch: android.opengl.GLES20#GL_STENCIL_INDEX: + Field GLES20.GL_STENCIL_INDEX: @Deprecated annotation (present) and @deprecated doc tag (not present) do not match +DeprecationMismatch: android.opengl.GLSurfaceView#surfaceRedrawNeeded(android.view.SurfaceHolder): + Method android.opengl.GLSurfaceView.surfaceRedrawNeeded(android.view.SurfaceHolder): @Deprecated annotation (present) and @deprecated doc tag (not present) do not match +DeprecationMismatch: android.os.UserManager#setUserRestrictions(android.os.Bundle): + Method android.os.UserManager.setUserRestrictions(android.os.Bundle): @Deprecated annotation (present) and @deprecated doc tag (not present) do not match +DeprecationMismatch: android.os.UserManager#setUserRestrictions(android.os.Bundle, android.os.UserHandle): + Method android.os.UserManager.setUserRestrictions(android.os.Bundle, android.os.UserHandle): @Deprecated annotation (present) and @deprecated doc tag (not present) do not match +DeprecationMismatch: android.provider.Contacts.People#markAsContacted(android.content.ContentResolver, long): + Method android.provider.Contacts.People.markAsContacted(android.content.ContentResolver, long): @Deprecated annotation (present) and @deprecated doc tag (not present) do not match +DeprecationMismatch: android.renderscript.Type.CubemapFace#POSITVE_X: + Field Type.CubemapFace.POSITVE_X: @Deprecated annotation (present) and @deprecated doc tag (not present) do not match +DeprecationMismatch: android.renderscript.Type.CubemapFace#POSITVE_Y: + Field Type.CubemapFace.POSITVE_Y: @Deprecated annotation (present) and @deprecated doc tag (not present) do not match +DeprecationMismatch: android.renderscript.Type.CubemapFace#POSITVE_Z: + Field Type.CubemapFace.POSITVE_Z: @Deprecated annotation (present) and @deprecated doc tag (not present) do not match +DeprecationMismatch: android.speech.tts.TextToSpeech#areDefaultsEnforced(): + Method android.speech.tts.TextToSpeech.areDefaultsEnforced(): @Deprecated annotation (present) and @deprecated doc tag (not present) do not match +DeprecationMismatch: android.telecom.StatusHints#StatusHints(android.content.ComponentName, CharSequence, int, android.os.Bundle): + Constructor android.telecom.StatusHints.StatusHints(android.content.ComponentName, CharSequence, int, android.os.Bundle): @Deprecated annotation (present) and @deprecated doc tag (not present) do not match +DeprecationMismatch: android.telecom.StatusHints#getIcon(android.content.Context): + Method android.telecom.StatusHints.getIcon(android.content.Context): @Deprecated annotation (present) and @deprecated doc tag (not present) do not match +DeprecationMismatch: android.telecom.StatusHints#getIconResId(): + Method android.telecom.StatusHints.getIconResId(): @Deprecated annotation (present) and @deprecated doc tag (not present) do not match +DeprecationMismatch: android.telecom.StatusHints#getPackageName(): + Method android.telecom.StatusHints.getPackageName(): @Deprecated annotation (present) and @deprecated doc tag (not present) do not match +DeprecationMismatch: android.telephony.PhoneStateListener#PhoneStateListener(java.util.concurrent.Executor): + Constructor android.telephony.PhoneStateListener.PhoneStateListener(java.util.concurrent.Executor): @Deprecated annotation (present) and @deprecated doc tag (not present) do not match +DeprecationMismatch: android.telephony.SubscriptionManager#PROFILE_CLASS_DEFAULT: + Field SubscriptionManager.PROFILE_CLASS_DEFAULT: @Deprecated annotation (present) and @deprecated doc tag (not present) do not match +DeprecationMismatch: android.telephony.SubscriptionPlan.Builder#createRecurringDaily(java.time.ZonedDateTime): + Method android.telephony.SubscriptionPlan.Builder.createRecurringDaily(java.time.ZonedDateTime): @Deprecated annotation (present) and @deprecated doc tag (not present) do not match +DeprecationMismatch: android.telephony.SubscriptionPlan.Builder#createRecurringMonthly(java.time.ZonedDateTime): + Method android.telephony.SubscriptionPlan.Builder.createRecurringMonthly(java.time.ZonedDateTime): @Deprecated annotation (present) and @deprecated doc tag (not present) do not match +DeprecationMismatch: android.telephony.SubscriptionPlan.Builder#createRecurringWeekly(java.time.ZonedDateTime): + Method android.telephony.SubscriptionPlan.Builder.createRecurringWeekly(java.time.ZonedDateTime): @Deprecated annotation (present) and @deprecated doc tag (not present) do not match +DeprecationMismatch: android.text.format.DateUtils#FORMAT_12HOUR: + Field DateUtils.FORMAT_12HOUR: @Deprecated annotation (present) and @deprecated doc tag (not present) do not match +DeprecationMismatch: android.text.format.DateUtils#FORMAT_24HOUR: + Field DateUtils.FORMAT_24HOUR: @Deprecated annotation (present) and @deprecated doc tag (not present) do not match +DeprecationMismatch: android.text.format.DateUtils#FORMAT_CAP_AMPM: + Field DateUtils.FORMAT_CAP_AMPM: @Deprecated annotation (present) and @deprecated doc tag (not present) do not match +DeprecationMismatch: android.text.format.DateUtils#FORMAT_CAP_MIDNIGHT: + Field DateUtils.FORMAT_CAP_MIDNIGHT: @Deprecated annotation (present) and @deprecated doc tag (not present) do not match +DeprecationMismatch: android.text.format.DateUtils#FORMAT_CAP_NOON: + Field DateUtils.FORMAT_CAP_NOON: @Deprecated annotation (present) and @deprecated doc tag (not present) do not match +DeprecationMismatch: android.text.format.DateUtils#FORMAT_CAP_NOON_MIDNIGHT: + Field DateUtils.FORMAT_CAP_NOON_MIDNIGHT: @Deprecated annotation (present) and @deprecated doc tag (not present) do not match +DeprecationMismatch: android.text.format.DateUtils#FORMAT_NO_NOON_MIDNIGHT: + Field DateUtils.FORMAT_NO_NOON_MIDNIGHT: @Deprecated annotation (present) and @deprecated doc tag (not present) do not match +DeprecationMismatch: android.view.ViewGroup.LayoutParams#FILL_PARENT: + Field ViewGroup.LayoutParams.FILL_PARENT: @Deprecated annotation (present) and @deprecated doc tag (not present) do not match +DeprecationMismatch: android.view.Window#setTitleColor(int): + Method android.view.Window.setTitleColor(int): @Deprecated annotation (present) and @deprecated doc tag (not present) do not match +DeprecationMismatch: android.view.accessibility.AccessibilityEvent#MAX_TEXT_LENGTH: + Field AccessibilityEvent.MAX_TEXT_LENGTH: @Deprecated annotation (present) and @deprecated doc tag (not present) do not match +DeprecationMismatch: android.webkit.WebSettings#getSaveFormData(): + Method android.webkit.WebSettings.getSaveFormData(): @Deprecated annotation (present) and @deprecated doc tag (not present) do not match +DeprecationMismatch: android.webkit.WebView#shouldDelayChildPressedState(): + Method android.webkit.WebView.shouldDelayChildPressedState(): @Deprecated annotation (present) and @deprecated doc tag (not present) do not match +DeprecationMismatch: android.webkit.WebViewDatabase#clearFormData(): + Method android.webkit.WebViewDatabase.clearFormData(): @Deprecated annotation (present) and @deprecated doc tag (not present) do not match +DeprecationMismatch: android.webkit.WebViewDatabase#hasFormData(): + Method android.webkit.WebViewDatabase.hasFormData(): @Deprecated annotation (present) and @deprecated doc tag (not present) do not match +DeprecationMismatch: javax.microedition.khronos.egl.EGL10#eglCreatePixmapSurface(javax.microedition.khronos.egl.EGLDisplay, javax.microedition.khronos.egl.EGLConfig, Object, int[]): + Method javax.microedition.khronos.egl.EGL10.eglCreatePixmapSurface(javax.microedition.khronos.egl.EGLDisplay, javax.microedition.khronos.egl.EGLConfig, Object, int[]): @Deprecated annotation (present) and @deprecated doc tag (not present) do not match + + +RequiresPermission: android.accounts.AccountManager#getAccountsByTypeAndFeatures(String, String[], android.accounts.AccountManagerCallback<android.accounts.Account[]>, android.os.Handler): + Method 'getAccountsByTypeAndFeatures' documentation mentions permissions without declaring @RequiresPermission +RequiresPermission: android.accounts.AccountManager#hasFeatures(android.accounts.Account, String[], android.accounts.AccountManagerCallback<java.lang.Boolean>, android.os.Handler): + Method 'hasFeatures' documentation mentions permissions without declaring @RequiresPermission +RequiresPermission: android.app.ActivityManager#addOnUidImportanceListener(android.app.ActivityManager.OnUidImportanceListener, int): + Method 'addOnUidImportanceListener' documentation mentions permissions already declared by @RequiresPermission +RequiresPermission: android.app.ActivityManager#getHistoricalProcessExitReasons(String, int, int): + Method 'getHistoricalProcessExitReasons' documentation mentions permissions without declaring @RequiresPermission +RequiresPermission: android.app.ActivityManager#getProcessesInErrorState(): + Method 'getProcessesInErrorState' documentation mentions permissions without declaring @RequiresPermission +RequiresPermission: android.app.ActivityManager#killProcessesWhenImperceptible(int[], String): + Method 'killProcessesWhenImperceptible' documentation mentions permissions already declared by @RequiresPermission +RequiresPermission: android.app.ActivityManager#setDeviceLocales(android.os.LocaleList): + Method 'setDeviceLocales' documentation mentions permissions without declaring @RequiresPermission +RequiresPermission: android.app.AlarmManager#setAlarmClock(android.app.AlarmManager.AlarmClockInfo, android.app.PendingIntent): + Method 'setAlarmClock' documentation mentions permissions already declared by @RequiresPermission +RequiresPermission: android.app.AlarmManager#setExact(int, long, android.app.PendingIntent): + Method 'setExact' documentation mentions permissions already declared by @RequiresPermission +RequiresPermission: android.app.AlarmManager#setExactAndAllowWhileIdle(int, long, android.app.PendingIntent): + Method 'setExactAndAllowWhileIdle' documentation mentions permissions already declared by @RequiresPermission +RequiresPermission: android.app.AlarmManager#setTime(long): + Method 'setTime' documentation mentions permissions already declared by @RequiresPermission +RequiresPermission: android.app.AppOpsManager#isOpActive(String, int, String): + Method 'isOpActive' documentation mentions permissions without declaring @RequiresPermission +RequiresPermission: android.app.AppOpsManager#startWatchingActive(String[], java.util.concurrent.Executor, android.app.AppOpsManager.OnOpActiveChangedListener): + Method 'startWatchingActive' documentation mentions permissions without declaring @RequiresPermission +RequiresPermission: android.app.AppOpsManager#startWatchingNoted(String[], java.util.concurrent.Executor, android.app.AppOpsManager.OnOpNotedListener): + Method 'startWatchingNoted' documentation mentions permissions already declared by @RequiresPermission +RequiresPermission: android.app.DownloadManager.Request#setDestinationInExternalPublicDir(String, String): + Method 'setDestinationInExternalPublicDir' documentation mentions permissions without declaring @RequiresPermission +RequiresPermission: android.app.DownloadManager.Request#setDestinationUri(android.net.Uri): + Method 'setDestinationUri' documentation mentions permissions without declaring @RequiresPermission +RequiresPermission: android.app.DownloadManager.Request#setNotificationVisibility(int): + Method 'setNotificationVisibility' documentation mentions permissions without declaring @RequiresPermission +RequiresPermission: android.app.DownloadManager.Request#setShowRunningNotification(boolean): + Method 'setShowRunningNotification' documentation mentions permissions without declaring @RequiresPermission +RequiresPermission: android.app.GameManager#setGameMode(String, int): + Method 'setGameMode' documentation mentions permissions already declared by @RequiresPermission +RequiresPermission: android.app.GameManager#updateCustomGameModeConfiguration(String, android.app.GameModeConfiguration): + Method 'updateCustomGameModeConfiguration' documentation mentions permissions already declared by @RequiresPermission +RequiresPermission: android.app.LocaleManager#getApplicationLocales(String): + Method 'getApplicationLocales' documentation mentions permissions already declared by @RequiresPermission +RequiresPermission: android.app.Notification.Builder#setFullScreenIntent(android.app.PendingIntent, boolean): + Method 'setFullScreenIntent' documentation mentions permissions without declaring @RequiresPermission +RequiresPermission: android.app.NotificationManager#canUseFullScreenIntent(): + Method 'canUseFullScreenIntent' documentation mentions permissions without declaring @RequiresPermission +RequiresPermission: android.app.Service#startForeground(int, android.app.Notification): + Method 'startForeground' documentation mentions permissions without declaring @RequiresPermission +RequiresPermission: android.app.StatusBarManager#canLaunchCaptureContentActivityForNote(android.app.Activity): + Method 'canLaunchCaptureContentActivityForNote' documentation mentions permissions already declared by @RequiresPermission +RequiresPermission: android.app.UiModeManager#releaseProjection(int): + Method 'releaseProjection' documentation mentions permissions already declared by @RequiresPermission +RequiresPermission: android.app.UiModeManager#requestProjection(int): + Method 'requestProjection' documentation mentions permissions already declared by @RequiresPermission +RequiresPermission: android.app.WallpaperInfo#getSettingsSliceUri(): + Method 'getSettingsSliceUri' documentation mentions permissions without declaring @RequiresPermission +RequiresPermission: android.app.WallpaperManager#clear(): + Method 'clear' documentation mentions permissions already declared by @RequiresPermission +RequiresPermission: android.app.WallpaperManager#clearWallpaper(int, int): + Method 'clearWallpaper' documentation mentions permissions already declared by @RequiresPermission +RequiresPermission: android.app.WallpaperManager#getDrawable(): + Method 'getDrawable' documentation mentions permissions already declared by @RequiresPermission +RequiresPermission: android.app.WallpaperManager#getDrawable(int): + Method 'getDrawable' documentation mentions permissions already declared by @RequiresPermission +RequiresPermission: android.app.WallpaperManager#getFastDrawable(): + Method 'getFastDrawable' documentation mentions permissions already declared by @RequiresPermission +RequiresPermission: android.app.WallpaperManager#getFastDrawable(int): + Method 'getFastDrawable' documentation mentions permissions already declared by @RequiresPermission +RequiresPermission: android.app.WallpaperManager#getWallpaperFile(int): + Method 'getWallpaperFile' documentation mentions permissions already declared by @RequiresPermission +RequiresPermission: android.app.WallpaperManager#getWallpaperInfo(int): + Method 'getWallpaperInfo' documentation mentions permissions without declaring @RequiresPermission +RequiresPermission: android.app.WallpaperManager#peekDrawable(): + Method 'peekDrawable' documentation mentions permissions already declared by @RequiresPermission +RequiresPermission: android.app.WallpaperManager#peekDrawable(int): + Method 'peekDrawable' documentation mentions permissions already declared by @RequiresPermission +RequiresPermission: android.app.WallpaperManager#peekFastDrawable(): + Method 'peekFastDrawable' documentation mentions permissions already declared by @RequiresPermission +RequiresPermission: android.app.WallpaperManager#peekFastDrawable(int): + Method 'peekFastDrawable' documentation mentions permissions already declared by @RequiresPermission +RequiresPermission: android.app.WallpaperManager#setBitmap(android.graphics.Bitmap): + Method 'setBitmap' documentation mentions permissions already declared by @RequiresPermission +RequiresPermission: android.app.WallpaperManager#setBitmap(android.graphics.Bitmap, android.graphics.Rect, boolean): + Method 'setBitmap' documentation mentions permissions already declared by @RequiresPermission +RequiresPermission: android.app.WallpaperManager#setDisplayPadding(android.graphics.Rect): + Method 'setDisplayPadding' documentation mentions permissions already declared by @RequiresPermission +RequiresPermission: android.app.WallpaperManager#setResource(int): + Method 'setResource' documentation mentions permissions already declared by @RequiresPermission +RequiresPermission: android.app.WallpaperManager#setStream(java.io.InputStream): + Method 'setStream' documentation mentions permissions already declared by @RequiresPermission +RequiresPermission: android.app.WallpaperManager#setStream(java.io.InputStream, android.graphics.Rect, boolean): + Method 'setStream' documentation mentions permissions already declared by @RequiresPermission +RequiresPermission: android.app.WallpaperManager#setWallpaperComponentWithFlags(android.content.ComponentName, int): + Method 'setWallpaperComponentWithFlags' documentation mentions permissions already declared by @RequiresPermission +RequiresPermission: android.app.WallpaperManager#suggestDesiredDimensions(int, int): + Method 'suggestDesiredDimensions' documentation mentions permissions without declaring @RequiresPermission +RequiresPermission: android.app.admin.DevicePolicyManager#addCrossProfileWidgetProvider(android.content.ComponentName, String): + Method 'addCrossProfileWidgetProvider' documentation mentions permissions already declared by @RequiresPermission +RequiresPermission: android.app.admin.DevicePolicyManager#addPersistentPreferredActivity(android.content.ComponentName, android.content.IntentFilter, android.content.ComponentName): + Method 'addPersistentPreferredActivity' documentation mentions permissions already declared by @RequiresPermission +RequiresPermission: android.app.admin.DevicePolicyManager#bindDeviceAdminServiceAsUser(android.content.ComponentName, android.content.Intent, android.content.ServiceConnection, int, android.os.UserHandle): + Method 'bindDeviceAdminServiceAsUser' documentation mentions permissions without declaring @RequiresPermission +RequiresPermission: android.app.admin.DevicePolicyManager#clearPackagePersistentPreferredActivities(android.content.ComponentName, String): + Method 'clearPackagePersistentPreferredActivities' documentation mentions permissions already declared by @RequiresPermission +RequiresPermission: android.app.admin.DevicePolicyManager#clearResetPasswordToken(android.content.ComponentName): + Method 'clearResetPasswordToken' documentation mentions permissions already declared by @RequiresPermission +RequiresPermission: android.app.admin.DevicePolicyManager#createAndProvisionManagedProfile(android.app.admin.ManagedProfileProvisioningParams): + Method 'createAndProvisionManagedProfile' documentation mentions permissions already declared by @RequiresPermission +RequiresPermission: android.app.admin.DevicePolicyManager#finalizeWorkProfileProvisioning(android.os.UserHandle, android.accounts.Account): + Method 'finalizeWorkProfileProvisioning' documentation mentions permissions already declared by @RequiresPermission +RequiresPermission: android.app.admin.DevicePolicyManager#generateKeyPair(android.content.ComponentName, String, android.security.keystore.KeyGenParameterSpec, int): + Method 'generateKeyPair' documentation mentions permissions already declared by @RequiresPermission +RequiresPermission: android.app.admin.DevicePolicyManager#getApplicationExemptions(String): + Method 'getApplicationExemptions' documentation mentions permissions already declared by @RequiresPermission +RequiresPermission: android.app.admin.DevicePolicyManager#getCrossProfileWidgetProviders(android.content.ComponentName): + Method 'getCrossProfileWidgetProviders' documentation mentions permissions already declared by @RequiresPermission +RequiresPermission: android.app.admin.DevicePolicyManager#getLockTaskFeatures(android.content.ComponentName): + Method 'getLockTaskFeatures' documentation mentions permissions already declared by @RequiresPermission +RequiresPermission: android.app.admin.DevicePolicyManager#getLockTaskPackages(android.content.ComponentName): + Method 'getLockTaskPackages' documentation mentions permissions already declared by @RequiresPermission +RequiresPermission: android.app.admin.DevicePolicyManager#getNearbyAppStreamingPolicy(): + Method 'getNearbyAppStreamingPolicy' documentation mentions permissions already declared by @RequiresPermission +RequiresPermission: android.app.admin.DevicePolicyManager#getNearbyNotificationStreamingPolicy(): + Method 'getNearbyNotificationStreamingPolicy' documentation mentions permissions already declared by @RequiresPermission +RequiresPermission: android.app.admin.DevicePolicyManager#getOrganizationName(android.content.ComponentName): + Method 'getOrganizationName' documentation mentions permissions already declared by @RequiresPermission +RequiresPermission: android.app.admin.DevicePolicyManager#getPasswordComplexity(): + Method 'getPasswordComplexity' documentation mentions permissions already declared by @RequiresPermission +RequiresPermission: android.app.admin.DevicePolicyManager#getShortSupportMessage(android.content.ComponentName): + Method 'getShortSupportMessage' documentation mentions permissions already declared by @RequiresPermission +RequiresPermission: android.app.admin.DevicePolicyManager#getUserControlDisabledPackages(android.content.ComponentName): + Method 'getUserControlDisabledPackages' documentation mentions permissions already declared by @RequiresPermission +RequiresPermission: android.app.admin.DevicePolicyManager#hasKeyPair(String): + Method 'hasKeyPair' documentation mentions permissions already declared by @RequiresPermission +RequiresPermission: android.app.admin.DevicePolicyManager#installKeyPair(android.content.ComponentName, java.security.PrivateKey, java.security.cert.Certificate, String): + Method 'installKeyPair' documentation mentions permissions already declared by @RequiresPermission +RequiresPermission: android.app.admin.DevicePolicyManager#installKeyPair(android.content.ComponentName, java.security.PrivateKey, java.security.cert.Certificate[], String, boolean): + Method 'installKeyPair' documentation mentions permissions already declared by @RequiresPermission +RequiresPermission: android.app.admin.DevicePolicyManager#installKeyPair(android.content.ComponentName, java.security.PrivateKey, java.security.cert.Certificate[], String, int): + Method 'installKeyPair' documentation mentions permissions already declared by @RequiresPermission +RequiresPermission: android.app.admin.DevicePolicyManager#isDeviceProvisioningConfigApplied(): + Method 'isDeviceProvisioningConfigApplied' documentation mentions permissions already declared by @RequiresPermission +RequiresPermission: android.app.admin.DevicePolicyManager#isPackageSuspended(android.content.ComponentName, String): + Method 'isPackageSuspended' documentation mentions permissions already declared by @RequiresPermission +RequiresPermission: android.app.admin.DevicePolicyManager#isResetPasswordTokenActive(android.content.ComponentName): + Method 'isResetPasswordTokenActive' documentation mentions permissions already declared by @RequiresPermission +RequiresPermission: android.app.admin.DevicePolicyManager#lockNow(int): + Method 'lockNow' documentation mentions permissions already declared by @RequiresPermission +RequiresPermission: android.app.admin.DevicePolicyManager#provisionFullyManagedDevice(android.app.admin.FullyManagedDeviceProvisioningParams): + Method 'provisionFullyManagedDevice' documentation mentions permissions already declared by @RequiresPermission +RequiresPermission: android.app.admin.DevicePolicyManager#removeCrossProfileWidgetProvider(android.content.ComponentName, String): + Method 'removeCrossProfileWidgetProvider' documentation mentions permissions already declared by @RequiresPermission +RequiresPermission: android.app.admin.DevicePolicyManager#sendLostModeLocationUpdate(java.util.concurrent.Executor, java.util.function.Consumer<java.lang.Boolean>): + Method 'sendLostModeLocationUpdate' documentation mentions permissions already declared by @RequiresPermission +RequiresPermission: android.app.admin.DevicePolicyManager#setActiveProfileOwner(android.content.ComponentName, String): + Method 'setActiveProfileOwner' documentation mentions permissions already declared by @RequiresPermission +RequiresPermission: android.app.admin.DevicePolicyManager#setAlwaysOnVpnPackage(android.content.ComponentName, String, boolean): + Method 'setAlwaysOnVpnPackage' documentation mentions permissions without declaring @RequiresPermission +RequiresPermission: android.app.admin.DevicePolicyManager#setApplicationExemptions(String, java.util.Set<java.lang.Integer>): + Method 'setApplicationExemptions' documentation mentions permissions already declared by @RequiresPermission +RequiresPermission: android.app.admin.DevicePolicyManager#setDeviceProvisioningConfigApplied(): + Method 'setDeviceProvisioningConfigApplied' documentation mentions permissions already declared by @RequiresPermission +RequiresPermission: android.app.admin.DevicePolicyManager#setLockTaskFeatures(android.content.ComponentName, int): + Method 'setLockTaskFeatures' documentation mentions permissions already declared by @RequiresPermission +RequiresPermission: android.app.admin.DevicePolicyManager#setLockTaskPackages(android.content.ComponentName, String[]): + Method 'setLockTaskPackages' documentation mentions permissions already declared by @RequiresPermission +RequiresPermission: android.app.admin.DevicePolicyManager#setPermittedInputMethods(android.content.ComponentName, java.util.List<java.lang.String>): + Method 'setPermittedInputMethods' documentation mentions permissions already declared by @RequiresPermission +RequiresPermission: android.app.admin.DevicePolicyManager#setUninstallBlocked(android.content.ComponentName, String, boolean): + Method 'setUninstallBlocked' documentation mentions permissions already declared by @RequiresPermission +RequiresPermission: android.app.admin.DevicePolicyManager#setUserControlDisabledPackages(android.content.ComponentName, java.util.List<java.lang.String>): + Method 'setUserControlDisabledPackages' documentation mentions permissions already declared by @RequiresPermission +RequiresPermission: android.app.admin.DevicePolicyManager#wipeData(int): + Method 'wipeData' documentation mentions permissions already declared by @RequiresPermission +RequiresPermission: android.app.admin.DevicePolicyManager#wipeData(int, CharSequence): + Method 'wipeData' documentation mentions permissions already declared by @RequiresPermission +RequiresPermission: android.app.admin.DevicePolicyManager#wipeDevice(int): + Method 'wipeDevice' documentation mentions permissions already declared by @RequiresPermission +RequiresPermission: android.app.admin.PolicyUpdateReceiver#onPolicyChanged(android.content.Context, String, android.os.Bundle, android.app.admin.TargetUser, android.app.admin.PolicyUpdateResult): + Method 'onPolicyChanged' documentation mentions permissions without declaring @RequiresPermission +RequiresPermission: android.app.admin.PolicyUpdateReceiver#onPolicySetResult(android.content.Context, String, android.os.Bundle, android.app.admin.TargetUser, android.app.admin.PolicyUpdateResult): + Method 'onPolicySetResult' documentation mentions permissions without declaring @RequiresPermission +RequiresPermission: android.app.backup.BackupManager#dataChanged(String): + Method 'dataChanged' documentation mentions permissions without declaring @RequiresPermission +RequiresPermission: android.app.backup.BackupManager#requestBackup(String[], android.app.backup.BackupObserver, android.app.backup.BackupManagerMonitor, int): + Method 'requestBackup' documentation mentions permissions already declared by @RequiresPermission +RequiresPermission: android.app.backup.BackupManager#setFrameworkSchedulingEnabled(boolean): + Method 'setFrameworkSchedulingEnabled' documentation mentions permissions already declared by @RequiresPermission +RequiresPermission: android.app.backup.BackupManager#updateTransportAttributes(android.content.ComponentName, String, android.content.Intent, String, android.content.Intent, CharSequence): + Method 'updateTransportAttributes' documentation mentions permissions already declared by @RequiresPermission +RequiresPermission: android.app.backup.BackupManager#updateTransportAttributes(android.content.ComponentName, String, android.content.Intent, String, android.content.Intent, String): + Method 'updateTransportAttributes' documentation mentions permissions already declared by @RequiresPermission +RequiresPermission: android.app.backup.RestoreSession#restoreAll(long, android.app.backup.RestoreObserver): + Method 'restoreAll' documentation mentions permissions without declaring @RequiresPermission +RequiresPermission: android.app.backup.RestoreSession#restoreAll(long, android.app.backup.RestoreObserver, android.app.backup.BackupManagerMonitor): + Method 'restoreAll' documentation mentions permissions without declaring @RequiresPermission +RequiresPermission: android.app.backup.RestoreSession#restorePackage(String, android.app.backup.RestoreObserver): + Method 'restorePackage' documentation mentions permissions without declaring @RequiresPermission +RequiresPermission: android.app.backup.RestoreSession#restorePackage(String, android.app.backup.RestoreObserver, android.app.backup.BackupManagerMonitor): + Method 'restorePackage' documentation mentions permissions without declaring @RequiresPermission +RequiresPermission: android.app.backup.RestoreSession#restorePackages(long, android.app.backup.RestoreObserver, java.util.Set<java.lang.String>): + Method 'restorePackages' documentation mentions permissions without declaring @RequiresPermission +RequiresPermission: android.app.backup.RestoreSession#restorePackages(long, android.app.backup.RestoreObserver, java.util.Set<java.lang.String>, android.app.backup.BackupManagerMonitor): + Method 'restorePackages' documentation mentions permissions without declaring @RequiresPermission +RequiresPermission: android.app.job.JobInfo.Builder#setRequiredNetwork(android.net.NetworkRequest): + Method 'setRequiredNetwork' documentation mentions permissions without declaring @RequiresPermission +RequiresPermission: android.app.job.JobInfo.Builder#setRequiredNetworkType(int): + Method 'setRequiredNetworkType' documentation mentions permissions without declaring @RequiresPermission +RequiresPermission: android.app.job.JobInfo.Builder#setUserInitiated(boolean): + Method 'setUserInitiated' documentation mentions permissions already declared by @RequiresPermission +RequiresPermission: android.app.job.JobParameters#isUserInitiatedJob(): + Method 'isUserInitiatedJob' documentation mentions permissions without declaring @RequiresPermission +RequiresPermission: android.app.job.JobScheduler#canRunUserInitiatedJobs(): + Method 'canRunUserInitiatedJobs' documentation mentions permissions without declaring @RequiresPermission +RequiresPermission: android.app.people.PeopleManager#isConversation(String, String): + Method 'isConversation' documentation mentions permissions already declared by @RequiresPermission +RequiresPermission: android.app.usage.StorageStatsManager#queryExternalStatsForUser(java.util.UUID, android.os.UserHandle): + Method 'queryExternalStatsForUser' documentation mentions permissions without declaring @RequiresPermission +RequiresPermission: android.app.usage.StorageStatsManager#queryStatsForPackage(java.util.UUID, String, android.os.UserHandle): + Method 'queryStatsForPackage' documentation mentions permissions without declaring @RequiresPermission +RequiresPermission: android.app.usage.StorageStatsManager#queryStatsForUid(java.util.UUID, int): + Method 'queryStatsForUid' documentation mentions permissions without declaring @RequiresPermission +RequiresPermission: android.app.usage.StorageStatsManager#queryStatsForUser(java.util.UUID, android.os.UserHandle): + Method 'queryStatsForUser' documentation mentions permissions without declaring @RequiresPermission +RequiresPermission: android.app.usage.UsageEvents.Event#getTaskRootClassName(): + Method 'getTaskRootClassName' documentation mentions permissions without declaring @RequiresPermission +RequiresPermission: android.app.usage.UsageEvents.Event#getTaskRootPackageName(): + Method 'getTaskRootPackageName' documentation mentions permissions without declaring @RequiresPermission +RequiresPermission: android.app.usage.UsageStatsManager#getAppStandbyBucket(String): + Method 'getAppStandbyBucket' documentation mentions permissions already declared by @RequiresPermission +RequiresPermission: android.app.usage.UsageStatsManager#getAppStandbyBuckets(): + Method 'getAppStandbyBuckets' documentation mentions permissions already declared by @RequiresPermission +RequiresPermission: android.app.usage.UsageStatsManager#isAppInactive(String): + Method 'isAppInactive' documentation mentions permissions without declaring @RequiresPermission +RequiresPermission: android.app.usage.UsageStatsManager#onCarrierPrivilegedAppsChanged(): + Method 'onCarrierPrivilegedAppsChanged' documentation mentions permissions already declared by @RequiresPermission +RequiresPermission: android.app.usage.UsageStatsManager#queryAndAggregateUsageStats(long, long): + Method 'queryAndAggregateUsageStats' documentation mentions permissions without declaring @RequiresPermission +RequiresPermission: android.app.usage.UsageStatsManager#queryConfigurations(int, long, long): + Method 'queryConfigurations' documentation mentions permissions without declaring @RequiresPermission +RequiresPermission: android.app.usage.UsageStatsManager#queryEventStats(int, long, long): + Method 'queryEventStats' documentation mentions permissions without declaring @RequiresPermission +RequiresPermission: android.app.usage.UsageStatsManager#queryEvents(long, long): + Method 'queryEvents' documentation mentions permissions without declaring @RequiresPermission +RequiresPermission: android.app.usage.UsageStatsManager#queryUsageStats(int, long, long): + Method 'queryUsageStats' documentation mentions permissions without declaring @RequiresPermission +RequiresPermission: android.app.usage.UsageStatsManager#registerAppUsageLimitObserver(int, String[], java.time.Duration, java.time.Duration, android.app.PendingIntent): + Method 'registerAppUsageLimitObserver' documentation mentions permissions already declared by @RequiresPermission +RequiresPermission: android.app.usage.UsageStatsManager#registerAppUsageObserver(int, String[], long, java.util.concurrent.TimeUnit, android.app.PendingIntent): + Method 'registerAppUsageObserver' documentation mentions permissions already declared by @RequiresPermission +RequiresPermission: android.app.usage.UsageStatsManager#registerUsageSessionObserver(int, String[], java.time.Duration, java.time.Duration, android.app.PendingIntent, android.app.PendingIntent): + Method 'registerUsageSessionObserver' documentation mentions permissions already declared by @RequiresPermission +RequiresPermission: android.app.usage.UsageStatsManager#reportUsageStart(android.app.Activity, String): + Method 'reportUsageStart' documentation mentions permissions without declaring @RequiresPermission +RequiresPermission: android.app.usage.UsageStatsManager#reportUsageStart(android.app.Activity, String, long): + Method 'reportUsageStart' documentation mentions permissions without declaring @RequiresPermission +RequiresPermission: android.app.usage.UsageStatsManager#unregisterAppUsageLimitObserver(int): + Method 'unregisterAppUsageLimitObserver' documentation mentions permissions already declared by @RequiresPermission +RequiresPermission: android.app.usage.UsageStatsManager#unregisterAppUsageObserver(int): + Method 'unregisterAppUsageObserver' documentation mentions permissions already declared by @RequiresPermission +RequiresPermission: android.app.usage.UsageStatsManager#unregisterUsageSessionObserver(int): + Method 'unregisterUsageSessionObserver' documentation mentions permissions already declared by @RequiresPermission +RequiresPermission: android.appwidget.AppWidgetManager#bindAppWidgetIdIfAllowed(int, android.os.UserHandle, android.content.ComponentName, android.os.Bundle): + Method 'bindAppWidgetIdIfAllowed' documentation mentions permissions without declaring @RequiresPermission +RequiresPermission: android.companion.CompanionDeviceManager#isDeviceAssociatedForWifiConnection(String, android.net.MacAddress, android.os.UserHandle): + Method 'isDeviceAssociatedForWifiConnection' documentation mentions permissions already declared by @RequiresPermission +RequiresPermission: android.companion.CompanionDeviceManager#startObservingDevicePresence(String): + Method 'startObservingDevicePresence' documentation mentions permissions already declared by @RequiresPermission +RequiresPermission: android.companion.CompanionDeviceManager#stopObservingDevicePresence(String): + Method 'stopObservingDevicePresence' documentation mentions permissions already declared by @RequiresPermission +RequiresPermission: android.companion.virtual.VirtualDeviceManager#createVirtualDevice(int, android.companion.virtual.VirtualDeviceParams): + Method 'createVirtualDevice' documentation mentions permissions already declared by @RequiresPermission +RequiresPermission: android.companion.virtual.VirtualDeviceParams.Builder#setLockState(int): + Method 'setLockState' documentation mentions permissions already declared by @RequiresPermission +RequiresPermission: android.content.ContentResolver#addPeriodicSync(android.accounts.Account, String, android.os.Bundle, long): + Method 'addPeriodicSync' documentation mentions permissions without declaring @RequiresPermission +RequiresPermission: android.content.ContentResolver#cancelSync(android.content.SyncRequest): + Method 'cancelSync' documentation mentions permissions without declaring @RequiresPermission +RequiresPermission: android.content.ContentResolver#getCurrentSync(): + Method 'getCurrentSync' documentation mentions permissions without declaring @RequiresPermission +RequiresPermission: android.content.ContentResolver#getCurrentSyncs(): + Method 'getCurrentSyncs' documentation mentions permissions without declaring @RequiresPermission +RequiresPermission: android.content.ContentResolver#getIsSyncable(android.accounts.Account, String): + Method 'getIsSyncable' documentation mentions permissions without declaring @RequiresPermission +RequiresPermission: android.content.ContentResolver#getMasterSyncAutomatically(): + Method 'getMasterSyncAutomatically' documentation mentions permissions without declaring @RequiresPermission +RequiresPermission: android.content.ContentResolver#getPeriodicSyncs(android.accounts.Account, String): + Method 'getPeriodicSyncs' documentation mentions permissions without declaring @RequiresPermission +RequiresPermission: android.content.ContentResolver#getSyncAutomatically(android.accounts.Account, String): + Method 'getSyncAutomatically' documentation mentions permissions without declaring @RequiresPermission +RequiresPermission: android.content.ContentResolver#isSyncActive(android.accounts.Account, String): + Method 'isSyncActive' documentation mentions permissions without declaring @RequiresPermission +RequiresPermission: android.content.ContentResolver#isSyncPending(android.accounts.Account, String): + Method 'isSyncPending' documentation mentions permissions without declaring @RequiresPermission +RequiresPermission: android.content.ContentResolver#registerContentObserverAsUser(android.net.Uri, boolean, android.database.ContentObserver, android.os.UserHandle): + Method 'registerContentObserverAsUser' documentation mentions permissions already declared by @RequiresPermission +RequiresPermission: android.content.ContentResolver#removePeriodicSync(android.accounts.Account, String, android.os.Bundle): + Method 'removePeriodicSync' documentation mentions permissions without declaring @RequiresPermission +RequiresPermission: android.content.ContentResolver#setIsSyncable(android.accounts.Account, String, int): + Method 'setIsSyncable' documentation mentions permissions without declaring @RequiresPermission +RequiresPermission: android.content.ContentResolver#setMasterSyncAutomatically(boolean): + Method 'setMasterSyncAutomatically' documentation mentions permissions without declaring @RequiresPermission +RequiresPermission: android.content.ContentResolver#setSyncAutomatically(android.accounts.Account, String, boolean): + Method 'setSyncAutomatically' documentation mentions permissions without declaring @RequiresPermission +RequiresPermission: android.content.Context#bindServiceAsUser(android.content.Intent, android.content.ServiceConnection, int, android.os.UserHandle): + Method 'bindServiceAsUser' documentation mentions permissions already declared by @RequiresPermission +RequiresPermission: android.content.Context#clearWallpaper(): + Method 'clearWallpaper' documentation mentions permissions without declaring @RequiresPermission +RequiresPermission: android.content.Context#getExternalCacheDir(): + Method 'getExternalCacheDir' documentation mentions permissions without declaring @RequiresPermission +RequiresPermission: android.content.Context#getExternalCacheDirs(): + Method 'getExternalCacheDirs' documentation mentions permissions without declaring @RequiresPermission +RequiresPermission: android.content.Context#getExternalFilesDir(String): + Method 'getExternalFilesDir' documentation mentions permissions without declaring @RequiresPermission +RequiresPermission: android.content.Context#getExternalFilesDirs(String): + Method 'getExternalFilesDirs' documentation mentions permissions without declaring @RequiresPermission +RequiresPermission: android.content.Context#getExternalMediaDirs(): + Method 'getExternalMediaDirs' documentation mentions permissions without declaring @RequiresPermission +RequiresPermission: android.content.Context#getObbDir(): + Method 'getObbDir' documentation mentions permissions without declaring @RequiresPermission +RequiresPermission: android.content.Context#getObbDirs(): + Method 'getObbDirs' documentation mentions permissions without declaring @RequiresPermission +RequiresPermission: android.content.Context#removeStickyBroadcastAsUser(android.content.Intent, android.os.UserHandle): + Method 'removeStickyBroadcastAsUser' documentation mentions permissions already declared by @RequiresPermission +RequiresPermission: android.content.Context#setWallpaper(android.graphics.Bitmap): + Method 'setWallpaper' documentation mentions permissions without declaring @RequiresPermission +RequiresPermission: android.content.Context#setWallpaper(java.io.InputStream): + Method 'setWallpaper' documentation mentions permissions without declaring @RequiresPermission +RequiresPermission: android.content.pm.CrossProfileApps#canRequestInteractAcrossProfiles(): + Method 'canRequestInteractAcrossProfiles' documentation mentions permissions without declaring @RequiresPermission +RequiresPermission: android.content.pm.CrossProfileApps#startActivity(android.content.ComponentName, android.os.UserHandle): + Method 'startActivity' documentation mentions permissions already declared by @RequiresPermission +RequiresPermission: android.content.pm.CrossProfileApps#startActivity(android.content.ComponentName, android.os.UserHandle, android.app.Activity, android.os.Bundle): + Method 'startActivity' documentation mentions permissions already declared by @RequiresPermission +RequiresPermission: android.content.pm.CrossProfileApps#startActivity(android.content.Intent, android.os.UserHandle, android.app.Activity): + Method 'startActivity' documentation mentions permissions already declared by @RequiresPermission +RequiresPermission: android.content.pm.CrossProfileApps#startActivity(android.content.Intent, android.os.UserHandle, android.app.Activity, android.os.Bundle): + Method 'startActivity' documentation mentions permissions already declared by @RequiresPermission +RequiresPermission: android.content.pm.LauncherApps#getAllPackageInstallerSessions(): + Method 'getAllPackageInstallerSessions' documentation mentions permissions without declaring @RequiresPermission +RequiresPermission: android.content.pm.LauncherApps#registerPackageInstallerSessionCallback(java.util.concurrent.Executor, android.content.pm.PackageInstaller.SessionCallback): + Method 'registerPackageInstallerSessionCallback' documentation mentions permissions without declaring @RequiresPermission +RequiresPermission: android.content.pm.LauncherApps.Callback#onPackagesSuspended(String[], android.os.UserHandle, android.os.Bundle): + Method 'onPackagesSuspended' documentation mentions permissions without declaring @RequiresPermission +RequiresPermission: android.content.pm.PackageInstaller#getAllSessions(): + Method 'getAllSessions' documentation mentions permissions without declaring @RequiresPermission +RequiresPermission: android.content.pm.PackageInstaller#getSessionInfo(int): + Method 'getSessionInfo' documentation mentions permissions without declaring @RequiresPermission +RequiresPermission: android.content.pm.PackageInstaller#getStagedSessions(): + Method 'getStagedSessions' documentation mentions permissions without declaring @RequiresPermission +RequiresPermission: android.content.pm.PackageInstaller#registerSessionCallback(android.content.pm.PackageInstaller.SessionCallback): + Method 'registerSessionCallback' documentation mentions permissions without declaring @RequiresPermission +RequiresPermission: android.content.pm.PackageInstaller.Session#requestUserPreapproval(android.content.pm.PackageInstaller.PreapprovalDetails, android.content.IntentSender): + Method 'requestUserPreapproval' documentation mentions permissions without declaring @RequiresPermission +RequiresPermission: android.content.pm.PackageInstaller.SessionParams#setInstallerPackageName(String): + Method 'setInstallerPackageName' documentation mentions permissions without declaring @RequiresPermission +RequiresPermission: android.content.pm.PackageInstaller.SessionParams#setPermissionState(String, int): + Method 'setPermissionState' documentation mentions permissions already declared by @RequiresPermission +RequiresPermission: android.content.pm.PackageInstaller.SessionParams#setRequestUpdateOwnership(boolean): + Method 'setRequestUpdateOwnership' documentation mentions permissions already declared by @RequiresPermission +RequiresPermission: android.content.pm.PackageInstaller.SessionParams#setRequireUserAction(int): + Method 'setRequireUserAction' documentation mentions permissions without declaring @RequiresPermission +RequiresPermission: android.content.pm.PackageManager#canRequestPackageInstalls(): + Method 'canRequestPackageInstalls' documentation mentions permissions without declaring @RequiresPermission +RequiresPermission: android.content.pm.PackageManager#getSuspendedPackageAppExtras(): + Method 'getSuspendedPackageAppExtras' documentation mentions permissions without declaring @RequiresPermission +RequiresPermission: android.content.pm.PackageManager#getUnsuspendablePackages(String[]): + Method 'getUnsuspendablePackages' documentation mentions permissions already declared by @RequiresPermission +RequiresPermission: android.content.pm.PackageManager#grantRuntimePermission(String, String, android.os.UserHandle): + Method 'grantRuntimePermission' documentation mentions permissions already declared by @RequiresPermission +RequiresPermission: android.content.pm.PackageManager#isAutoRevokeWhitelisted(String): + Method 'isAutoRevokeWhitelisted' documentation mentions permissions already declared by @RequiresPermission +RequiresPermission: android.content.pm.PackageManager#isPackageSuspended(): + Method 'isPackageSuspended' documentation mentions permissions without declaring @RequiresPermission +RequiresPermission: android.content.pm.PackageManager#revokeRuntimePermission(String, String, android.os.UserHandle): + Method 'revokeRuntimePermission' documentation mentions permissions already declared by @RequiresPermission +RequiresPermission: android.content.pm.PackageManager#revokeRuntimePermission(String, String, android.os.UserHandle, String): + Method 'revokeRuntimePermission' documentation mentions permissions already declared by @RequiresPermission +RequiresPermission: android.content.pm.PackageManager#setDistractingPackageRestrictions(String[], int): + Method 'setDistractingPackageRestrictions' documentation mentions permissions already declared by @RequiresPermission +RequiresPermission: android.content.pm.PackageManager#setPackagesSuspended(String[], boolean, android.os.PersistableBundle, android.os.PersistableBundle, String): + Method 'setPackagesSuspended' documentation mentions permissions already declared by @RequiresPermission +RequiresPermission: android.content.pm.PackageManager#setPackagesSuspended(String[], boolean, android.os.PersistableBundle, android.os.PersistableBundle, android.content.pm.SuspendDialogInfo): + Method 'setPackagesSuspended' documentation mentions permissions already declared by @RequiresPermission +RequiresPermission: android.content.pm.PackageManager#setPackagesSuspended(String[], boolean, android.os.PersistableBundle, android.os.PersistableBundle, android.content.pm.SuspendDialogInfo, int): + Method 'setPackagesSuspended' documentation mentions permissions already declared by @RequiresPermission +RequiresPermission: android.content.pm.PackageManager#verifyIntentFilter(int, int, java.util.List<java.lang.String>): + Method 'verifyIntentFilter' documentation mentions permissions already declared by @RequiresPermission +RequiresPermission: android.hardware.Sensor#getHighestDirectReportRateLevel(): + Method 'getHighestDirectReportRateLevel' documentation mentions permissions without declaring @RequiresPermission +RequiresPermission: android.hardware.Sensor#getMinDelay(): + Method 'getMinDelay' documentation mentions permissions without declaring @RequiresPermission +RequiresPermission: android.hardware.camera2.CameraCharacteristics#getKeysNeedingPermission(): + Method 'getKeysNeedingPermission' documentation mentions permissions without declaring @RequiresPermission +RequiresPermission: android.hardware.camera2.CameraManager.AvailabilityCallback#onCameraClosed(String): + Method 'onCameraClosed' documentation mentions permissions already declared by @RequiresPermission +RequiresPermission: android.hardware.camera2.CameraManager.AvailabilityCallback#onCameraOpened(String, String): + Method 'onCameraOpened' documentation mentions permissions already declared by @RequiresPermission +RequiresPermission: android.hardware.hdmi.HdmiControlManager#getHdmiCecVersion(): + Method 'getHdmiCecVersion' documentation mentions permissions already declared by @RequiresPermission +RequiresPermission: android.hardware.hdmi.HdmiControlManager#setHdmiCecVersion(int): + Method 'setHdmiCecVersion' documentation mentions permissions already declared by @RequiresPermission +RequiresPermission: android.hardware.location.GeofenceHardware#addGeofence(int, int, android.hardware.location.GeofenceHardwareRequest, android.hardware.location.GeofenceHardwareCallback): + Method 'addGeofence' documentation mentions permissions without declaring @RequiresPermission +RequiresPermission: android.hardware.location.GeofenceHardware#getMonitoringTypes(): + Method 'getMonitoringTypes' documentation mentions permissions without declaring @RequiresPermission +RequiresPermission: android.hardware.location.GeofenceHardware#pauseGeofence(int, int): + Method 'pauseGeofence' documentation mentions permissions without declaring @RequiresPermission +RequiresPermission: android.hardware.location.GeofenceHardware#registerForMonitorStateChangeCallback(int, android.hardware.location.GeofenceHardwareMonitorCallback): + Method 'registerForMonitorStateChangeCallback' documentation mentions permissions without declaring @RequiresPermission +RequiresPermission: android.hardware.location.GeofenceHardware#removeGeofence(int, int): + Method 'removeGeofence' documentation mentions permissions without declaring @RequiresPermission +RequiresPermission: android.hardware.location.GeofenceHardware#resumeGeofence(int, int, int): + Method 'resumeGeofence' documentation mentions permissions without declaring @RequiresPermission +RequiresPermission: android.hardware.location.GeofenceHardware#unregisterForMonitorStateChangeCallback(int, android.hardware.location.GeofenceHardwareMonitorCallback): + Method 'unregisterForMonitorStateChangeCallback' documentation mentions permissions without declaring @RequiresPermission +RequiresPermission: android.hardware.usb.UsbManager#grantPermission(android.hardware.usb.UsbDevice, String): + Method 'grantPermission' documentation mentions permissions already declared by @RequiresPermission +RequiresPermission: android.hardware.usb.UsbManager#hasPermission(android.hardware.usb.UsbDevice): + Method 'hasPermission' documentation mentions permissions without declaring @RequiresPermission +RequiresPermission: android.hardware.usb.UsbManager#requestPermission(android.hardware.usb.UsbDevice, android.app.PendingIntent): + Method 'requestPermission' documentation mentions permissions without declaring @RequiresPermission +RequiresPermission: android.media.AudioAttributes.Builder#setHapticChannelsMuted(boolean): + Method 'setHapticChannelsMuted' documentation mentions permissions without declaring @RequiresPermission +RequiresPermission: android.media.AudioManager#getCallDownlinkExtractionAudioRecord(android.media.AudioFormat): + Method 'getCallDownlinkExtractionAudioRecord' documentation mentions permissions already declared by @RequiresPermission +RequiresPermission: android.media.AudioManager#getCallUplinkInjectionAudioTrack(android.media.AudioFormat): + Method 'getCallUplinkInjectionAudioTrack' documentation mentions permissions already declared by @RequiresPermission +RequiresPermission: android.media.AudioManager#registerAudioPolicy(android.media.audiopolicy.AudioPolicy): + Method 'registerAudioPolicy' documentation mentions permissions already declared by @RequiresPermission +RequiresPermission: android.media.AudioRecord#shareAudioHistory(String, long): + Method 'shareAudioHistory' documentation mentions permissions already declared by @RequiresPermission +RequiresPermission: android.media.AudioRecordingConfiguration#getClientUid(): + Method 'getClientUid' documentation mentions permissions already declared by @RequiresPermission +RequiresPermission: android.media.MediaCodec#createByCodecNameForClient(String, int, int): + Method 'createByCodecNameForClient' documentation mentions permissions already declared by @RequiresPermission +RequiresPermission: android.media.MediaExtractor#setDataSource(String): + Method 'setDataSource' documentation mentions permissions without declaring @RequiresPermission +RequiresPermission: android.media.MediaExtractor#setDataSource(String, java.util.Map<java.lang.String,java.lang.String>): + Method 'setDataSource' documentation mentions permissions without declaring @RequiresPermission +RequiresPermission: android.media.MediaExtractor#setDataSource(android.content.Context, android.net.Uri, java.util.Map<java.lang.String,java.lang.String>): + Method 'setDataSource' documentation mentions permissions without declaring @RequiresPermission +RequiresPermission: android.media.MediaPlayer#setWakeMode(android.content.Context, int): + Method 'setWakeMode' documentation mentions permissions without declaring @RequiresPermission +RequiresPermission: android.media.MediaRouter2#getInstance(android.content.Context, String): + Method 'getInstance' documentation mentions permissions already declared by @RequiresPermission +RequiresPermission: android.media.RingtoneManager#getCursor(): + Method 'getCursor' documentation mentions permissions without declaring @RequiresPermission +RequiresPermission: android.media.RingtoneManager#getValidRingtoneUri(android.content.Context): + Method 'getValidRingtoneUri' documentation mentions permissions without declaring @RequiresPermission +RequiresPermission: android.media.audiofx.HapticGenerator#setEnabled(boolean): + Method 'setEnabled' documentation mentions permissions without declaring @RequiresPermission +RequiresPermission: android.media.projection.MediaProjection#createVirtualDisplay(String, int, int, int, int, android.view.Surface, android.hardware.display.VirtualDisplay.Callback, android.os.Handler): + Method 'createVirtualDisplay' documentation mentions permissions without declaring @RequiresPermission +RequiresPermission: android.media.projection.MediaProjectionManager#getMediaProjection(int, android.content.Intent): + Method 'getMediaProjection' documentation mentions permissions without declaring @RequiresPermission +RequiresPermission: android.media.session.MediaSessionManager#addOnActiveSessionsChangedListener(android.content.ComponentName, android.os.UserHandle, java.util.concurrent.Executor, android.media.session.MediaSessionManager.OnActiveSessionsChangedListener): + Method 'addOnActiveSessionsChangedListener' documentation mentions permissions without declaring @RequiresPermission +RequiresPermission: android.media.session.MediaSessionManager#addOnActiveSessionsChangedListener(android.media.session.MediaSessionManager.OnActiveSessionsChangedListener, android.content.ComponentName): + Method 'addOnActiveSessionsChangedListener' documentation mentions permissions without declaring @RequiresPermission +RequiresPermission: android.media.session.MediaSessionManager#addOnActiveSessionsChangedListener(android.media.session.MediaSessionManager.OnActiveSessionsChangedListener, android.content.ComponentName, android.os.Handler): + Method 'addOnActiveSessionsChangedListener' documentation mentions permissions without declaring @RequiresPermission +RequiresPermission: android.media.session.MediaSessionManager#addOnMediaKeyEventSessionChangedListener(java.util.concurrent.Executor, android.media.session.MediaSessionManager.OnMediaKeyEventSessionChangedListener): + Method 'addOnMediaKeyEventSessionChangedListener' documentation mentions permissions without declaring @RequiresPermission +RequiresPermission: android.media.session.MediaSessionManager#getActiveSessions(android.content.ComponentName): + Method 'getActiveSessions' documentation mentions permissions without declaring @RequiresPermission +RequiresPermission: android.media.session.MediaSessionManager#getActiveSessionsForUser(android.content.ComponentName, android.os.UserHandle): + Method 'getActiveSessionsForUser' documentation mentions permissions without declaring @RequiresPermission +RequiresPermission: android.media.session.MediaSessionManager#getMediaKeyEventSession(): + Method 'getMediaKeyEventSession' documentation mentions permissions without declaring @RequiresPermission +RequiresPermission: android.media.session.MediaSessionManager#getMediaKeyEventSessionPackageName(): + Method 'getMediaKeyEventSessionPackageName' documentation mentions permissions without declaring @RequiresPermission +RequiresPermission: android.media.session.MediaSessionManager#isTrustedForMediaControl(android.media.session.MediaSessionManager.RemoteUserInfo): + Method 'isTrustedForMediaControl' documentation mentions permissions without declaring @RequiresPermission +RequiresPermission: android.media.voice.KeyphraseModelManager#deleteKeyphraseSoundModel(int, java.util.Locale): + Method 'deleteKeyphraseSoundModel' documentation mentions permissions already declared by @RequiresPermission +RequiresPermission: android.media.voice.KeyphraseModelManager#getKeyphraseSoundModel(int, java.util.Locale): + Method 'getKeyphraseSoundModel' documentation mentions permissions already declared by @RequiresPermission +RequiresPermission: android.media.voice.KeyphraseModelManager#updateKeyphraseSoundModel(android.hardware.soundtrigger.SoundTrigger.KeyphraseSoundModel): + Method 'updateKeyphraseSoundModel' documentation mentions permissions already declared by @RequiresPermission +RequiresPermission: android.net.NetworkScoreManager#clearScores(): + Method 'clearScores' documentation mentions permissions already declared by @RequiresPermission +RequiresPermission: android.net.NetworkScoreManager#disableScoring(): + Method 'disableScoring' documentation mentions permissions already declared by @RequiresPermission +RequiresPermission: android.net.NetworkScoreManager#getActiveScorerPackage(): + Method 'getActiveScorerPackage' documentation mentions permissions already declared by @RequiresPermission +RequiresPermission: android.net.NetworkScoreManager#registerNetworkScoreCallback(int, int, java.util.concurrent.Executor, android.net.NetworkScoreManager.NetworkScoreCallback): + Method 'registerNetworkScoreCallback' documentation mentions permissions already declared by @RequiresPermission +RequiresPermission: android.net.NetworkScoreManager#requestScores(java.util.Collection<android.net.NetworkKey>): + Method 'requestScores' documentation mentions permissions already declared by @RequiresPermission +RequiresPermission: android.net.NetworkScoreManager#setActiveScorer(String): + Method 'setActiveScorer' documentation mentions permissions already declared by @RequiresPermission +RequiresPermission: android.net.VpnService#prepareAndAuthorize(android.content.Context): + Method 'prepareAndAuthorize' documentation mentions permissions already declared by @RequiresPermission +RequiresPermission: android.net.sip.SipAudioCall#setSpeakerMode(boolean): + Method 'setSpeakerMode' documentation mentions permissions without declaring @RequiresPermission +RequiresPermission: android.net.sip.SipAudioCall#startAudio(): + Method 'startAudio' documentation mentions permissions without declaring @RequiresPermission +RequiresPermission: android.net.vcn.VcnManager#addVcnNetworkPolicyChangeListener(java.util.concurrent.Executor, android.net.vcn.VcnManager.VcnNetworkPolicyChangeListener): + Method 'addVcnNetworkPolicyChangeListener' documentation mentions permissions already declared by @RequiresPermission +RequiresPermission: android.net.vcn.VcnManager#applyVcnNetworkPolicy(android.net.NetworkCapabilities, android.net.LinkProperties): + Method 'applyVcnNetworkPolicy' documentation mentions permissions already declared by @RequiresPermission +RequiresPermission: android.net.vcn.VcnManager#removeVcnNetworkPolicyChangeListener(android.net.vcn.VcnManager.VcnNetworkPolicyChangeListener): + Method 'removeVcnNetworkPolicyChangeListener' documentation mentions permissions already declared by @RequiresPermission +RequiresPermission: android.nfc.NfcAdapter#disableForegroundDispatch(android.app.Activity): + Method 'disableForegroundDispatch' documentation mentions permissions without declaring @RequiresPermission +RequiresPermission: android.nfc.NfcAdapter#enableForegroundDispatch(android.app.Activity, android.app.PendingIntent, android.content.IntentFilter[], String[][]): + Method 'enableForegroundDispatch' documentation mentions permissions without declaring @RequiresPermission +RequiresPermission: android.nfc.cardemulation.CardEmulation#isDefaultServiceForAid(android.content.ComponentName, String): + Method 'isDefaultServiceForAid' documentation mentions permissions without declaring @RequiresPermission +RequiresPermission: android.nfc.cardemulation.CardEmulation#isDefaultServiceForCategory(android.content.ComponentName, String): + Method 'isDefaultServiceForCategory' documentation mentions permissions without declaring @RequiresPermission +RequiresPermission: android.nfc.cardemulation.CardEmulation#setOffHostForService(android.content.ComponentName, String): + Method 'setOffHostForService' documentation mentions permissions already declared by @RequiresPermission +RequiresPermission: android.nfc.tech.IsoDep#getTimeout(): + Method 'getTimeout' documentation mentions permissions without declaring @RequiresPermission +RequiresPermission: android.nfc.tech.IsoDep#setTimeout(int): + Method 'setTimeout' documentation mentions permissions without declaring @RequiresPermission +RequiresPermission: android.nfc.tech.IsoDep#transceive(byte[]): + Method 'transceive' documentation mentions permissions without declaring @RequiresPermission +RequiresPermission: android.nfc.tech.MifareClassic#authenticateSectorWithKeyA(int, byte[]): + Method 'authenticateSectorWithKeyA' documentation mentions permissions without declaring @RequiresPermission +RequiresPermission: android.nfc.tech.MifareClassic#authenticateSectorWithKeyB(int, byte[]): + Method 'authenticateSectorWithKeyB' documentation mentions permissions without declaring @RequiresPermission +RequiresPermission: android.nfc.tech.MifareClassic#decrement(int, int): + Method 'decrement' documentation mentions permissions without declaring @RequiresPermission +RequiresPermission: android.nfc.tech.MifareClassic#getTimeout(): + Method 'getTimeout' documentation mentions permissions without declaring @RequiresPermission +RequiresPermission: android.nfc.tech.MifareClassic#increment(int, int): + Method 'increment' documentation mentions permissions without declaring @RequiresPermission +RequiresPermission: android.nfc.tech.MifareClassic#readBlock(int): + Method 'readBlock' documentation mentions permissions without declaring @RequiresPermission +RequiresPermission: android.nfc.tech.MifareClassic#restore(int): + Method 'restore' documentation mentions permissions without declaring @RequiresPermission +RequiresPermission: android.nfc.tech.MifareClassic#setTimeout(int): + Method 'setTimeout' documentation mentions permissions without declaring @RequiresPermission +RequiresPermission: android.nfc.tech.MifareClassic#transceive(byte[]): + Method 'transceive' documentation mentions permissions without declaring @RequiresPermission +RequiresPermission: android.nfc.tech.MifareClassic#transfer(int): + Method 'transfer' documentation mentions permissions without declaring @RequiresPermission +RequiresPermission: android.nfc.tech.MifareClassic#writeBlock(int, byte[]): + Method 'writeBlock' documentation mentions permissions without declaring @RequiresPermission +RequiresPermission: android.nfc.tech.MifareUltralight#getTimeout(): + Method 'getTimeout' documentation mentions permissions without declaring @RequiresPermission +RequiresPermission: android.nfc.tech.MifareUltralight#readPages(int): + Method 'readPages' documentation mentions permissions without declaring @RequiresPermission +RequiresPermission: android.nfc.tech.MifareUltralight#setTimeout(int): + Method 'setTimeout' documentation mentions permissions without declaring @RequiresPermission +RequiresPermission: android.nfc.tech.MifareUltralight#transceive(byte[]): + Method 'transceive' documentation mentions permissions without declaring @RequiresPermission +RequiresPermission: android.nfc.tech.MifareUltralight#writePage(int, byte[]): + Method 'writePage' documentation mentions permissions without declaring @RequiresPermission +RequiresPermission: android.nfc.tech.Ndef#getNdefMessage(): + Method 'getNdefMessage' documentation mentions permissions without declaring @RequiresPermission +RequiresPermission: android.nfc.tech.Ndef#isWritable(): + Method 'isWritable' documentation mentions permissions without declaring @RequiresPermission +RequiresPermission: android.nfc.tech.Ndef#makeReadOnly(): + Method 'makeReadOnly' documentation mentions permissions without declaring @RequiresPermission +RequiresPermission: android.nfc.tech.Ndef#writeNdefMessage(android.nfc.NdefMessage): + Method 'writeNdefMessage' documentation mentions permissions without declaring @RequiresPermission +RequiresPermission: android.nfc.tech.NdefFormatable#format(android.nfc.NdefMessage): + Method 'format' documentation mentions permissions without declaring @RequiresPermission +RequiresPermission: android.nfc.tech.NdefFormatable#formatReadOnly(android.nfc.NdefMessage): + Method 'formatReadOnly' documentation mentions permissions without declaring @RequiresPermission +RequiresPermission: android.nfc.tech.NfcA#getTimeout(): + Method 'getTimeout' documentation mentions permissions without declaring @RequiresPermission +RequiresPermission: android.nfc.tech.NfcA#setTimeout(int): + Method 'setTimeout' documentation mentions permissions without declaring @RequiresPermission +RequiresPermission: android.nfc.tech.NfcA#transceive(byte[]): + Method 'transceive' documentation mentions permissions without declaring @RequiresPermission +RequiresPermission: android.nfc.tech.NfcB#transceive(byte[]): + Method 'transceive' documentation mentions permissions without declaring @RequiresPermission +RequiresPermission: android.nfc.tech.NfcF#getTimeout(): + Method 'getTimeout' documentation mentions permissions without declaring @RequiresPermission +RequiresPermission: android.nfc.tech.NfcF#setTimeout(int): + Method 'setTimeout' documentation mentions permissions without declaring @RequiresPermission +RequiresPermission: android.nfc.tech.NfcF#transceive(byte[]): + Method 'transceive' documentation mentions permissions without declaring @RequiresPermission +RequiresPermission: android.nfc.tech.NfcV#transceive(byte[]): + Method 'transceive' documentation mentions permissions without declaring @RequiresPermission +RequiresPermission: android.nfc.tech.TagTechnology#close(): + Method 'close' documentation mentions permissions without declaring @RequiresPermission +RequiresPermission: android.nfc.tech.TagTechnology#connect(): + Method 'connect' documentation mentions permissions without declaring @RequiresPermission +RequiresPermission: android.os.BugreportManager#cancelBugreport(): + Method 'cancelBugreport' documentation mentions permissions without declaring @RequiresPermission +RequiresPermission: android.os.BugreportManager#preDumpUiData(): + Method 'preDumpUiData' documentation mentions permissions already declared by @RequiresPermission +RequiresPermission: android.os.Build#getSerial(): + Method 'getSerial' documentation mentions permissions already declared by @RequiresPermission +RequiresPermission: android.os.Debug#dumpService(String, java.io.FileDescriptor, String[]): + Method 'dumpService' documentation mentions permissions without declaring @RequiresPermission +RequiresPermission: android.os.DropBoxManager#getNextEntry(String, long): + Method 'getNextEntry' documentation mentions permissions already declared by @RequiresPermission +RequiresPermission: android.os.Environment#getExternalStorageDirectory(): + Method 'getExternalStorageDirectory' documentation mentions permissions without declaring @RequiresPermission +RequiresPermission: android.os.Environment#isExternalStorageManager(): + Method 'isExternalStorageManager' documentation mentions permissions without declaring @RequiresPermission +RequiresPermission: android.os.Environment#isExternalStorageManager(java.io.File): + Method 'isExternalStorageManager' documentation mentions permissions without declaring @RequiresPermission +RequiresPermission: android.os.PowerManager#dream(long): + Method 'dream' documentation mentions permissions already declared by @RequiresPermission +RequiresPermission: android.os.PowerManager#forceSuspend(): + Method 'forceSuspend' documentation mentions permissions already declared by @RequiresPermission +RequiresPermission: android.os.PowerManager#getPowerSaveModeTrigger(): + Method 'getPowerSaveModeTrigger' documentation mentions permissions without declaring @RequiresPermission +RequiresPermission: android.os.PowerManager#newWakeLock(int, String): + Method 'newWakeLock' documentation mentions permissions without declaring @RequiresPermission +RequiresPermission: android.os.PowerManager#reboot(String): + Method 'reboot' documentation mentions permissions already declared by @RequiresPermission +RequiresPermission: android.os.PowerManager#setBatteryDischargePrediction(java.time.Duration, boolean): + Method 'setBatteryDischargePrediction' documentation mentions permissions already declared by @RequiresPermission +RequiresPermission: android.os.PowerManager#setDynamicPowerSaveHint(boolean, int): + Method 'setDynamicPowerSaveHint' documentation mentions permissions already declared by @RequiresPermission +RequiresPermission: android.os.PowerManager#userActivity(long, int, int): + Method 'userActivity' documentation mentions permissions already declared by @RequiresPermission +RequiresPermission: android.os.RecoverySystem#rebootWipeUserData(android.content.Context): + Method 'rebootWipeUserData' documentation mentions permissions without declaring @RequiresPermission +RequiresPermission: android.os.StrictMode.VmPolicy.Builder#detectFileUriExposure(): + Method 'detectFileUriExposure' documentation mentions permissions without declaring @RequiresPermission +RequiresPermission: android.os.SystemUpdateManager#retrieveSystemUpdateInfo(): + Method 'retrieveSystemUpdateInfo' documentation mentions permissions already declared by @RequiresPermission +RequiresPermission: android.os.SystemUpdateManager#updateSystemUpdateInfo(android.os.PersistableBundle): + Method 'updateSystemUpdateInfo' documentation mentions permissions already declared by @RequiresPermission +RequiresPermission: android.os.UserManager#getUserProperties(android.os.UserHandle): + Method 'getUserProperties' documentation mentions permissions already declared by @RequiresPermission +RequiresPermission: android.os.UserManager#getUserRestrictions(android.os.UserHandle): + Method 'getUserRestrictions' documentation mentions permissions already declared by @RequiresPermission +RequiresPermission: android.os.UserManager#hasUserRestrictionForUser(String, android.os.UserHandle): + Method 'hasUserRestrictionForUser' documentation mentions permissions already declared by @RequiresPermission +RequiresPermission: android.os.UserManager#isManagedProfile(int): + Method 'isManagedProfile' documentation mentions permissions already declared by @RequiresPermission +RequiresPermission: android.os.UserManager#isRestrictedProfile(): + Method 'isRestrictedProfile' documentation mentions permissions without declaring @RequiresPermission +RequiresPermission: android.os.UserManager#isRestrictedProfile(android.os.UserHandle): + Method 'isRestrictedProfile' documentation mentions permissions already declared by @RequiresPermission +RequiresPermission: android.os.UserManager#isUserUnlocked(android.os.UserHandle): + Method 'isUserUnlocked' documentation mentions permissions already declared by @RequiresPermission +RequiresPermission: android.os.UserManager#isUserUnlockingOrUnlocked(android.os.UserHandle): + Method 'isUserUnlockingOrUnlocked' documentation mentions permissions already declared by @RequiresPermission +RequiresPermission: android.os.UserManager#requestQuietModeEnabled(boolean, android.os.UserHandle): + Method 'requestQuietModeEnabled' documentation mentions permissions already declared by @RequiresPermission +RequiresPermission: android.os.UserManager#setUserRestriction(String, boolean): + Method 'setUserRestriction' documentation mentions permissions already declared by @RequiresPermission +RequiresPermission: android.os.health.SystemHealthManager#takeUidSnapshot(int): + Method 'takeUidSnapshot' documentation mentions permissions without declaring @RequiresPermission +RequiresPermission: android.os.health.SystemHealthManager#takeUidSnapshots(int[]): + Method 'takeUidSnapshots' documentation mentions permissions without declaring @RequiresPermission +RequiresPermission: android.os.storage.StorageManager#getCloudMediaProvider(): + Method 'getCloudMediaProvider' documentation mentions permissions without declaring @RequiresPermission +RequiresPermission: android.os.storage.StorageManager#getManageSpaceActivityIntent(String, int): + Method 'getManageSpaceActivityIntent' documentation mentions permissions already declared by @RequiresPermission +RequiresPermission: android.os.storage.StorageManager#notifyAppIoBlocked(java.util.UUID, int, int, int): + Method 'notifyAppIoBlocked' documentation mentions permissions without declaring @RequiresPermission +RequiresPermission: android.os.storage.StorageManager#notifyAppIoResumed(java.util.UUID, int, int, int): + Method 'notifyAppIoResumed' documentation mentions permissions without declaring @RequiresPermission +RequiresPermission: android.os.storage.StorageManager#setCloudMediaProvider(String): + Method 'setCloudMediaProvider' documentation mentions permissions without declaring @RequiresPermission +RequiresPermission: android.os.storage.StorageVolume#createAccessIntent(String): + Method 'createAccessIntent' documentation mentions permissions without declaring @RequiresPermission +RequiresPermission: android.permission.PermissionManager#checkPermissionForDataDelivery(String, android.content.AttributionSource, String): + Method 'checkPermissionForDataDelivery' documentation mentions permissions already declared by @RequiresPermission +RequiresPermission: android.permission.PermissionManager#checkPermissionForDataDeliveryFromDataSource(String, android.content.AttributionSource, String): + Method 'checkPermissionForDataDeliveryFromDataSource' documentation mentions permissions already declared by @RequiresPermission +RequiresPermission: android.permission.PermissionManager#checkPermissionForStartDataDelivery(String, android.content.AttributionSource, String): + Method 'checkPermissionForStartDataDelivery' documentation mentions permissions already declared by @RequiresPermission +RequiresPermission: android.provider.Settings#canDrawOverlays(android.content.Context): + Method 'canDrawOverlays' documentation mentions permissions without declaring @RequiresPermission +RequiresPermission: android.provider.Settings.System#canWrite(android.content.Context): + Method 'canWrite' documentation mentions permissions without declaring @RequiresPermission +RequiresPermission: android.security.KeyChain#removeCredentialManagementApp(android.content.Context): + Method 'removeCredentialManagementApp' documentation mentions permissions already declared by @RequiresPermission +RequiresPermission: android.service.credentials.BeginCreateCredentialResponse.Builder#setRemoteCreateEntry(android.service.credentials.RemoteEntry): + Method 'setRemoteCreateEntry' documentation mentions permissions already declared by @RequiresPermission +RequiresPermission: android.service.credentials.BeginGetCredentialResponse.Builder#setRemoteCredentialEntry(android.service.credentials.RemoteEntry): + Method 'setRemoteCredentialEntry' documentation mentions permissions already declared by @RequiresPermission +RequiresPermission: android.service.credentials.CallingAppInfo#getOrigin(): + Method 'getOrigin' documentation mentions permissions without declaring @RequiresPermission +RequiresPermission: android.telecom.Call.Details#getContactDisplayName(): + Method 'getContactDisplayName' documentation mentions permissions without declaring @RequiresPermission +RequiresPermission: android.telecom.Call.Details#getContactPhotoUri(): + Method 'getContactPhotoUri' documentation mentions permissions without declaring @RequiresPermission +RequiresPermission: android.telecom.TelecomManager#acceptHandover(android.net.Uri, int, android.telecom.PhoneAccountHandle): + Method 'acceptHandover' documentation mentions permissions without declaring @RequiresPermission +RequiresPermission: android.telecom.TelecomManager#addNewIncomingCall(android.telecom.PhoneAccountHandle, android.os.Bundle): + Method 'addNewIncomingCall' documentation mentions permissions without declaring @RequiresPermission +RequiresPermission: android.telecom.TelecomManager#addNewIncomingConference(android.telecom.PhoneAccountHandle, android.os.Bundle): + Method 'addNewIncomingConference' documentation mentions permissions without declaring @RequiresPermission +RequiresPermission: android.telecom.TelecomManager#getCallState(): + Method 'getCallState' documentation mentions permissions already declared by @RequiresPermission +RequiresPermission: android.telecom.TelecomManager#getLine1Number(android.telecom.PhoneAccountHandle): + Method 'getLine1Number' documentation mentions permissions already declared by @RequiresPermission +RequiresPermission: android.telecom.TelecomManager#getOwnSelfManagedPhoneAccounts(): + Method 'getOwnSelfManagedPhoneAccounts' documentation mentions permissions already declared by @RequiresPermission +RequiresPermission: android.telecom.TelecomManager#getPhoneAccount(android.telecom.PhoneAccountHandle): + Method 'getPhoneAccount' documentation mentions permissions without declaring @RequiresPermission +RequiresPermission: android.telecom.TelecomManager#getSelfManagedPhoneAccounts(): + Method 'getSelfManagedPhoneAccounts' documentation mentions permissions already declared by @RequiresPermission +RequiresPermission: android.telecom.TelecomManager#hasManageOngoingCallsPermission(): + Method 'hasManageOngoingCallsPermission' documentation mentions permissions without declaring @RequiresPermission +RequiresPermission: android.telecom.TelecomManager#placeCall(android.net.Uri, android.os.Bundle): + Method 'placeCall' documentation mentions permissions already declared by @RequiresPermission +RequiresPermission: android.telecom.TelecomManager#showInCallScreen(boolean): + Method 'showInCallScreen' documentation mentions permissions already declared by @RequiresPermission +RequiresPermission: android.telecom.TelecomManager#silenceRinger(): + Method 'silenceRinger' documentation mentions permissions already declared by @RequiresPermission +RequiresPermission: android.telephony.CarrierConfigManager#getConfig(): + Method 'getConfig' documentation mentions permissions already declared by @RequiresPermission +RequiresPermission: android.telephony.CarrierConfigManager#getConfig(java.lang.String...): + Method 'getConfig' documentation mentions permissions already declared by @RequiresPermission +RequiresPermission: android.telephony.CarrierConfigManager#getConfigByComponentForSubId(String, int): + Method 'getConfigByComponentForSubId' documentation mentions permissions already declared by @RequiresPermission +RequiresPermission: android.telephony.CarrierConfigManager#getConfigForSubId(int): + Method 'getConfigForSubId' documentation mentions permissions already declared by @RequiresPermission +RequiresPermission: android.telephony.CarrierConfigManager#getConfigForSubId(int, java.lang.String...): + Method 'getConfigForSubId' documentation mentions permissions already declared by @RequiresPermission +RequiresPermission: android.telephony.CarrierConfigManager#notifyConfigChangedForSubId(int): + Method 'notifyConfigChangedForSubId' documentation mentions permissions already declared by @RequiresPermission +RequiresPermission: android.telephony.CellLocation#requestLocationUpdate(): + Method 'requestLocationUpdate' documentation mentions permissions without declaring @RequiresPermission +RequiresPermission: android.telephony.NetworkRegistrationInfo#getCellIdentity(): + Method 'getCellIdentity' documentation mentions permissions without declaring @RequiresPermission +RequiresPermission: android.telephony.PhoneStateListener#onActiveDataSubscriptionIdChanged(int): + Method 'onActiveDataSubscriptionIdChanged' documentation mentions permissions already declared by @RequiresPermission +RequiresPermission: android.telephony.PhoneStateListener#onCallAttributesChanged(android.telephony.CallAttributes): + Method 'onCallAttributesChanged' documentation mentions permissions already declared by @RequiresPermission +RequiresPermission: android.telephony.PhoneStateListener#onCallStateChanged(int, String): + Method 'onCallStateChanged' documentation mentions permissions already declared by @RequiresPermission +RequiresPermission: android.telephony.PhoneStateListener#onDisplayInfoChanged(android.telephony.TelephonyDisplayInfo): + Method 'onDisplayInfoChanged' documentation mentions permissions already declared by @RequiresPermission +RequiresPermission: android.telephony.PhoneStateListener#onPreciseDataConnectionStateChanged(android.telephony.PreciseDataConnectionState): + Method 'onPreciseDataConnectionStateChanged' documentation mentions permissions already declared by @RequiresPermission +RequiresPermission: android.telephony.PhoneStateListener#onRadioPowerStateChanged(int): + Method 'onRadioPowerStateChanged' documentation mentions permissions already declared by @RequiresPermission +RequiresPermission: android.telephony.PhoneStateListener#onServiceStateChanged(android.telephony.ServiceState): + Method 'onServiceStateChanged' documentation mentions permissions without declaring @RequiresPermission +RequiresPermission: android.telephony.ServiceState#getCdmaNetworkId(): + Method 'getCdmaNetworkId' documentation mentions permissions already declared by @RequiresPermission +RequiresPermission: android.telephony.ServiceState#getCdmaSystemId(): + Method 'getCdmaSystemId' documentation mentions permissions already declared by @RequiresPermission +RequiresPermission: android.telephony.ServiceState#getOperatorAlphaLong(): + Method 'getOperatorAlphaLong' documentation mentions permissions already declared by @RequiresPermission +RequiresPermission: android.telephony.ServiceState#getOperatorAlphaShort(): + Method 'getOperatorAlphaShort' documentation mentions permissions already declared by @RequiresPermission +RequiresPermission: android.telephony.ServiceState#getOperatorNumeric(): + Method 'getOperatorNumeric' documentation mentions permissions already declared by @RequiresPermission +RequiresPermission: android.telephony.SignalStrengthUpdateRequest.Builder#setSystemThresholdReportingRequestedWhileIdle(boolean): + Method 'setSystemThresholdReportingRequestedWhileIdle' documentation mentions permissions already declared by @RequiresPermission +RequiresPermission: android.telephony.SmsManager#disableCellBroadcastRange(int, int, int): + Method 'disableCellBroadcastRange' documentation mentions permissions without declaring @RequiresPermission +RequiresPermission: android.telephony.SmsManager#enableCellBroadcastRange(int, int, int): + Method 'enableCellBroadcastRange' documentation mentions permissions without declaring @RequiresPermission +RequiresPermission: android.telephony.SmsManager#getSmscAddress(): + Method 'getSmscAddress' documentation mentions permissions already declared by @RequiresPermission +RequiresPermission: android.telephony.SmsManager#injectSmsPdu(byte[], String, android.app.PendingIntent): + Method 'injectSmsPdu' documentation mentions permissions without declaring @RequiresPermission +RequiresPermission: android.telephony.SmsManager#sendDataMessage(String, String, short, byte[], android.app.PendingIntent, android.app.PendingIntent): + Method 'sendDataMessage' documentation mentions permissions without declaring @RequiresPermission +RequiresPermission: android.telephony.SmsManager#sendMultipartTextMessage(String, String, java.util.ArrayList<java.lang.String>, java.util.ArrayList<android.app.PendingIntent>, java.util.ArrayList<android.app.PendingIntent>): + Method 'sendMultipartTextMessage' documentation mentions permissions without declaring @RequiresPermission +RequiresPermission: android.telephony.SmsManager#sendMultipartTextMessageWithoutPersisting(String, String, java.util.List<java.lang.String>, java.util.List<android.app.PendingIntent>, java.util.List<android.app.PendingIntent>): + Method 'sendMultipartTextMessageWithoutPersisting' documentation mentions permissions already declared by @RequiresPermission +RequiresPermission: android.telephony.SmsManager#sendTextMessage(String, String, String, android.app.PendingIntent, android.app.PendingIntent): + Method 'sendTextMessage' documentation mentions permissions without declaring @RequiresPermission +RequiresPermission: android.telephony.SmsManager#sendTextMessageWithoutPersisting(String, String, String, android.app.PendingIntent, android.app.PendingIntent): + Method 'sendTextMessageWithoutPersisting' documentation mentions permissions already declared by @RequiresPermission +RequiresPermission: android.telephony.SmsManager#setSmscAddress(String): + Method 'setSmscAddress' documentation mentions permissions already declared by @RequiresPermission +RequiresPermission: android.telephony.SubscriptionManager#addSubscriptionsIntoGroup(java.util.List<java.lang.Integer>, android.os.ParcelUuid): + Method 'addSubscriptionsIntoGroup' documentation mentions permissions already declared by @RequiresPermission +RequiresPermission: android.telephony.SubscriptionManager#createSubscriptionGroup(java.util.List<java.lang.Integer>): + Method 'createSubscriptionGroup' documentation mentions permissions already declared by @RequiresPermission +RequiresPermission: android.telephony.SubscriptionManager#getActiveSubscriptionInfo(int): + Method 'getActiveSubscriptionInfo' documentation mentions permissions already declared by @RequiresPermission +RequiresPermission: android.telephony.SubscriptionManager#getActiveSubscriptionInfoForSimSlotIndex(int): + Method 'getActiveSubscriptionInfoForSimSlotIndex' documentation mentions permissions already declared by @RequiresPermission +RequiresPermission: android.telephony.SubscriptionManager#getActiveSubscriptionInfoList(): + Method 'getActiveSubscriptionInfoList' documentation mentions permissions already declared by @RequiresPermission +RequiresPermission: android.telephony.SubscriptionManager#getAvailableSubscriptionInfoList(): + Method 'getAvailableSubscriptionInfoList' documentation mentions permissions without declaring @RequiresPermission +RequiresPermission: android.telephony.SubscriptionManager#getCompleteActiveSubscriptionInfoList(): + Method 'getCompleteActiveSubscriptionInfoList' documentation mentions permissions without declaring @RequiresPermission +RequiresPermission: android.telephony.SubscriptionManager#getOpportunisticSubscriptions(): + Method 'getOpportunisticSubscriptions' documentation mentions permissions already declared by @RequiresPermission +RequiresPermission: android.telephony.SubscriptionManager#getResourcesForSubId(android.content.Context, int): + Method 'getResourcesForSubId' documentation mentions permissions without declaring @RequiresPermission +RequiresPermission: android.telephony.SubscriptionManager#getSubscriptionsInGroup(android.os.ParcelUuid): + Method 'getSubscriptionsInGroup' documentation mentions permissions already declared by @RequiresPermission +RequiresPermission: android.telephony.SubscriptionManager#removeSubscriptionsFromGroup(java.util.List<java.lang.Integer>, android.os.ParcelUuid): + Method 'removeSubscriptionsFromGroup' documentation mentions permissions already declared by @RequiresPermission +RequiresPermission: android.telephony.SubscriptionManager#requestEmbeddedSubscriptionInfoListRefresh(): + Method 'requestEmbeddedSubscriptionInfoListRefresh' documentation mentions permissions without declaring @RequiresPermission +RequiresPermission: android.telephony.SubscriptionManager#requestEmbeddedSubscriptionInfoListRefresh(int): + Method 'requestEmbeddedSubscriptionInfoListRefresh' documentation mentions permissions without declaring @RequiresPermission +RequiresPermission: android.telephony.SubscriptionManager#setOpportunistic(boolean, int): + Method 'setOpportunistic' documentation mentions permissions already declared by @RequiresPermission +RequiresPermission: android.telephony.SubscriptionManager#setPreferredDataSubscriptionId(int, boolean, java.util.concurrent.Executor, java.util.function.Consumer<java.lang.Integer>): + Method 'setPreferredDataSubscriptionId' documentation mentions permissions already declared by @RequiresPermission +RequiresPermission: android.telephony.TelephonyCallback.ActiveDataSubscriptionIdListener#onActiveDataSubscriptionIdChanged(int): + Method 'onActiveDataSubscriptionIdChanged' documentation mentions permissions already declared by @RequiresPermission +RequiresPermission: android.telephony.TelephonyCallback.BarringInfoListener#onBarringInfoChanged(android.telephony.BarringInfo): + Method 'onBarringInfoChanged' documentation mentions permissions already declared by @RequiresPermission +RequiresPermission: android.telephony.TelephonyCallback.CallAttributesListener#onCallAttributesChanged(android.telephony.CallAttributes): + Method 'onCallAttributesChanged' documentation mentions permissions already declared by @RequiresPermission +RequiresPermission: android.telephony.TelephonyCallback.CallAttributesListener#onCallStatesChanged(java.util.List<android.telephony.CallState>): + Method 'onCallStatesChanged' documentation mentions permissions already declared by @RequiresPermission +RequiresPermission: android.telephony.TelephonyCallback.CallForwardingIndicatorListener#onCallForwardingIndicatorChanged(boolean): + Method 'onCallForwardingIndicatorChanged' documentation mentions permissions already declared by @RequiresPermission +RequiresPermission: android.telephony.TelephonyCallback.DataEnabledListener#onDataEnabledChanged(boolean, int): + Method 'onDataEnabledChanged' documentation mentions permissions already declared by @RequiresPermission +RequiresPermission: android.telephony.TelephonyCallback.EmergencyNumberListListener#onEmergencyNumberListChanged(java.util.Map<java.lang.Integer,java.util.List<android.telephony.emergency.EmergencyNumber>>): + Method 'onEmergencyNumberListChanged' documentation mentions permissions already declared by @RequiresPermission +RequiresPermission: android.telephony.TelephonyCallback.ImsCallDisconnectCauseListener#onImsCallDisconnectCauseChanged(android.telephony.ims.ImsReasonInfo): + Method 'onImsCallDisconnectCauseChanged' documentation mentions permissions already declared by @RequiresPermission +RequiresPermission: android.telephony.TelephonyCallback.MessageWaitingIndicatorListener#onMessageWaitingIndicatorChanged(boolean): + Method 'onMessageWaitingIndicatorChanged' documentation mentions permissions already declared by @RequiresPermission +RequiresPermission: android.telephony.TelephonyCallback.PhysicalChannelConfigListener#onPhysicalChannelConfigChanged(java.util.List<android.telephony.PhysicalChannelConfig>): + Method 'onPhysicalChannelConfigChanged' documentation mentions permissions already declared by @RequiresPermission +RequiresPermission: android.telephony.TelephonyCallback.PreciseCallStateListener#onPreciseCallStateChanged(android.telephony.PreciseCallState): + Method 'onPreciseCallStateChanged' documentation mentions permissions already declared by @RequiresPermission +RequiresPermission: android.telephony.TelephonyCallback.PreciseDataConnectionStateListener#onPreciseDataConnectionStateChanged(android.telephony.PreciseDataConnectionState): + Method 'onPreciseDataConnectionStateChanged' documentation mentions permissions already declared by @RequiresPermission +RequiresPermission: android.telephony.TelephonyCallback.RegistrationFailedListener#onRegistrationFailed(android.telephony.CellIdentity, String, int, int, int): + Method 'onRegistrationFailed' documentation mentions permissions already declared by @RequiresPermission +RequiresPermission: android.telephony.TelephonyCallback.ServiceStateListener#onServiceStateChanged(android.telephony.ServiceState): + Method 'onServiceStateChanged' documentation mentions permissions without declaring @RequiresPermission +RequiresPermission: android.telephony.TelephonyManager#bootstrapAuthenticationRequest(int, android.net.Uri, android.telephony.gba.UaSecurityProtocolIdentifier, boolean, java.util.concurrent.Executor, android.telephony.TelephonyManager.BootstrapAuthenticationCallback): + Method 'bootstrapAuthenticationRequest' documentation mentions permissions already declared by @RequiresPermission +RequiresPermission: android.telephony.TelephonyManager#changeIccLockPin(String, String): + Method 'changeIccLockPin' documentation mentions permissions already declared by @RequiresPermission +RequiresPermission: android.telephony.TelephonyManager#clearRadioPowerOffForReason(int): + Method 'clearRadioPowerOffForReason' documentation mentions permissions already declared by @RequiresPermission +RequiresPermission: android.telephony.TelephonyManager#clearSignalStrengthUpdateRequest(android.telephony.SignalStrengthUpdateRequest): + Method 'clearSignalStrengthUpdateRequest' documentation mentions permissions already declared by @RequiresPermission +RequiresPermission: android.telephony.TelephonyManager#doesSwitchMultiSimConfigTriggerReboot(): + Method 'doesSwitchMultiSimConfigTriggerReboot' documentation mentions permissions already declared by @RequiresPermission +RequiresPermission: android.telephony.TelephonyManager#enableModemForSlot(int, boolean): + Method 'enableModemForSlot' documentation mentions permissions already declared by @RequiresPermission +RequiresPermission: android.telephony.TelephonyManager#getAidForAppType(int): + Method 'getAidForAppType' documentation mentions permissions already declared by @RequiresPermission +RequiresPermission: android.telephony.TelephonyManager#getAllowedNetworkTypes(): + Method 'getAllowedNetworkTypes' documentation mentions permissions already declared by @RequiresPermission +RequiresPermission: android.telephony.TelephonyManager#getAllowedNetworkTypesBitmask(): + Method 'getAllowedNetworkTypesBitmask' documentation mentions permissions already declared by @RequiresPermission +RequiresPermission: android.telephony.TelephonyManager#getAllowedNetworkTypesForReason(int): + Method 'getAllowedNetworkTypesForReason' documentation mentions permissions already declared by @RequiresPermission +RequiresPermission: android.telephony.TelephonyManager#getCallState(): + Method 'getCallState' documentation mentions permissions already declared by @RequiresPermission +RequiresPermission: android.telephony.TelephonyManager#getCallStateForSubscription(): + Method 'getCallStateForSubscription' documentation mentions permissions already declared by @RequiresPermission +RequiresPermission: android.telephony.TelephonyManager#getCarrierConfig(): + Method 'getCarrierConfig' documentation mentions permissions already declared by @RequiresPermission +RequiresPermission: android.telephony.TelephonyManager#getCarrierInfoForImsiEncryption(int): + Method 'getCarrierInfoForImsiEncryption' documentation mentions permissions already declared by @RequiresPermission +RequiresPermission: android.telephony.TelephonyManager#getCarrierRestrictionStatus(java.util.concurrent.Executor, java.util.function.Consumer<java.lang.Integer>): + Method 'getCarrierRestrictionStatus' documentation mentions permissions already declared by @RequiresPermission +RequiresPermission: android.telephony.TelephonyManager#getCdmaRoamingMode(): + Method 'getCdmaRoamingMode' documentation mentions permissions already declared by @RequiresPermission +RequiresPermission: android.telephony.TelephonyManager#getCdmaSubscriptionMode(): + Method 'getCdmaSubscriptionMode' documentation mentions permissions already declared by @RequiresPermission +RequiresPermission: android.telephony.TelephonyManager#getDataActivationState(): + Method 'getDataActivationState' documentation mentions permissions already declared by @RequiresPermission +RequiresPermission: android.telephony.TelephonyManager#getDataNetworkType(): + Method 'getDataNetworkType' documentation mentions permissions already declared by @RequiresPermission +RequiresPermission: android.telephony.TelephonyManager#getDeviceId(): + Method 'getDeviceId' documentation mentions permissions already declared by @RequiresPermission +RequiresPermission: android.telephony.TelephonyManager#getDeviceId(int): + Method 'getDeviceId' documentation mentions permissions already declared by @RequiresPermission +RequiresPermission: android.telephony.TelephonyManager#getDeviceSoftwareVersion(int): + Method 'getDeviceSoftwareVersion' documentation mentions permissions already declared by @RequiresPermission +RequiresPermission: android.telephony.TelephonyManager#getEmergencyNumberDbVersion(): + Method 'getEmergencyNumberDbVersion' documentation mentions permissions already declared by @RequiresPermission +RequiresPermission: android.telephony.TelephonyManager#getEmergencyNumberList(): + Method 'getEmergencyNumberList' documentation mentions permissions already declared by @RequiresPermission +RequiresPermission: android.telephony.TelephonyManager#getEmergencyNumberList(int): + Method 'getEmergencyNumberList' documentation mentions permissions already declared by @RequiresPermission +RequiresPermission: android.telephony.TelephonyManager#getEquivalentHomePlmns(): + Method 'getEquivalentHomePlmns' documentation mentions permissions already declared by @RequiresPermission +RequiresPermission: android.telephony.TelephonyManager#getForbiddenPlmns(): + Method 'getForbiddenPlmns' documentation mentions permissions already declared by @RequiresPermission +RequiresPermission: android.telephony.TelephonyManager#getGroupIdLevel1(): + Method 'getGroupIdLevel1' documentation mentions permissions already declared by @RequiresPermission +RequiresPermission: android.telephony.TelephonyManager#getImei(int): + Method 'getImei' documentation mentions permissions already declared by @RequiresPermission +RequiresPermission: android.telephony.TelephonyManager#getIsimDomain(): + Method 'getIsimDomain' documentation mentions permissions already declared by @RequiresPermission +RequiresPermission: android.telephony.TelephonyManager#getLine1Number(): + Method 'getLine1Number' documentation mentions permissions already declared by @RequiresPermission +RequiresPermission: android.telephony.TelephonyManager#getManualNetworkSelectionPlmn(): + Method 'getManualNetworkSelectionPlmn' documentation mentions permissions already declared by @RequiresPermission +RequiresPermission: android.telephony.TelephonyManager#getMeid(): + Method 'getMeid' documentation mentions permissions already declared by @RequiresPermission +RequiresPermission: android.telephony.TelephonyManager#getMeid(int): + Method 'getMeid' documentation mentions permissions already declared by @RequiresPermission +RequiresPermission: android.telephony.TelephonyManager#getNai(): + Method 'getNai' documentation mentions permissions already declared by @RequiresPermission +RequiresPermission: android.telephony.TelephonyManager#getNetworkSelectionMode(): + Method 'getNetworkSelectionMode' documentation mentions permissions already declared by @RequiresPermission +RequiresPermission: android.telephony.TelephonyManager#getNetworkSlicingConfiguration(java.util.concurrent.Executor, android.os.OutcomeReceiver<android.telephony.data.NetworkSlicingConfig,android.telephony.TelephonyManager.NetworkSlicingException>): + Method 'getNetworkSlicingConfiguration' documentation mentions permissions already declared by @RequiresPermission +RequiresPermission: android.telephony.TelephonyManager#getPhoneAccountHandle(): + Method 'getPhoneAccountHandle' documentation mentions permissions already declared by @RequiresPermission +RequiresPermission: android.telephony.TelephonyManager#getPreferredNetworkTypeBitmask(): + Method 'getPreferredNetworkTypeBitmask' documentation mentions permissions already declared by @RequiresPermission +RequiresPermission: android.telephony.TelephonyManager#getPreferredOpportunisticDataSubscription(): + Method 'getPreferredOpportunisticDataSubscription' documentation mentions permissions already declared by @RequiresPermission +RequiresPermission: android.telephony.TelephonyManager#getRadioPowerOffReasons(): + Method 'getRadioPowerOffReasons' documentation mentions permissions already declared by @RequiresPermission +RequiresPermission: android.telephony.TelephonyManager#getRadioPowerState(): + Method 'getRadioPowerState' documentation mentions permissions already declared by @RequiresPermission +RequiresPermission: android.telephony.TelephonyManager#getServiceState(): + Method 'getServiceState' documentation mentions permissions already declared by @RequiresPermission +RequiresPermission: android.telephony.TelephonyManager#getServiceState(int): + Method 'getServiceState' documentation mentions permissions already declared by @RequiresPermission +RequiresPermission: android.telephony.TelephonyManager#getSimLocale(): + Method 'getSimLocale' documentation mentions permissions already declared by @RequiresPermission +RequiresPermission: android.telephony.TelephonyManager#getSimSerialNumber(): + Method 'getSimSerialNumber' documentation mentions permissions already declared by @RequiresPermission +RequiresPermission: android.telephony.TelephonyManager#getSubscriberId(): + Method 'getSubscriberId' documentation mentions permissions already declared by @RequiresPermission +RequiresPermission: android.telephony.TelephonyManager#getSupportedRadioAccessFamily(): + Method 'getSupportedRadioAccessFamily' documentation mentions permissions already declared by @RequiresPermission +RequiresPermission: android.telephony.TelephonyManager#getSystemSelectionChannels(): + Method 'getSystemSelectionChannels' documentation mentions permissions already declared by @RequiresPermission +RequiresPermission: android.telephony.TelephonyManager#getTelephonyHistograms(): + Method 'getTelephonyHistograms' documentation mentions permissions already declared by @RequiresPermission +RequiresPermission: android.telephony.TelephonyManager#getVisualVoicemailPackageName(): + Method 'getVisualVoicemailPackageName' documentation mentions permissions already declared by @RequiresPermission +RequiresPermission: android.telephony.TelephonyManager#getVoiceActivationState(): + Method 'getVoiceActivationState' documentation mentions permissions already declared by @RequiresPermission +RequiresPermission: android.telephony.TelephonyManager#getVoiceMailAlphaTag(): + Method 'getVoiceMailAlphaTag' documentation mentions permissions already declared by @RequiresPermission +RequiresPermission: android.telephony.TelephonyManager#getVoiceMailNumber(): + Method 'getVoiceMailNumber' documentation mentions permissions already declared by @RequiresPermission +RequiresPermission: android.telephony.TelephonyManager#getVoiceNetworkType(): + Method 'getVoiceNetworkType' documentation mentions permissions already declared by @RequiresPermission +RequiresPermission: android.telephony.TelephonyManager#iccCloseLogicalChannel(int): + Method 'iccCloseLogicalChannel' documentation mentions permissions without declaring @RequiresPermission +RequiresPermission: android.telephony.TelephonyManager#iccCloseLogicalChannelBySlot(int, int): + Method 'iccCloseLogicalChannelBySlot' documentation mentions permissions already declared by @RequiresPermission +RequiresPermission: android.telephony.TelephonyManager#iccExchangeSimIO(int, int, int, int, int, String): + Method 'iccExchangeSimIO' documentation mentions permissions without declaring @RequiresPermission +RequiresPermission: android.telephony.TelephonyManager#iccOpenLogicalChannel(String): + Method 'iccOpenLogicalChannel' documentation mentions permissions without declaring @RequiresPermission +RequiresPermission: android.telephony.TelephonyManager#iccOpenLogicalChannel(String, int): + Method 'iccOpenLogicalChannel' documentation mentions permissions without declaring @RequiresPermission +RequiresPermission: android.telephony.TelephonyManager#iccOpenLogicalChannelBySlot(int, String, int): + Method 'iccOpenLogicalChannelBySlot' documentation mentions permissions already declared by @RequiresPermission +RequiresPermission: android.telephony.TelephonyManager#iccTransmitApduBasicChannel(int, int, int, int, int, String): + Method 'iccTransmitApduBasicChannel' documentation mentions permissions without declaring @RequiresPermission +RequiresPermission: android.telephony.TelephonyManager#iccTransmitApduBasicChannelBySlot(int, int, int, int, int, int, String): + Method 'iccTransmitApduBasicChannelBySlot' documentation mentions permissions already declared by @RequiresPermission +RequiresPermission: android.telephony.TelephonyManager#iccTransmitApduLogicalChannel(int, int, int, int, int, int, String): + Method 'iccTransmitApduLogicalChannel' documentation mentions permissions without declaring @RequiresPermission +RequiresPermission: android.telephony.TelephonyManager#iccTransmitApduLogicalChannelBySlot(int, int, int, int, int, int, int, String): + Method 'iccTransmitApduLogicalChannelBySlot' documentation mentions permissions already declared by @RequiresPermission +RequiresPermission: android.telephony.TelephonyManager#isApplicationOnUicc(int): + Method 'isApplicationOnUicc' documentation mentions permissions already declared by @RequiresPermission +RequiresPermission: android.telephony.TelephonyManager#isDataEnabled(): + Method 'isDataEnabled' documentation mentions permissions already declared by @RequiresPermission +RequiresPermission: android.telephony.TelephonyManager#isDataEnabledForReason(int): + Method 'isDataEnabledForReason' documentation mentions permissions already declared by @RequiresPermission +RequiresPermission: android.telephony.TelephonyManager#isDataRoamingEnabled(): + Method 'isDataRoamingEnabled' documentation mentions permissions already declared by @RequiresPermission +RequiresPermission: android.telephony.TelephonyManager#isEmergencyAssistanceEnabled(): + Method 'isEmergencyAssistanceEnabled' documentation mentions permissions already declared by @RequiresPermission +RequiresPermission: android.telephony.TelephonyManager#isIccLockEnabled(): + Method 'isIccLockEnabled' documentation mentions permissions already declared by @RequiresPermission +RequiresPermission: android.telephony.TelephonyManager#isManualNetworkSelectionAllowed(): + Method 'isManualNetworkSelectionAllowed' documentation mentions permissions already declared by @RequiresPermission +RequiresPermission: android.telephony.TelephonyManager#isModemEnabledForSlot(int): + Method 'isModemEnabledForSlot' documentation mentions permissions already declared by @RequiresPermission +RequiresPermission: android.telephony.TelephonyManager#isMultiSimSupported(): + Method 'isMultiSimSupported' documentation mentions permissions already declared by @RequiresPermission +RequiresPermission: android.telephony.TelephonyManager#isOpportunisticNetworkEnabled(): + Method 'isOpportunisticNetworkEnabled' documentation mentions permissions already declared by @RequiresPermission +RequiresPermission: android.telephony.TelephonyManager#isPotentialEmergencyNumber(String): + Method 'isPotentialEmergencyNumber' documentation mentions permissions already declared by @RequiresPermission +RequiresPermission: android.telephony.TelephonyManager#isPremiumCapabilityAvailableForPurchase(int): + Method 'isPremiumCapabilityAvailableForPurchase' documentation mentions permissions already declared by @RequiresPermission +RequiresPermission: android.telephony.TelephonyManager#isTetheringApnRequired(): + Method 'isTetheringApnRequired' documentation mentions permissions already declared by @RequiresPermission +RequiresPermission: android.telephony.TelephonyManager#notifyOtaEmergencyNumberDbInstalled(): + Method 'notifyOtaEmergencyNumberDbInstalled' documentation mentions permissions already declared by @RequiresPermission +RequiresPermission: android.telephony.TelephonyManager#prepareForUnattendedReboot(): + Method 'prepareForUnattendedReboot' documentation mentions permissions already declared by @RequiresPermission +RequiresPermission: android.telephony.TelephonyManager#purchasePremiumCapability(int, java.util.concurrent.Executor, java.util.function.Consumer<java.lang.Integer>): + Method 'purchasePremiumCapability' documentation mentions permissions already declared by @RequiresPermission +RequiresPermission: android.telephony.TelephonyManager#rebootModem(): + Method 'rebootModem' documentation mentions permissions already declared by @RequiresPermission +RequiresPermission: android.telephony.TelephonyManager#rebootRadio(): + Method 'rebootRadio' documentation mentions permissions already declared by @RequiresPermission +RequiresPermission: android.telephony.TelephonyManager#reportDefaultNetworkStatus(boolean): + Method 'reportDefaultNetworkStatus' documentation mentions permissions already declared by @RequiresPermission +RequiresPermission: android.telephony.TelephonyManager#requestNetworkScan(android.telephony.NetworkScanRequest, java.util.concurrent.Executor, android.telephony.TelephonyScanManager.NetworkScanCallback): + Method 'requestNetworkScan' documentation mentions permissions already declared by @RequiresPermission +RequiresPermission: android.telephony.TelephonyManager#requestNetworkScan(int, android.telephony.NetworkScanRequest, java.util.concurrent.Executor, android.telephony.TelephonyScanManager.NetworkScanCallback): + Method 'requestNetworkScan' documentation mentions permissions already declared by @RequiresPermission +RequiresPermission: android.telephony.TelephonyManager#requestNumberVerification(android.telephony.PhoneNumberRange, long, java.util.concurrent.Executor, android.telephony.NumberVerificationCallback): + Method 'requestNumberVerification' documentation mentions permissions already declared by @RequiresPermission +RequiresPermission: android.telephony.TelephonyManager#requestRadioPowerOffForReason(int): + Method 'requestRadioPowerOffForReason' documentation mentions permissions already declared by @RequiresPermission +RequiresPermission: android.telephony.TelephonyManager#resetAllCarrierActions(): + Method 'resetAllCarrierActions' documentation mentions permissions already declared by @RequiresPermission +RequiresPermission: android.telephony.TelephonyManager#resetCarrierKeysForImsiEncryption(): + Method 'resetCarrierKeysForImsiEncryption' documentation mentions permissions already declared by @RequiresPermission +RequiresPermission: android.telephony.TelephonyManager#resetOtaEmergencyNumberDbFilePath(): + Method 'resetOtaEmergencyNumberDbFilePath' documentation mentions permissions already declared by @RequiresPermission +RequiresPermission: android.telephony.TelephonyManager#resetRadioConfig(): + Method 'resetRadioConfig' documentation mentions permissions already declared by @RequiresPermission +RequiresPermission: android.telephony.TelephonyManager#sendEnvelopeWithStatus(String): + Method 'sendEnvelopeWithStatus' documentation mentions permissions without declaring @RequiresPermission +RequiresPermission: android.telephony.TelephonyManager#sendThermalMitigationRequest(android.telephony.ThermalMitigationRequest): + Method 'sendThermalMitigationRequest' documentation mentions permissions already declared by @RequiresPermission +RequiresPermission: android.telephony.TelephonyManager#sendUssdRequest(String, android.telephony.TelephonyManager.UssdResponseCallback, android.os.Handler): + Method 'sendUssdRequest' documentation mentions permissions already declared by @RequiresPermission +RequiresPermission: android.telephony.TelephonyManager#sendVisualVoicemailSms(String, int, String, android.app.PendingIntent): + Method 'sendVisualVoicemailSms' documentation mentions permissions without declaring @RequiresPermission +RequiresPermission: android.telephony.TelephonyManager#setAllowedCarriers(int, java.util.List<android.service.carrier.CarrierIdentifier>): + Method 'setAllowedCarriers' documentation mentions permissions already declared by @RequiresPermission +RequiresPermission: android.telephony.TelephonyManager#setAllowedNetworkTypesForReason(int, long): + Method 'setAllowedNetworkTypesForReason' documentation mentions permissions already declared by @RequiresPermission +RequiresPermission: android.telephony.TelephonyManager#setCarrierDataEnabled(boolean): + Method 'setCarrierDataEnabled' documentation mentions permissions already declared by @RequiresPermission +RequiresPermission: android.telephony.TelephonyManager#setCarrierRestrictionRules(android.telephony.CarrierRestrictionRules): + Method 'setCarrierRestrictionRules' documentation mentions permissions already declared by @RequiresPermission +RequiresPermission: android.telephony.TelephonyManager#setCdmaRoamingMode(int): + Method 'setCdmaRoamingMode' documentation mentions permissions already declared by @RequiresPermission +RequiresPermission: android.telephony.TelephonyManager#setCdmaSubscriptionMode(int): + Method 'setCdmaSubscriptionMode' documentation mentions permissions already declared by @RequiresPermission +RequiresPermission: android.telephony.TelephonyManager#setDataActivationState(int): + Method 'setDataActivationState' documentation mentions permissions already declared by @RequiresPermission +RequiresPermission: android.telephony.TelephonyManager#setDataEnabled(boolean): + Method 'setDataEnabled' documentation mentions permissions already declared by @RequiresPermission +RequiresPermission: android.telephony.TelephonyManager#setDataEnabledForReason(int, boolean): + Method 'setDataEnabledForReason' documentation mentions permissions already declared by @RequiresPermission +RequiresPermission: android.telephony.TelephonyManager#setDataRoamingEnabled(boolean): + Method 'setDataRoamingEnabled' documentation mentions permissions already declared by @RequiresPermission +RequiresPermission: android.telephony.TelephonyManager#setForbiddenPlmns(java.util.List<java.lang.String>): + Method 'setForbiddenPlmns' documentation mentions permissions already declared by @RequiresPermission +RequiresPermission: android.telephony.TelephonyManager#setIccLockEnabled(boolean, String): + Method 'setIccLockEnabled' documentation mentions permissions already declared by @RequiresPermission +RequiresPermission: android.telephony.TelephonyManager#setNetworkSelectionModeAutomatic(): + Method 'setNetworkSelectionModeAutomatic' documentation mentions permissions already declared by @RequiresPermission +RequiresPermission: android.telephony.TelephonyManager#setNetworkSelectionModeManual(String, boolean): + Method 'setNetworkSelectionModeManual' documentation mentions permissions already declared by @RequiresPermission +RequiresPermission: android.telephony.TelephonyManager#setNetworkSelectionModeManual(String, boolean, int): + Method 'setNetworkSelectionModeManual' documentation mentions permissions already declared by @RequiresPermission +RequiresPermission: android.telephony.TelephonyManager#setOpportunisticNetworkState(boolean): + Method 'setOpportunisticNetworkState' documentation mentions permissions already declared by @RequiresPermission +RequiresPermission: android.telephony.TelephonyManager#setPreferredNetworkTypeBitmask(long): + Method 'setPreferredNetworkTypeBitmask' documentation mentions permissions already declared by @RequiresPermission +RequiresPermission: android.telephony.TelephonyManager#setPreferredOpportunisticDataSubscription(int, boolean, java.util.concurrent.Executor, java.util.function.Consumer<java.lang.Integer>): + Method 'setPreferredOpportunisticDataSubscription' documentation mentions permissions without declaring @RequiresPermission +RequiresPermission: android.telephony.TelephonyManager#setRadioEnabled(boolean): + Method 'setRadioEnabled' documentation mentions permissions already declared by @RequiresPermission +RequiresPermission: android.telephony.TelephonyManager#setSignalStrengthUpdateRequest(android.telephony.SignalStrengthUpdateRequest): + Method 'setSignalStrengthUpdateRequest' documentation mentions permissions already declared by @RequiresPermission +RequiresPermission: android.telephony.TelephonyManager#setSimPowerState(int): + Method 'setSimPowerState' documentation mentions permissions already declared by @RequiresPermission +RequiresPermission: android.telephony.TelephonyManager#setSimPowerState(int, java.util.concurrent.Executor, java.util.function.Consumer<java.lang.Integer>): + Method 'setSimPowerState' documentation mentions permissions already declared by @RequiresPermission +RequiresPermission: android.telephony.TelephonyManager#setSimPowerStateForSlot(int, int): + Method 'setSimPowerStateForSlot' documentation mentions permissions already declared by @RequiresPermission +RequiresPermission: android.telephony.TelephonyManager#setSimPowerStateForSlot(int, int, java.util.concurrent.Executor, java.util.function.Consumer<java.lang.Integer>): + Method 'setSimPowerStateForSlot' documentation mentions permissions already declared by @RequiresPermission +RequiresPermission: android.telephony.TelephonyManager#setVoiceActivationState(int): + Method 'setVoiceActivationState' documentation mentions permissions already declared by @RequiresPermission +RequiresPermission: android.telephony.TelephonyManager#setVoicemailRingtoneUri(android.telecom.PhoneAccountHandle, android.net.Uri): + Method 'setVoicemailRingtoneUri' documentation mentions permissions without declaring @RequiresPermission +RequiresPermission: android.telephony.TelephonyManager#setVoicemailVibrationEnabled(android.telecom.PhoneAccountHandle, boolean): + Method 'setVoicemailVibrationEnabled' documentation mentions permissions without declaring @RequiresPermission +RequiresPermission: android.telephony.TelephonyManager#supplyIccLockPin(String): + Method 'supplyIccLockPin' documentation mentions permissions already declared by @RequiresPermission +RequiresPermission: android.telephony.TelephonyManager#supplyIccLockPuk(String, String): + Method 'supplyIccLockPuk' documentation mentions permissions already declared by @RequiresPermission +RequiresPermission: android.telephony.TelephonyManager#switchMultiSimConfig(int): + Method 'switchMultiSimConfig' documentation mentions permissions already declared by @RequiresPermission +RequiresPermission: android.telephony.TelephonyManager#updateAvailableNetworks(java.util.List<android.telephony.AvailableNetworkInfo>, java.util.concurrent.Executor, java.util.function.Consumer<java.lang.Integer>): + Method 'updateAvailableNetworks' documentation mentions permissions without declaring @RequiresPermission +RequiresPermission: android.telephony.TelephonyManager#updateOtaEmergencyNumberDbFilePath(android.os.ParcelFileDescriptor): + Method 'updateOtaEmergencyNumberDbFilePath' documentation mentions permissions already declared by @RequiresPermission +RequiresPermission: android.telephony.VisualVoicemailService#sendVisualVoicemailSms(android.content.Context, android.telecom.PhoneAccountHandle, String, short, String, android.app.PendingIntent): + Method 'sendVisualVoicemailSms' documentation mentions permissions without declaring @RequiresPermission +RequiresPermission: android.telephony.VisualVoicemailService#setSmsFilterSettings(android.content.Context, android.telecom.PhoneAccountHandle, android.telephony.VisualVoicemailSmsFilterSettings): + Method 'setSmsFilterSettings' documentation mentions permissions without declaring @RequiresPermission +RequiresPermission: android.telephony.euicc.EuiccManager#continueOperation(android.content.Intent, android.os.Bundle): + Method 'continueOperation' documentation mentions permissions already declared by @RequiresPermission +RequiresPermission: android.telephony.euicc.EuiccManager#deleteSubscription(int, android.app.PendingIntent): + Method 'deleteSubscription' documentation mentions permissions already declared by @RequiresPermission +RequiresPermission: android.telephony.euicc.EuiccManager#downloadSubscription(android.telephony.euicc.DownloadableSubscription, boolean, android.app.PendingIntent): + Method 'downloadSubscription' documentation mentions permissions already declared by @RequiresPermission +RequiresPermission: android.telephony.euicc.EuiccManager#eraseSubscriptions(android.app.PendingIntent): + Method 'eraseSubscriptions' documentation mentions permissions already declared by @RequiresPermission +RequiresPermission: android.telephony.euicc.EuiccManager#eraseSubscriptions(int, android.app.PendingIntent): + Method 'eraseSubscriptions' documentation mentions permissions already declared by @RequiresPermission +RequiresPermission: android.telephony.euicc.EuiccManager#getDefaultDownloadableSubscriptionList(android.app.PendingIntent): + Method 'getDefaultDownloadableSubscriptionList' documentation mentions permissions already declared by @RequiresPermission +RequiresPermission: android.telephony.euicc.EuiccManager#getDownloadableSubscriptionMetadata(android.telephony.euicc.DownloadableSubscription, android.app.PendingIntent): + Method 'getDownloadableSubscriptionMetadata' documentation mentions permissions already declared by @RequiresPermission +RequiresPermission: android.telephony.euicc.EuiccManager#getOtaStatus(): + Method 'getOtaStatus' documentation mentions permissions already declared by @RequiresPermission +RequiresPermission: android.telephony.euicc.EuiccManager#getSupportedCountries(): + Method 'getSupportedCountries' documentation mentions permissions already declared by @RequiresPermission +RequiresPermission: android.telephony.euicc.EuiccManager#getUnsupportedCountries(): + Method 'getUnsupportedCountries' documentation mentions permissions already declared by @RequiresPermission +RequiresPermission: android.telephony.euicc.EuiccManager#setSupportedCountries(java.util.List<java.lang.String>): + Method 'setSupportedCountries' documentation mentions permissions already declared by @RequiresPermission +RequiresPermission: android.telephony.euicc.EuiccManager#setUnsupportedCountries(java.util.List<java.lang.String>): + Method 'setUnsupportedCountries' documentation mentions permissions already declared by @RequiresPermission +RequiresPermission: android.telephony.euicc.EuiccManager#switchToSubscription(int, android.app.PendingIntent): + Method 'switchToSubscription' documentation mentions permissions already declared by @RequiresPermission +RequiresPermission: android.telephony.euicc.EuiccManager#switchToSubscription(int, int, android.app.PendingIntent): + Method 'switchToSubscription' documentation mentions permissions already declared by @RequiresPermission +RequiresPermission: android.telephony.euicc.EuiccManager#updateSubscriptionNickname(int, String, android.app.PendingIntent): + Method 'updateSubscriptionNickname' documentation mentions permissions already declared by @RequiresPermission +RequiresPermission: android.telephony.ims.ImsMmTelManager#createForSubscriptionId(int): + Method 'createForSubscriptionId' documentation mentions permissions already declared by @RequiresPermission +RequiresPermission: android.telephony.ims.ImsMmTelManager#getRegistrationTransportType(java.util.concurrent.Executor, java.util.function.Consumer<java.lang.Integer>): + Method 'getRegistrationTransportType' documentation mentions permissions already declared by @RequiresPermission +RequiresPermission: android.telephony.ims.ImsMmTelManager#getVoWiFiModeSetting(): + Method 'getVoWiFiModeSetting' documentation mentions permissions already declared by @RequiresPermission +RequiresPermission: android.telephony.ims.ImsMmTelManager#isAdvancedCallingSettingEnabled(): + Method 'isAdvancedCallingSettingEnabled' documentation mentions permissions already declared by @RequiresPermission +RequiresPermission: android.telephony.ims.ImsMmTelManager#isCrossSimCallingEnabled(): + Method 'isCrossSimCallingEnabled' documentation mentions permissions already declared by @RequiresPermission +RequiresPermission: android.telephony.ims.ImsMmTelManager#isTtyOverVolteEnabled(): + Method 'isTtyOverVolteEnabled' documentation mentions permissions already declared by @RequiresPermission +RequiresPermission: android.telephony.ims.ImsMmTelManager#isVoWiFiRoamingSettingEnabled(): + Method 'isVoWiFiRoamingSettingEnabled' documentation mentions permissions already declared by @RequiresPermission +RequiresPermission: android.telephony.ims.ImsMmTelManager#isVoWiFiSettingEnabled(): + Method 'isVoWiFiSettingEnabled' documentation mentions permissions already declared by @RequiresPermission +RequiresPermission: android.telephony.ims.ImsMmTelManager#isVtSettingEnabled(): + Method 'isVtSettingEnabled' documentation mentions permissions already declared by @RequiresPermission +RequiresPermission: android.telephony.ims.ImsMmTelManager#registerImsRegistrationCallback(java.util.concurrent.Executor, android.telephony.ims.RegistrationManager.RegistrationCallback): + Method 'registerImsRegistrationCallback' documentation mentions permissions already declared by @RequiresPermission +RequiresPermission: android.telephony.ims.ImsMmTelManager#registerImsStateCallback(java.util.concurrent.Executor, android.telephony.ims.ImsStateCallback): + Method 'registerImsStateCallback' documentation mentions permissions already declared by @RequiresPermission +RequiresPermission: android.telephony.ims.ImsMmTelManager#registerMmTelCapabilityCallback(java.util.concurrent.Executor, android.telephony.ims.ImsMmTelManager.CapabilityCallback): + Method 'registerMmTelCapabilityCallback' documentation mentions permissions already declared by @RequiresPermission +RequiresPermission: android.telephony.ims.ImsMmTelManager#unregisterImsRegistrationCallback(android.telephony.ims.RegistrationManager.RegistrationCallback): + Method 'unregisterImsRegistrationCallback' documentation mentions permissions already declared by @RequiresPermission +RequiresPermission: android.telephony.ims.ImsMmTelManager#unregisterMmTelCapabilityCallback(android.telephony.ims.ImsMmTelManager.CapabilityCallback): + Method 'unregisterMmTelCapabilityCallback' documentation mentions permissions already declared by @RequiresPermission +RequiresPermission: android.telephony.ims.ImsRcsManager#getRegistrationState(java.util.concurrent.Executor, java.util.function.Consumer<java.lang.Integer>): + Method 'getRegistrationState' documentation mentions permissions already declared by @RequiresPermission +RequiresPermission: android.telephony.ims.ImsRcsManager#getRegistrationTransportType(java.util.concurrent.Executor, java.util.function.Consumer<java.lang.Integer>): + Method 'getRegistrationTransportType' documentation mentions permissions already declared by @RequiresPermission +RequiresPermission: android.telephony.ims.ImsRcsManager#registerImsRegistrationCallback(java.util.concurrent.Executor, android.telephony.ims.RegistrationManager.RegistrationCallback): + Method 'registerImsRegistrationCallback' documentation mentions permissions already declared by @RequiresPermission +RequiresPermission: android.telephony.ims.ImsRcsManager#registerImsStateCallback(java.util.concurrent.Executor, android.telephony.ims.ImsStateCallback): + Method 'registerImsStateCallback' documentation mentions permissions already declared by @RequiresPermission +RequiresPermission: android.telephony.ims.ImsRcsManager#unregisterImsRegistrationCallback(android.telephony.ims.RegistrationManager.RegistrationCallback): + Method 'unregisterImsRegistrationCallback' documentation mentions permissions already declared by @RequiresPermission +RequiresPermission: android.telephony.ims.ProvisioningManager#getProvisioningStatusForCapability(int, int): + Method 'getProvisioningStatusForCapability' documentation mentions permissions already declared by @RequiresPermission +RequiresPermission: android.telephony.ims.ProvisioningManager#getRcsProvisioningStatusForCapability(int, int): + Method 'getRcsProvisioningStatusForCapability' documentation mentions permissions already declared by @RequiresPermission +RequiresPermission: android.telephony.ims.ProvisioningManager#isProvisioningRequiredForCapability(int, int): + Method 'isProvisioningRequiredForCapability' documentation mentions permissions already declared by @RequiresPermission +RequiresPermission: android.telephony.ims.ProvisioningManager#isRcsProvisioningRequiredForCapability(int, int): + Method 'isRcsProvisioningRequiredForCapability' documentation mentions permissions already declared by @RequiresPermission +RequiresPermission: android.telephony.ims.ProvisioningManager#isRcsVolteSingleRegistrationCapable(): + Method 'isRcsVolteSingleRegistrationCapable' documentation mentions permissions already declared by @RequiresPermission +RequiresPermission: android.telephony.ims.ProvisioningManager#notifyRcsAutoConfigurationReceived(byte[], boolean): + Method 'notifyRcsAutoConfigurationReceived' documentation mentions permissions already declared by @RequiresPermission +RequiresPermission: android.telephony.ims.ProvisioningManager#registerFeatureProvisioningChangedCallback(java.util.concurrent.Executor, android.telephony.ims.ProvisioningManager.FeatureProvisioningCallback): + Method 'registerFeatureProvisioningChangedCallback' documentation mentions permissions already declared by @RequiresPermission +RequiresPermission: android.telephony.ims.ProvisioningManager#registerProvisioningChangedCallback(java.util.concurrent.Executor, android.telephony.ims.ProvisioningManager.Callback): + Method 'registerProvisioningChangedCallback' documentation mentions permissions already declared by @RequiresPermission +RequiresPermission: android.telephony.ims.ProvisioningManager#registerRcsProvisioningCallback(java.util.concurrent.Executor, android.telephony.ims.ProvisioningManager.RcsProvisioningCallback): + Method 'registerRcsProvisioningCallback' documentation mentions permissions already declared by @RequiresPermission +RequiresPermission: android.telephony.ims.ProvisioningManager#setProvisioningStatusForCapability(int, int, boolean): + Method 'setProvisioningStatusForCapability' documentation mentions permissions already declared by @RequiresPermission +RequiresPermission: android.telephony.ims.ProvisioningManager#setRcsProvisioningStatusForCapability(int, boolean): + Method 'setRcsProvisioningStatusForCapability' documentation mentions permissions already declared by @RequiresPermission +RequiresPermission: android.telephony.ims.ProvisioningManager#setRcsProvisioningStatusForCapability(int, int, boolean): + Method 'setRcsProvisioningStatusForCapability' documentation mentions permissions already declared by @RequiresPermission +RequiresPermission: android.telephony.ims.ProvisioningManager#unregisterProvisioningChangedCallback(android.telephony.ims.ProvisioningManager.Callback): + Method 'unregisterProvisioningChangedCallback' documentation mentions permissions already declared by @RequiresPermission +RequiresPermission: android.telephony.ims.ProvisioningManager#unregisterRcsProvisioningCallback(android.telephony.ims.ProvisioningManager.RcsProvisioningCallback): + Method 'unregisterRcsProvisioningCallback' documentation mentions permissions already declared by @RequiresPermission +RequiresPermission: android.telephony.ims.SipDelegateManager#registerSipDialogStateCallback(java.util.concurrent.Executor, android.telephony.ims.SipDialogStateCallback): + Method 'registerSipDialogStateCallback' documentation mentions permissions already declared by @RequiresPermission +RequiresPermission: android.telephony.ims.SipDelegateManager#unregisterSipDialogStateCallback(android.telephony.ims.SipDialogStateCallback): + Method 'unregisterSipDialogStateCallback' documentation mentions permissions already declared by @RequiresPermission +RequiresPermission: android.view.WindowManager.LayoutParams#isSystemApplicationOverlay(): + Method 'isSystemApplicationOverlay' documentation mentions permissions without declaring @RequiresPermission +RequiresPermission: android.view.accessibility.AccessibilityManager#registerDisplayProxy(android.view.accessibility.AccessibilityDisplayProxy): + Method 'registerDisplayProxy' documentation mentions permissions already declared by @RequiresPermission +RequiresPermission: android.view.accessibility.AccessibilityManager#unregisterDisplayProxy(android.view.accessibility.AccessibilityDisplayProxy): + Method 'unregisterDisplayProxy' documentation mentions permissions already declared by @RequiresPermission +RequiresPermission: android.view.accessibility.CaptioningManager#setSystemAudioCaptioningEnabled(boolean): + Method 'setSystemAudioCaptioningEnabled' documentation mentions permissions already declared by @RequiresPermission +RequiresPermission: android.view.accessibility.CaptioningManager#setSystemAudioCaptioningUiEnabled(boolean): + Method 'setSystemAudioCaptioningUiEnabled' documentation mentions permissions already declared by @RequiresPermission +RequiresPermission: android.view.inputmethod.InputMethodManager#setCurrentInputMethodSubtype(android.view.inputmethod.InputMethodSubtype): + Method 'setCurrentInputMethodSubtype' documentation mentions permissions already declared by @RequiresPermission +RequiresPermission: android.webkit.WebSettings#setBlockNetworkLoads(boolean): + Method 'setBlockNetworkLoads' documentation mentions permissions without declaring @RequiresPermission +RequiresPermission: android.webkit.WebSettings#setGeolocationEnabled(boolean): + Method 'setGeolocationEnabled' documentation mentions permissions without declaring @RequiresPermission + + SamShouldBeLast: android.app.Activity#convertToTranslucent(android.app.Activity.TranslucentConversionListener, android.app.ActivityOptions): SAM-compatible parameters (such as parameter 1, "callback", in android.app.Activity.convertToTranslucent) should be last to improve Kotlin interoperability; see https://kotlinlang.org/docs/reference/java-interop.html#sam-conversions SamShouldBeLast: android.app.ActivityManager#addOnUidImportanceListener(android.app.ActivityManager.OnUidImportanceListener, int): @@ -37,6 +1747,80 @@ SamShouldBeLast: android.media.session.MediaSessionManager#setOnVolumeKeyLongPre SAM-compatible parameters (such as parameter 1, "listener", in android.media.session.MediaSessionManager.setOnVolumeKeyLongPressListener) should be last to improve Kotlin interoperability; see https://kotlinlang.org/docs/reference/java-interop.html#sam-conversions +SdkConstant: android.content.Intent#ACTION_BATTERY_LEVEL_CHANGED: + Field 'ACTION_BATTERY_LEVEL_CHANGED' is missing @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION) +SdkConstant: android.content.Intent#ACTION_DEVICE_CUSTOMIZATION_READY: + Field 'ACTION_DEVICE_CUSTOMIZATION_READY' is missing @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION) +SdkConstant: android.content.Intent#ACTION_GLOBAL_BUTTON: + Field 'ACTION_GLOBAL_BUTTON' is missing @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION) +SdkConstant: android.content.Intent#ACTION_PRE_BOOT_COMPLETED: + Field 'ACTION_PRE_BOOT_COMPLETED' is missing @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION) +SdkConstant: android.content.Intent#ACTION_UNARCHIVE_PACKAGE: + Field 'ACTION_UNARCHIVE_PACKAGE' is missing @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION) +SdkConstant: android.content.pm.PackageInstaller#ACTION_CONFIRM_PRE_APPROVAL: + Field 'ACTION_CONFIRM_PRE_APPROVAL' is missing @SdkConstant(SdkConstantType.ACTIVITY_INTENT_ACTION) +SdkConstant: android.hardware.usb.UsbManager#ACTION_USB_PORT_CHANGED: + Field 'ACTION_USB_PORT_CHANGED' is missing @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION) +SdkConstant: android.hardware.usb.UsbManager#ACTION_USB_PORT_COMPLIANCE_CHANGED: + Field 'ACTION_USB_PORT_COMPLIANCE_CHANGED' is missing @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION) +SdkConstant: android.hardware.usb.UsbManager#ACTION_USB_STATE: + Field 'ACTION_USB_STATE' is missing @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION) +SdkConstant: android.nfc.NfcAdapter#ACTION_REQUIRE_UNLOCK_FOR_NFC: + Field 'ACTION_REQUIRE_UNLOCK_FOR_NFC' is missing @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION) +SdkConstant: android.service.euicc.EuiccService#ACTION_DELETE_SUBSCRIPTION_PRIVILEGED: + Field 'ACTION_DELETE_SUBSCRIPTION_PRIVILEGED' is missing @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION) +SdkConstant: android.service.euicc.EuiccService#ACTION_RENAME_SUBSCRIPTION_PRIVILEGED: + Field 'ACTION_RENAME_SUBSCRIPTION_PRIVILEGED' is missing @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION) +SdkConstant: android.service.euicc.EuiccService#ACTION_TOGGLE_SUBSCRIPTION_PRIVILEGED: + Field 'ACTION_TOGGLE_SUBSCRIPTION_PRIVILEGED' is missing @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION) +SdkConstant: android.telephony.TelephonyManager#ACTION_DEFAULT_DATA_SUBSCRIPTION_CHANGED: + Field 'ACTION_DEFAULT_DATA_SUBSCRIPTION_CHANGED' is missing @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION) +SdkConstant: android.telephony.TelephonyManager#ACTION_DEFAULT_VOICE_SUBSCRIPTION_CHANGED: + Field 'ACTION_DEFAULT_VOICE_SUBSCRIPTION_CHANGED' is missing @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION) +SdkConstant: android.telephony.TelephonyManager#ACTION_REQUEST_OMADM_CONFIGURATION_UPDATE: + Field 'ACTION_REQUEST_OMADM_CONFIGURATION_UPDATE' is missing @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION) +SdkConstant: android.telephony.TelephonyManager#ACTION_SHOW_NOTICE_ECM_BLOCK_OTHERS: + Field 'ACTION_SHOW_NOTICE_ECM_BLOCK_OTHERS' is missing @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION) + + +Todo: android.Manifest.permission#DOMAIN_VERIFICATION_AGENT: + Documentation mentions 'TODO' +Todo: android.Manifest.permission#INSTALL_EXISTING_PACKAGES: + Documentation mentions 'TODO' +Todo: android.Manifest.permission#READ_PEOPLE_DATA: + Documentation mentions 'TODO' +Todo: android.app.NotificationManager#isNotificationAssistantAccessGranted(android.content.ComponentName): + Documentation mentions 'TODO' +Todo: android.hardware.camera2.params.StreamConfigurationMap: + Documentation mentions 'TODO' +Todo: android.hardware.location.ContextHubManager#getNanoAppInstanceInfo(int): + Documentation mentions 'TODO' +Todo: android.hardware.location.ContextHubManager#loadNanoApp(int, android.hardware.location.NanoApp): + Documentation mentions 'TODO' +Todo: android.hardware.location.ContextHubManager#unloadNanoApp(int): + Documentation mentions 'TODO' +Todo: android.hardware.location.NanoAppInstanceInfo: + Documentation mentions 'TODO' +Todo: android.media.tv.TvContentRatingSystemInfo#getXmlUri(): + Documentation mentions 'TODO' +Todo: android.media.tv.TvInputInfo#isConnectedToHdmiSwitch(): + Documentation mentions 'TODO' +Todo: android.os.RecoverySystem#prepareForUnattendedUpdate(android.content.Context, String, android.content.IntentSender): + Documentation mentions 'TODO' +Todo: android.os.RecoverySystem#rebootAndApply(android.content.Context, String, String): + Documentation mentions 'TODO' +Todo: android.os.SystemConfigManager: + Documentation mentions 'TODO' +Todo: android.os.UpdateEngineCallback#onStatusUpdate(int, float): + Documentation mentions 'TODO' +Todo: android.provider.ContactsContract.RawContacts#newEntityIterator(android.database.Cursor): + Documentation mentions 'TODO' +Todo: android.service.voice.AlwaysOnHotwordDetector: + Documentation mentions 'TODO' +Todo: android.telephony.TelephonyManager#getCurrentPhoneType(): + Documentation mentions 'TODO' + + UnflaggedApi: android.Manifest.permission#MANAGE_REMOTE_AUTH: New API must be flagged with @FlaggedApi: field android.Manifest.permission.MANAGE_REMOTE_AUTH UnflaggedApi: android.Manifest.permission#USE_COMPANION_TRANSPORTS: diff --git a/core/api/system-current.txt b/core/api/system-current.txt index 5bce8b291402..79cd373e0aef 100644 --- a/core/api/system-current.txt +++ b/core/api/system-current.txt @@ -37,7 +37,7 @@ package android { field public static final String ALLOW_ANY_CODEC_FOR_PLAYBACK = "android.permission.ALLOW_ANY_CODEC_FOR_PLAYBACK"; field public static final String ALLOW_PLACE_IN_MULTI_PANE_SETTINGS = "android.permission.ALLOW_PLACE_IN_MULTI_PANE_SETTINGS"; field public static final String ALLOW_SLIPPERY_TOUCHES = "android.permission.ALLOW_SLIPPERY_TOUCHES"; - field public static final String ALWAYS_UPDATE_WALLPAPER = "android.permission.ALWAYS_UPDATE_WALLPAPER"; + field @FlaggedApi("com.android.window.flags.always_update_wallpaper_permission") public static final String ALWAYS_UPDATE_WALLPAPER = "android.permission.ALWAYS_UPDATE_WALLPAPER"; field public static final String AMBIENT_WALLPAPER = "android.permission.AMBIENT_WALLPAPER"; field public static final String APPROVE_INCIDENT_REPORTS = "android.permission.APPROVE_INCIDENT_REPORTS"; field public static final String ASSOCIATE_COMPANION_DEVICES = "android.permission.ASSOCIATE_COMPANION_DEVICES"; @@ -627,6 +627,7 @@ package android.app { field public static final String OPSTR_BIND_ACCESSIBILITY_SERVICE = "android:bind_accessibility_service"; field public static final String OPSTR_CAPTURE_CONSENTLESS_BUGREPORT_ON_USERDEBUG_BUILD = "android:capture_consentless_bugreport_on_userdebug_build"; field public static final String OPSTR_CHANGE_WIFI_STATE = "android:change_wifi_state"; + field @FlaggedApi("android.view.contentprotection.flags.create_accessibility_overlay_app_op_enabled") public static final String OPSTR_CREATE_ACCESSIBILITY_OVERLAY = "android:create_accessibility_overlay"; field public static final String OPSTR_ESTABLISH_VPN_MANAGER = "android:establish_vpn_manager"; field public static final String OPSTR_ESTABLISH_VPN_SERVICE = "android:establish_vpn_service"; field public static final String OPSTR_GET_ACCOUNTS = "android:get_accounts"; @@ -980,7 +981,7 @@ package android.app { field public static final int SEMANTIC_ACTION_MARK_CONVERSATION_AS_PRIORITY = 11; // 0xb } - public static final class Notification.TvExtender implements android.app.Notification.Extender { + @FlaggedApi("android.app.api_tvextender") public static final class Notification.TvExtender implements android.app.Notification.Extender { method public boolean getSuppressShowOverApps(); method public android.app.Notification.TvExtender setChannel(String); } @@ -3252,6 +3253,7 @@ package android.companion.virtual { field @Deprecated public static final int NAVIGATION_POLICY_DEFAULT_BLOCKED = 1; // 0x1 field @FlaggedApi("android.companion.virtual.flags.dynamic_policy") public static final int POLICY_TYPE_ACTIVITY = 3; // 0x3 field public static final int POLICY_TYPE_AUDIO = 1; // 0x1 + field @FlaggedApi("android.companion.virtual.flags.cross_device_clipboard") public static final int POLICY_TYPE_CLIPBOARD = 4; // 0x4 field public static final int POLICY_TYPE_RECENTS = 2; // 0x2 field public static final int POLICY_TYPE_SENSORS = 0; // 0x0 } @@ -3914,6 +3916,7 @@ package android.content.pm { method @RequiresPermission(android.Manifest.permission.GRANT_RUNTIME_PERMISSIONS) public abstract void grantRuntimePermission(@NonNull String, @NonNull String, @NonNull android.os.UserHandle); method @Deprecated public abstract int installExistingPackage(@NonNull String) throws android.content.pm.PackageManager.NameNotFoundException; method @Deprecated public abstract int installExistingPackage(@NonNull String, int) throws android.content.pm.PackageManager.NameNotFoundException; + method @FlaggedApi("android.content.pm.archiving") public boolean isAppArchivable(@NonNull String) throws android.content.pm.PackageManager.NameNotFoundException; method @NonNull @RequiresPermission(android.Manifest.permission.INTERACT_ACROSS_USERS) public java.util.List<android.content.pm.ResolveInfo> queryBroadcastReceiversAsUser(@NonNull android.content.Intent, int, android.os.UserHandle); method @NonNull @RequiresPermission(android.Manifest.permission.INTERACT_ACROSS_USERS) public java.util.List<android.content.pm.ResolveInfo> queryBroadcastReceiversAsUser(@NonNull android.content.Intent, @NonNull android.content.pm.PackageManager.ResolveInfoFlags, @NonNull android.os.UserHandle); method @NonNull @RequiresPermission(android.Manifest.permission.INTERACT_ACROSS_USERS) public java.util.List<android.content.pm.ResolveInfo> queryIntentActivitiesAsUser(@NonNull android.content.Intent, int, @NonNull android.os.UserHandle); diff --git a/core/api/system-lint-baseline.txt b/core/api/system-lint-baseline.txt index a5010312e764..865240207a95 100644 --- a/core/api/system-lint-baseline.txt +++ b/core/api/system-lint-baseline.txt @@ -3,6 +3,512 @@ ArrayReturn: android.view.contentcapture.ViewNode#getAutofillOptions(): Method should return Collection<CharSequence> (or subclass) instead of raw array; was `java.lang.CharSequence[]` +BroadcastBehavior: android.app.AlarmManager#ACTION_NEXT_ALARM_CLOCK_CHANGED: + Field 'ACTION_NEXT_ALARM_CLOCK_CHANGED' is missing @BroadcastBehavior +BroadcastBehavior: android.app.AlarmManager#ACTION_SCHEDULE_EXACT_ALARM_PERMISSION_STATE_CHANGED: + Field 'ACTION_SCHEDULE_EXACT_ALARM_PERMISSION_STATE_CHANGED' is missing @BroadcastBehavior +BroadcastBehavior: android.app.NotificationManager#ACTION_CLOSE_NOTIFICATION_HANDLER_PANEL: + Field 'ACTION_CLOSE_NOTIFICATION_HANDLER_PANEL' is missing @BroadcastBehavior +BroadcastBehavior: android.app.admin.DevicePolicyManager#ACTION_APPLICATION_DELEGATION_SCOPES_CHANGED: + Field 'ACTION_APPLICATION_DELEGATION_SCOPES_CHANGED' is missing @BroadcastBehavior +BroadcastBehavior: android.app.admin.DevicePolicyManager#ACTION_MANAGED_PROFILE_PROVISIONED: + Field 'ACTION_MANAGED_PROFILE_PROVISIONED' is missing @BroadcastBehavior +BroadcastBehavior: android.content.Intent#ACTION_AIRPLANE_MODE_CHANGED: + Field 'ACTION_AIRPLANE_MODE_CHANGED' is missing @BroadcastBehavior +BroadcastBehavior: android.content.Intent#ACTION_APPLICATION_LOCALE_CHANGED: + Field 'ACTION_APPLICATION_LOCALE_CHANGED' is missing @BroadcastBehavior +BroadcastBehavior: android.content.Intent#ACTION_APPLICATION_RESTRICTIONS_CHANGED: + Field 'ACTION_APPLICATION_RESTRICTIONS_CHANGED' is missing @BroadcastBehavior +BroadcastBehavior: android.content.Intent#ACTION_BATTERY_CHANGED: + Field 'ACTION_BATTERY_CHANGED' is missing @BroadcastBehavior +BroadcastBehavior: android.content.Intent#ACTION_BATTERY_LEVEL_CHANGED: + Field 'ACTION_BATTERY_LEVEL_CHANGED' is missing @BroadcastBehavior +BroadcastBehavior: android.content.Intent#ACTION_BATTERY_LOW: + Field 'ACTION_BATTERY_LOW' is missing @BroadcastBehavior +BroadcastBehavior: android.content.Intent#ACTION_BATTERY_OKAY: + Field 'ACTION_BATTERY_OKAY' is missing @BroadcastBehavior +BroadcastBehavior: android.content.Intent#ACTION_CAMERA_BUTTON: + Field 'ACTION_CAMERA_BUTTON' is missing @BroadcastBehavior +BroadcastBehavior: android.content.Intent#ACTION_CLOSE_SYSTEM_DIALOGS: + Field 'ACTION_CLOSE_SYSTEM_DIALOGS' is missing @BroadcastBehavior +BroadcastBehavior: android.content.Intent#ACTION_CONFIGURATION_CHANGED: + Field 'ACTION_CONFIGURATION_CHANGED' is missing @BroadcastBehavior +BroadcastBehavior: android.content.Intent#ACTION_DATE_CHANGED: + Field 'ACTION_DATE_CHANGED' is missing @BroadcastBehavior +BroadcastBehavior: android.content.Intent#ACTION_DEVICE_CUSTOMIZATION_READY: + Field 'ACTION_DEVICE_CUSTOMIZATION_READY' is missing @BroadcastBehavior +BroadcastBehavior: android.content.Intent#ACTION_DEVICE_STORAGE_LOW: + Field 'ACTION_DEVICE_STORAGE_LOW' is missing @BroadcastBehavior +BroadcastBehavior: android.content.Intent#ACTION_DEVICE_STORAGE_OK: + Field 'ACTION_DEVICE_STORAGE_OK' is missing @BroadcastBehavior +BroadcastBehavior: android.content.Intent#ACTION_DOCK_EVENT: + Field 'ACTION_DOCK_EVENT' is missing @BroadcastBehavior +BroadcastBehavior: android.content.Intent#ACTION_DOMAINS_NEED_VERIFICATION: + Field 'ACTION_DOMAINS_NEED_VERIFICATION' is missing @BroadcastBehavior +BroadcastBehavior: android.content.Intent#ACTION_DREAMING_STARTED: + Field 'ACTION_DREAMING_STARTED' is missing @BroadcastBehavior +BroadcastBehavior: android.content.Intent#ACTION_DREAMING_STOPPED: + Field 'ACTION_DREAMING_STOPPED' is missing @BroadcastBehavior +BroadcastBehavior: android.content.Intent#ACTION_EXTERNAL_APPLICATIONS_AVAILABLE: + Field 'ACTION_EXTERNAL_APPLICATIONS_AVAILABLE' is missing @BroadcastBehavior +BroadcastBehavior: android.content.Intent#ACTION_EXTERNAL_APPLICATIONS_UNAVAILABLE: + Field 'ACTION_EXTERNAL_APPLICATIONS_UNAVAILABLE' is missing @BroadcastBehavior +BroadcastBehavior: android.content.Intent#ACTION_GLOBAL_BUTTON: + Field 'ACTION_GLOBAL_BUTTON' is missing @BroadcastBehavior +BroadcastBehavior: android.content.Intent#ACTION_GTALK_SERVICE_CONNECTED: + Field 'ACTION_GTALK_SERVICE_CONNECTED' is missing @BroadcastBehavior +BroadcastBehavior: android.content.Intent#ACTION_GTALK_SERVICE_DISCONNECTED: + Field 'ACTION_GTALK_SERVICE_DISCONNECTED' is missing @BroadcastBehavior +BroadcastBehavior: android.content.Intent#ACTION_HEADSET_PLUG: + Field 'ACTION_HEADSET_PLUG' is missing @BroadcastBehavior +BroadcastBehavior: android.content.Intent#ACTION_INPUT_METHOD_CHANGED: + Field 'ACTION_INPUT_METHOD_CHANGED' is missing @BroadcastBehavior +BroadcastBehavior: android.content.Intent#ACTION_INSTALL_INSTANT_APP_PACKAGE: + Field 'ACTION_INSTALL_INSTANT_APP_PACKAGE' is missing @BroadcastBehavior +BroadcastBehavior: android.content.Intent#ACTION_INSTANT_APP_RESOLVER_SETTINGS: + Field 'ACTION_INSTANT_APP_RESOLVER_SETTINGS' is missing @BroadcastBehavior +BroadcastBehavior: android.content.Intent#ACTION_INTENT_FILTER_NEEDS_VERIFICATION: + Field 'ACTION_INTENT_FILTER_NEEDS_VERIFICATION' is missing @BroadcastBehavior +BroadcastBehavior: android.content.Intent#ACTION_LOAD_DATA: + Field 'ACTION_LOAD_DATA' is missing @BroadcastBehavior +BroadcastBehavior: android.content.Intent#ACTION_LOCALE_CHANGED: + Field 'ACTION_LOCALE_CHANGED' is missing @BroadcastBehavior +BroadcastBehavior: android.content.Intent#ACTION_LOCKED_BOOT_COMPLETED: + Field 'ACTION_LOCKED_BOOT_COMPLETED' is missing @BroadcastBehavior +BroadcastBehavior: android.content.Intent#ACTION_MANAGE_PACKAGE_STORAGE: + Field 'ACTION_MANAGE_PACKAGE_STORAGE' is missing @BroadcastBehavior +BroadcastBehavior: android.content.Intent#ACTION_MEDIA_BAD_REMOVAL: + Field 'ACTION_MEDIA_BAD_REMOVAL' is missing @BroadcastBehavior +BroadcastBehavior: android.content.Intent#ACTION_MEDIA_BUTTON: + Field 'ACTION_MEDIA_BUTTON' is missing @BroadcastBehavior +BroadcastBehavior: android.content.Intent#ACTION_MEDIA_CHECKING: + Field 'ACTION_MEDIA_CHECKING' is missing @BroadcastBehavior +BroadcastBehavior: android.content.Intent#ACTION_MEDIA_EJECT: + Field 'ACTION_MEDIA_EJECT' is missing @BroadcastBehavior +BroadcastBehavior: android.content.Intent#ACTION_MEDIA_MOUNTED: + Field 'ACTION_MEDIA_MOUNTED' is missing @BroadcastBehavior +BroadcastBehavior: android.content.Intent#ACTION_MEDIA_NOFS: + Field 'ACTION_MEDIA_NOFS' is missing @BroadcastBehavior +BroadcastBehavior: android.content.Intent#ACTION_MEDIA_REMOVED: + Field 'ACTION_MEDIA_REMOVED' is missing @BroadcastBehavior +BroadcastBehavior: android.content.Intent#ACTION_MEDIA_SCANNER_FINISHED: + Field 'ACTION_MEDIA_SCANNER_FINISHED' is missing @BroadcastBehavior +BroadcastBehavior: android.content.Intent#ACTION_MEDIA_SCANNER_SCAN_FILE: + Field 'ACTION_MEDIA_SCANNER_SCAN_FILE' is missing @BroadcastBehavior +BroadcastBehavior: android.content.Intent#ACTION_MEDIA_SCANNER_STARTED: + Field 'ACTION_MEDIA_SCANNER_STARTED' is missing @BroadcastBehavior +BroadcastBehavior: android.content.Intent#ACTION_MEDIA_SHARED: + Field 'ACTION_MEDIA_SHARED' is missing @BroadcastBehavior +BroadcastBehavior: android.content.Intent#ACTION_MEDIA_UNMOUNTABLE: + Field 'ACTION_MEDIA_UNMOUNTABLE' is missing @BroadcastBehavior +BroadcastBehavior: android.content.Intent#ACTION_MEDIA_UNMOUNTED: + Field 'ACTION_MEDIA_UNMOUNTED' is missing @BroadcastBehavior +BroadcastBehavior: android.content.Intent#ACTION_MY_PACKAGE_REPLACED: + Field 'ACTION_MY_PACKAGE_REPLACED' is missing @BroadcastBehavior +BroadcastBehavior: android.content.Intent#ACTION_MY_PACKAGE_SUSPENDED: + Field 'ACTION_MY_PACKAGE_SUSPENDED' is missing @BroadcastBehavior +BroadcastBehavior: android.content.Intent#ACTION_MY_PACKAGE_UNSUSPENDED: + Field 'ACTION_MY_PACKAGE_UNSUSPENDED' is missing @BroadcastBehavior +BroadcastBehavior: android.content.Intent#ACTION_NEW_OUTGOING_CALL: + Field 'ACTION_NEW_OUTGOING_CALL' is missing @BroadcastBehavior +BroadcastBehavior: android.content.Intent#ACTION_PACKAGES_SUSPENDED: + Field 'ACTION_PACKAGES_SUSPENDED' is missing @BroadcastBehavior +BroadcastBehavior: android.content.Intent#ACTION_PACKAGES_UNSUSPENDED: + Field 'ACTION_PACKAGES_UNSUSPENDED' is missing @BroadcastBehavior +BroadcastBehavior: android.content.Intent#ACTION_PACKAGE_ADDED: + Field 'ACTION_PACKAGE_ADDED' is missing @BroadcastBehavior +BroadcastBehavior: android.content.Intent#ACTION_PACKAGE_CHANGED: + Field 'ACTION_PACKAGE_CHANGED' is missing @BroadcastBehavior +BroadcastBehavior: android.content.Intent#ACTION_PACKAGE_DATA_CLEARED: + Field 'ACTION_PACKAGE_DATA_CLEARED' is missing @BroadcastBehavior +BroadcastBehavior: android.content.Intent#ACTION_PACKAGE_FIRST_LAUNCH: + Field 'ACTION_PACKAGE_FIRST_LAUNCH' is missing @BroadcastBehavior +BroadcastBehavior: android.content.Intent#ACTION_PACKAGE_FULLY_REMOVED: + Field 'ACTION_PACKAGE_FULLY_REMOVED' is missing @BroadcastBehavior +BroadcastBehavior: android.content.Intent#ACTION_PACKAGE_INSTALL: + Field 'ACTION_PACKAGE_INSTALL' is missing @BroadcastBehavior +BroadcastBehavior: android.content.Intent#ACTION_PACKAGE_NEEDS_INTEGRITY_VERIFICATION: + Field 'ACTION_PACKAGE_NEEDS_INTEGRITY_VERIFICATION' is missing @BroadcastBehavior +BroadcastBehavior: android.content.Intent#ACTION_PACKAGE_NEEDS_VERIFICATION: + Field 'ACTION_PACKAGE_NEEDS_VERIFICATION' is missing @BroadcastBehavior +BroadcastBehavior: android.content.Intent#ACTION_PACKAGE_REMOVED: + Field 'ACTION_PACKAGE_REMOVED' is missing @BroadcastBehavior +BroadcastBehavior: android.content.Intent#ACTION_PACKAGE_REPLACED: + Field 'ACTION_PACKAGE_REPLACED' is missing @BroadcastBehavior +BroadcastBehavior: android.content.Intent#ACTION_PACKAGE_RESTARTED: + Field 'ACTION_PACKAGE_RESTARTED' is missing @BroadcastBehavior +BroadcastBehavior: android.content.Intent#ACTION_PACKAGE_UNSTOPPED: + Field 'ACTION_PACKAGE_UNSTOPPED' is missing @BroadcastBehavior +BroadcastBehavior: android.content.Intent#ACTION_PACKAGE_UNSUSPENDED_MANUALLY: + Field 'ACTION_PACKAGE_UNSUSPENDED_MANUALLY' is missing @BroadcastBehavior +BroadcastBehavior: android.content.Intent#ACTION_PACKAGE_VERIFIED: + Field 'ACTION_PACKAGE_VERIFIED' is missing @BroadcastBehavior +BroadcastBehavior: android.content.Intent#ACTION_POWER_CONNECTED: + Field 'ACTION_POWER_CONNECTED' is missing @BroadcastBehavior +BroadcastBehavior: android.content.Intent#ACTION_POWER_DISCONNECTED: + Field 'ACTION_POWER_DISCONNECTED' is missing @BroadcastBehavior +BroadcastBehavior: android.content.Intent#ACTION_PRE_BOOT_COMPLETED: + Field 'ACTION_PRE_BOOT_COMPLETED' is missing @BroadcastBehavior +BroadcastBehavior: android.content.Intent#ACTION_PROVIDER_CHANGED: + Field 'ACTION_PROVIDER_CHANGED' is missing @BroadcastBehavior +BroadcastBehavior: android.content.Intent#ACTION_QUERY_PACKAGE_RESTART: + Field 'ACTION_QUERY_PACKAGE_RESTART' is missing @BroadcastBehavior +BroadcastBehavior: android.content.Intent#ACTION_REBOOT: + Field 'ACTION_REBOOT' is missing @BroadcastBehavior +BroadcastBehavior: android.content.Intent#ACTION_RESOLVE_INSTANT_APP_PACKAGE: + Field 'ACTION_RESOLVE_INSTANT_APP_PACKAGE' is missing @BroadcastBehavior +BroadcastBehavior: android.content.Intent#ACTION_ROLLBACK_COMMITTED: + Field 'ACTION_ROLLBACK_COMMITTED' is missing @BroadcastBehavior +BroadcastBehavior: android.content.Intent#ACTION_SCREEN_OFF: + Field 'ACTION_SCREEN_OFF' is missing @BroadcastBehavior +BroadcastBehavior: android.content.Intent#ACTION_SCREEN_ON: + Field 'ACTION_SCREEN_ON' is missing @BroadcastBehavior +BroadcastBehavior: android.content.Intent#ACTION_SHOW_SUSPENDED_APP_DETAILS: + Field 'ACTION_SHOW_SUSPENDED_APP_DETAILS' is missing @BroadcastBehavior +BroadcastBehavior: android.content.Intent#ACTION_SHUTDOWN: + Field 'ACTION_SHUTDOWN' is missing @BroadcastBehavior +BroadcastBehavior: android.content.Intent#ACTION_SIM_STATE_CHANGED: + Field 'ACTION_SIM_STATE_CHANGED' is missing @BroadcastBehavior +BroadcastBehavior: android.content.Intent#ACTION_SPLIT_CONFIGURATION_CHANGED: + Field 'ACTION_SPLIT_CONFIGURATION_CHANGED' is missing @BroadcastBehavior +BroadcastBehavior: android.content.Intent#ACTION_TIMEZONE_CHANGED: + Field 'ACTION_TIMEZONE_CHANGED' is missing @BroadcastBehavior +BroadcastBehavior: android.content.Intent#ACTION_TIME_CHANGED: + Field 'ACTION_TIME_CHANGED' is missing @BroadcastBehavior +BroadcastBehavior: android.content.Intent#ACTION_TIME_TICK: + Field 'ACTION_TIME_TICK' is missing @BroadcastBehavior +BroadcastBehavior: android.content.Intent#ACTION_UID_REMOVED: + Field 'ACTION_UID_REMOVED' is missing @BroadcastBehavior +BroadcastBehavior: android.content.Intent#ACTION_UMS_CONNECTED: + Field 'ACTION_UMS_CONNECTED' is missing @BroadcastBehavior +BroadcastBehavior: android.content.Intent#ACTION_UMS_DISCONNECTED: + Field 'ACTION_UMS_DISCONNECTED' is missing @BroadcastBehavior +BroadcastBehavior: android.content.Intent#ACTION_UNARCHIVE_PACKAGE: + Field 'ACTION_UNARCHIVE_PACKAGE' is missing @BroadcastBehavior +BroadcastBehavior: android.content.Intent#ACTION_USER_PRESENT: + Field 'ACTION_USER_PRESENT' is missing @BroadcastBehavior +BroadcastBehavior: android.content.Intent#ACTION_USER_UNLOCKED: + Field 'ACTION_USER_UNLOCKED' is missing @BroadcastBehavior +BroadcastBehavior: android.content.Intent#ACTION_WALLPAPER_CHANGED: + Field 'ACTION_WALLPAPER_CHANGED' is missing @BroadcastBehavior +BroadcastBehavior: android.content.pm.PackageInstaller#ACTION_SESSION_COMMITTED: + Field 'ACTION_SESSION_COMMITTED' is missing @BroadcastBehavior +BroadcastBehavior: android.content.pm.PackageInstaller#ACTION_SESSION_UPDATED: + Field 'ACTION_SESSION_UPDATED' is missing @BroadcastBehavior +BroadcastBehavior: android.hardware.Camera#ACTION_NEW_PICTURE: + Field 'ACTION_NEW_PICTURE' is missing @BroadcastBehavior +BroadcastBehavior: android.hardware.Camera#ACTION_NEW_VIDEO: + Field 'ACTION_NEW_VIDEO' is missing @BroadcastBehavior +BroadcastBehavior: android.hardware.hdmi.HdmiControlManager#ACTION_OSD_MESSAGE: + Field 'ACTION_OSD_MESSAGE' is missing @BroadcastBehavior +BroadcastBehavior: android.hardware.input.InputManager#ACTION_QUERY_KEYBOARD_LAYOUTS: + Field 'ACTION_QUERY_KEYBOARD_LAYOUTS' is missing @BroadcastBehavior +BroadcastBehavior: android.hardware.usb.UsbManager#ACTION_USB_ACCESSORY_DETACHED: + Field 'ACTION_USB_ACCESSORY_DETACHED' is missing @BroadcastBehavior +BroadcastBehavior: android.hardware.usb.UsbManager#ACTION_USB_ACCESSORY_HANDSHAKE: + Field 'ACTION_USB_ACCESSORY_HANDSHAKE' is missing @BroadcastBehavior +BroadcastBehavior: android.hardware.usb.UsbManager#ACTION_USB_DEVICE_DETACHED: + Field 'ACTION_USB_DEVICE_DETACHED' is missing @BroadcastBehavior +BroadcastBehavior: android.hardware.usb.UsbManager#ACTION_USB_PORT_CHANGED: + Field 'ACTION_USB_PORT_CHANGED' is missing @BroadcastBehavior +BroadcastBehavior: android.hardware.usb.UsbManager#ACTION_USB_PORT_COMPLIANCE_CHANGED: + Field 'ACTION_USB_PORT_COMPLIANCE_CHANGED' is missing @BroadcastBehavior +BroadcastBehavior: android.hardware.usb.UsbManager#ACTION_USB_STATE: + Field 'ACTION_USB_STATE' is missing @BroadcastBehavior +BroadcastBehavior: android.media.AudioManager#ACTION_HDMI_AUDIO_PLUG: + Field 'ACTION_HDMI_AUDIO_PLUG' is missing @BroadcastBehavior +BroadcastBehavior: android.media.AudioManager#ACTION_HEADSET_PLUG: + Field 'ACTION_HEADSET_PLUG' is missing @BroadcastBehavior +BroadcastBehavior: android.media.AudioManager#ACTION_MICROPHONE_MUTE_CHANGED: + Field 'ACTION_MICROPHONE_MUTE_CHANGED' is missing @BroadcastBehavior +BroadcastBehavior: android.media.AudioManager#ACTION_SPEAKERPHONE_STATE_CHANGED: + Field 'ACTION_SPEAKERPHONE_STATE_CHANGED' is missing @BroadcastBehavior +BroadcastBehavior: android.media.tv.TvContract#ACTION_CHANNEL_BROWSABLE_REQUESTED: + Field 'ACTION_CHANNEL_BROWSABLE_REQUESTED' is missing @BroadcastBehavior +BroadcastBehavior: android.media.tv.TvContract#ACTION_INITIALIZE_PROGRAMS: + Field 'ACTION_INITIALIZE_PROGRAMS' is missing @BroadcastBehavior +BroadcastBehavior: android.media.tv.TvContract#ACTION_PREVIEW_PROGRAM_ADDED_TO_WATCH_NEXT: + Field 'ACTION_PREVIEW_PROGRAM_ADDED_TO_WATCH_NEXT' is missing @BroadcastBehavior +BroadcastBehavior: android.media.tv.TvContract#ACTION_PREVIEW_PROGRAM_BROWSABLE_DISABLED: + Field 'ACTION_PREVIEW_PROGRAM_BROWSABLE_DISABLED' is missing @BroadcastBehavior +BroadcastBehavior: android.media.tv.TvContract#ACTION_WATCH_NEXT_PROGRAM_BROWSABLE_DISABLED: + Field 'ACTION_WATCH_NEXT_PROGRAM_BROWSABLE_DISABLED' is missing @BroadcastBehavior +BroadcastBehavior: android.net.NetworkScoreManager#ACTION_SCORER_CHANGED: + Field 'ACTION_SCORER_CHANGED' is missing @BroadcastBehavior +BroadcastBehavior: android.net.NetworkScoreManager#ACTION_SCORE_NETWORKS: + Field 'ACTION_SCORE_NETWORKS' is missing @BroadcastBehavior +BroadcastBehavior: android.net.Proxy#PROXY_CHANGE_ACTION: + Field 'PROXY_CHANGE_ACTION' is missing @BroadcastBehavior +BroadcastBehavior: android.nfc.NfcAdapter#ACTION_ADAPTER_STATE_CHANGED: + Field 'ACTION_ADAPTER_STATE_CHANGED' is missing @BroadcastBehavior +BroadcastBehavior: android.nfc.NfcAdapter#ACTION_PREFERRED_PAYMENT_CHANGED: + Field 'ACTION_PREFERRED_PAYMENT_CHANGED' is missing @BroadcastBehavior +BroadcastBehavior: android.nfc.NfcAdapter#ACTION_REQUIRE_UNLOCK_FOR_NFC: + Field 'ACTION_REQUIRE_UNLOCK_FOR_NFC' is missing @BroadcastBehavior +BroadcastBehavior: android.nfc.NfcAdapter#ACTION_TRANSACTION_DETECTED: + Field 'ACTION_TRANSACTION_DETECTED' is missing @BroadcastBehavior +BroadcastBehavior: android.os.DropBoxManager#ACTION_DROPBOX_ENTRY_ADDED: + Field 'ACTION_DROPBOX_ENTRY_ADDED' is missing @BroadcastBehavior +BroadcastBehavior: android.provider.CalendarContract#ACTION_EVENT_REMINDER: + Field 'ACTION_EVENT_REMINDER' is missing @BroadcastBehavior +BroadcastBehavior: android.provider.ContactsContract.SimContacts#ACTION_SIM_ACCOUNTS_CHANGED: + Field 'ACTION_SIM_ACCOUNTS_CHANGED' is missing @BroadcastBehavior +BroadcastBehavior: android.provider.Telephony.Sms.Intents#ACTION_SMS_EMERGENCY_CB_RECEIVED: + Field 'ACTION_SMS_EMERGENCY_CB_RECEIVED' is missing @BroadcastBehavior +BroadcastBehavior: android.provider.Telephony.Sms.Intents#DATA_SMS_RECEIVED_ACTION: + Field 'DATA_SMS_RECEIVED_ACTION' is missing @BroadcastBehavior +BroadcastBehavior: android.provider.Telephony.Sms.Intents#SECRET_CODE_ACTION: + Field 'SECRET_CODE_ACTION' is missing @BroadcastBehavior +BroadcastBehavior: android.provider.Telephony.Sms.Intents#SIM_FULL_ACTION: + Field 'SIM_FULL_ACTION' is missing @BroadcastBehavior +BroadcastBehavior: android.provider.Telephony.Sms.Intents#SMS_CB_RECEIVED_ACTION: + Field 'SMS_CB_RECEIVED_ACTION' is missing @BroadcastBehavior +BroadcastBehavior: android.provider.Telephony.Sms.Intents#SMS_DELIVER_ACTION: + Field 'SMS_DELIVER_ACTION' is missing @BroadcastBehavior +BroadcastBehavior: android.provider.Telephony.Sms.Intents#SMS_RECEIVED_ACTION: + Field 'SMS_RECEIVED_ACTION' is missing @BroadcastBehavior +BroadcastBehavior: android.provider.Telephony.Sms.Intents#SMS_REJECTED_ACTION: + Field 'SMS_REJECTED_ACTION' is missing @BroadcastBehavior +BroadcastBehavior: android.provider.Telephony.Sms.Intents#SMS_SERVICE_CATEGORY_PROGRAM_DATA_RECEIVED_ACTION: + Field 'SMS_SERVICE_CATEGORY_PROGRAM_DATA_RECEIVED_ACTION' is missing @BroadcastBehavior +BroadcastBehavior: android.provider.Telephony.Sms.Intents#WAP_PUSH_DELIVER_ACTION: + Field 'WAP_PUSH_DELIVER_ACTION' is missing @BroadcastBehavior +BroadcastBehavior: android.provider.Telephony.Sms.Intents#WAP_PUSH_RECEIVED_ACTION: + Field 'WAP_PUSH_RECEIVED_ACTION' is missing @BroadcastBehavior +BroadcastBehavior: android.security.KeyChain#ACTION_KEYCHAIN_CHANGED: + Field 'ACTION_KEYCHAIN_CHANGED' is missing @BroadcastBehavior +BroadcastBehavior: android.security.KeyChain#ACTION_KEY_ACCESS_CHANGED: + Field 'ACTION_KEY_ACCESS_CHANGED' is missing @BroadcastBehavior +BroadcastBehavior: android.security.KeyChain#ACTION_STORAGE_CHANGED: + Field 'ACTION_STORAGE_CHANGED' is missing @BroadcastBehavior +BroadcastBehavior: android.security.KeyChain#ACTION_TRUST_STORE_CHANGED: + Field 'ACTION_TRUST_STORE_CHANGED' is missing @BroadcastBehavior +BroadcastBehavior: android.service.euicc.EuiccService#ACTION_DELETE_SUBSCRIPTION_PRIVILEGED: + Field 'ACTION_DELETE_SUBSCRIPTION_PRIVILEGED' is missing @BroadcastBehavior +BroadcastBehavior: android.service.euicc.EuiccService#ACTION_RENAME_SUBSCRIPTION_PRIVILEGED: + Field 'ACTION_RENAME_SUBSCRIPTION_PRIVILEGED' is missing @BroadcastBehavior +BroadcastBehavior: android.service.euicc.EuiccService#ACTION_START_EUICC_ACTIVATION: + Field 'ACTION_START_EUICC_ACTIVATION' is missing @BroadcastBehavior +BroadcastBehavior: android.service.euicc.EuiccService#ACTION_TOGGLE_SUBSCRIPTION_PRIVILEGED: + Field 'ACTION_TOGGLE_SUBSCRIPTION_PRIVILEGED' is missing @BroadcastBehavior +BroadcastBehavior: android.speech.tts.TextToSpeech#ACTION_TTS_QUEUE_PROCESSING_COMPLETED: + Field 'ACTION_TTS_QUEUE_PROCESSING_COMPLETED' is missing @BroadcastBehavior +BroadcastBehavior: android.speech.tts.TextToSpeech.Engine#ACTION_TTS_DATA_INSTALLED: + Field 'ACTION_TTS_DATA_INSTALLED' is missing @BroadcastBehavior +BroadcastBehavior: android.telephony.SubscriptionManager#ACTION_DEFAULT_SMS_SUBSCRIPTION_CHANGED: + Field 'ACTION_DEFAULT_SMS_SUBSCRIPTION_CHANGED' is missing @BroadcastBehavior +BroadcastBehavior: android.telephony.SubscriptionManager#ACTION_DEFAULT_SUBSCRIPTION_CHANGED: + Field 'ACTION_DEFAULT_SUBSCRIPTION_CHANGED' is missing @BroadcastBehavior +BroadcastBehavior: android.telephony.SubscriptionManager#ACTION_REFRESH_SUBSCRIPTION_PLANS: + Field 'ACTION_REFRESH_SUBSCRIPTION_PLANS' is missing @BroadcastBehavior +BroadcastBehavior: android.telephony.SubscriptionManager#ACTION_SUBSCRIPTION_PLANS_CHANGED: + Field 'ACTION_SUBSCRIPTION_PLANS_CHANGED' is missing @BroadcastBehavior +BroadcastBehavior: android.telephony.TelephonyManager#ACTION_CARRIER_SIGNAL_DEFAULT_NETWORK_AVAILABLE: + Field 'ACTION_CARRIER_SIGNAL_DEFAULT_NETWORK_AVAILABLE' is missing @BroadcastBehavior +BroadcastBehavior: android.telephony.TelephonyManager#ACTION_CARRIER_SIGNAL_PCO_VALUE: + Field 'ACTION_CARRIER_SIGNAL_PCO_VALUE' is missing @BroadcastBehavior +BroadcastBehavior: android.telephony.TelephonyManager#ACTION_CARRIER_SIGNAL_REDIRECTED: + Field 'ACTION_CARRIER_SIGNAL_REDIRECTED' is missing @BroadcastBehavior +BroadcastBehavior: android.telephony.TelephonyManager#ACTION_CARRIER_SIGNAL_REQUEST_NETWORK_FAILED: + Field 'ACTION_CARRIER_SIGNAL_REQUEST_NETWORK_FAILED' is missing @BroadcastBehavior +BroadcastBehavior: android.telephony.TelephonyManager#ACTION_CARRIER_SIGNAL_RESET: + Field 'ACTION_CARRIER_SIGNAL_RESET' is missing @BroadcastBehavior +BroadcastBehavior: android.telephony.TelephonyManager#ACTION_DEFAULT_DATA_SUBSCRIPTION_CHANGED: + Field 'ACTION_DEFAULT_DATA_SUBSCRIPTION_CHANGED' is missing @BroadcastBehavior +BroadcastBehavior: android.telephony.TelephonyManager#ACTION_DEFAULT_VOICE_SUBSCRIPTION_CHANGED: + Field 'ACTION_DEFAULT_VOICE_SUBSCRIPTION_CHANGED' is missing @BroadcastBehavior +BroadcastBehavior: android.telephony.TelephonyManager#ACTION_EMERGENCY_CALLBACK_MODE_CHANGED: + Field 'ACTION_EMERGENCY_CALLBACK_MODE_CHANGED' is missing @BroadcastBehavior +BroadcastBehavior: android.telephony.TelephonyManager#ACTION_EMERGENCY_CALL_STATE_CHANGED: + Field 'ACTION_EMERGENCY_CALL_STATE_CHANGED' is missing @BroadcastBehavior +BroadcastBehavior: android.telephony.TelephonyManager#ACTION_REQUEST_OMADM_CONFIGURATION_UPDATE: + Field 'ACTION_REQUEST_OMADM_CONFIGURATION_UPDATE' is missing @BroadcastBehavior +BroadcastBehavior: android.telephony.TelephonyManager#ACTION_SECRET_CODE: + Field 'ACTION_SECRET_CODE' is missing @BroadcastBehavior +BroadcastBehavior: android.telephony.TelephonyManager#ACTION_SHOW_NOTICE_ECM_BLOCK_OTHERS: + Field 'ACTION_SHOW_NOTICE_ECM_BLOCK_OTHERS' is missing @BroadcastBehavior +BroadcastBehavior: android.telephony.TelephonyManager#ACTION_SIM_APPLICATION_STATE_CHANGED: + Field 'ACTION_SIM_APPLICATION_STATE_CHANGED' is missing @BroadcastBehavior +BroadcastBehavior: android.telephony.TelephonyManager#ACTION_SIM_CARD_STATE_CHANGED: + Field 'ACTION_SIM_CARD_STATE_CHANGED' is missing @BroadcastBehavior +BroadcastBehavior: android.telephony.TelephonyManager#ACTION_SIM_SLOT_STATUS_CHANGED: + Field 'ACTION_SIM_SLOT_STATUS_CHANGED' is missing @BroadcastBehavior +BroadcastBehavior: android.telephony.TelephonyManager#ACTION_SUBSCRIPTION_CARRIER_IDENTITY_CHANGED: + Field 'ACTION_SUBSCRIPTION_CARRIER_IDENTITY_CHANGED' is missing @BroadcastBehavior +BroadcastBehavior: android.telephony.TelephonyManager#ACTION_SUBSCRIPTION_SPECIFIC_CARRIER_IDENTITY_CHANGED: + Field 'ACTION_SUBSCRIPTION_SPECIFIC_CARRIER_IDENTITY_CHANGED' is missing @BroadcastBehavior +BroadcastBehavior: android.telephony.euicc.EuiccManager#ACTION_NOTIFY_CARRIER_SETUP_INCOMPLETE: + Field 'ACTION_NOTIFY_CARRIER_SETUP_INCOMPLETE' is missing @BroadcastBehavior +BroadcastBehavior: android.telephony.euicc.EuiccManager#ACTION_OTA_STATUS_CHANGED: + Field 'ACTION_OTA_STATUS_CHANGED' is missing @BroadcastBehavior + + +DeprecationMismatch: android.accounts.AccountManager#newChooseAccountIntent(android.accounts.Account, java.util.ArrayList<android.accounts.Account>, String[], boolean, String, String, String[], android.os.Bundle): + Method android.accounts.AccountManager.newChooseAccountIntent(android.accounts.Account, java.util.ArrayList<android.accounts.Account>, String[], boolean, String, String, String[], android.os.Bundle): @Deprecated annotation (present) and @deprecated doc tag (not present) do not match +DeprecationMismatch: android.app.Activity#enterPictureInPictureMode(): + Method android.app.Activity.enterPictureInPictureMode(): @Deprecated annotation (present) and @deprecated doc tag (not present) do not match +DeprecationMismatch: android.app.Instrumentation#startAllocCounting(): + Method android.app.Instrumentation.startAllocCounting(): @Deprecated annotation (present) and @deprecated doc tag (not present) do not match +DeprecationMismatch: android.app.Instrumentation#stopAllocCounting(): + Method android.app.Instrumentation.stopAllocCounting(): @Deprecated annotation (present) and @deprecated doc tag (not present) do not match +DeprecationMismatch: android.app.Notification#bigContentView: + Field Notification.bigContentView: @Deprecated annotation (present) and @deprecated doc tag (not present) do not match +DeprecationMismatch: android.app.Notification#contentView: + Field Notification.contentView: @Deprecated annotation (present) and @deprecated doc tag (not present) do not match +DeprecationMismatch: android.app.Notification#headsUpContentView: + Field Notification.headsUpContentView: @Deprecated annotation (present) and @deprecated doc tag (not present) do not match +DeprecationMismatch: android.app.Notification#tickerView: + Field Notification.tickerView: @Deprecated annotation (present) and @deprecated doc tag (not present) do not match +DeprecationMismatch: android.app.Notification.Action.Builder#Builder(int, CharSequence, android.app.PendingIntent): + Constructor android.app.Notification.Action.Builder.Builder(int, CharSequence, android.app.PendingIntent): @Deprecated annotation (present) and @deprecated doc tag (not present) do not match +DeprecationMismatch: android.app.Notification.Action.WearableExtender#getCancelLabel(): + Method android.app.Notification.Action.WearableExtender.getCancelLabel(): @Deprecated annotation (present) and @deprecated doc tag (not present) do not match +DeprecationMismatch: android.app.Notification.Action.WearableExtender#getConfirmLabel(): + Method android.app.Notification.Action.WearableExtender.getConfirmLabel(): @Deprecated annotation (present) and @deprecated doc tag (not present) do not match +DeprecationMismatch: android.app.Notification.Action.WearableExtender#getInProgressLabel(): + Method android.app.Notification.Action.WearableExtender.getInProgressLabel(): @Deprecated annotation (present) and @deprecated doc tag (not present) do not match +DeprecationMismatch: android.app.Notification.Action.WearableExtender#setCancelLabel(CharSequence): + Method android.app.Notification.Action.WearableExtender.setCancelLabel(CharSequence): @Deprecated annotation (present) and @deprecated doc tag (not present) do not match +DeprecationMismatch: android.app.Notification.Action.WearableExtender#setConfirmLabel(CharSequence): + Method android.app.Notification.Action.WearableExtender.setConfirmLabel(CharSequence): @Deprecated annotation (present) and @deprecated doc tag (not present) do not match +DeprecationMismatch: android.app.Notification.Action.WearableExtender#setInProgressLabel(CharSequence): + Method android.app.Notification.Action.WearableExtender.setInProgressLabel(CharSequence): @Deprecated annotation (present) and @deprecated doc tag (not present) do not match +DeprecationMismatch: android.app.Notification.Builder#setContent(android.widget.RemoteViews): + Method android.app.Notification.Builder.setContent(android.widget.RemoteViews): @Deprecated annotation (present) and @deprecated doc tag (not present) do not match +DeprecationMismatch: android.app.Notification.Builder#setTicker(CharSequence, android.widget.RemoteViews): + Method android.app.Notification.Builder.setTicker(CharSequence, android.widget.RemoteViews): @Deprecated annotation (present) and @deprecated doc tag (not present) do not match +DeprecationMismatch: android.app.Notification.WearableExtender#getContentIcon(): + Method android.app.Notification.WearableExtender.getContentIcon(): @Deprecated annotation (present) and @deprecated doc tag (not present) do not match +DeprecationMismatch: android.app.Notification.WearableExtender#getContentIconGravity(): + Method android.app.Notification.WearableExtender.getContentIconGravity(): @Deprecated annotation (present) and @deprecated doc tag (not present) do not match +DeprecationMismatch: android.app.Notification.WearableExtender#getCustomContentHeight(): + Method android.app.Notification.WearableExtender.getCustomContentHeight(): @Deprecated annotation (present) and @deprecated doc tag (not present) do not match +DeprecationMismatch: android.app.Notification.WearableExtender#getCustomSizePreset(): + Method android.app.Notification.WearableExtender.getCustomSizePreset(): @Deprecated annotation (present) and @deprecated doc tag (not present) do not match +DeprecationMismatch: android.app.Notification.WearableExtender#getGravity(): + Method android.app.Notification.WearableExtender.getGravity(): @Deprecated annotation (present) and @deprecated doc tag (not present) do not match +DeprecationMismatch: android.app.Notification.WearableExtender#getHintAvoidBackgroundClipping(): + Method android.app.Notification.WearableExtender.getHintAvoidBackgroundClipping(): @Deprecated annotation (present) and @deprecated doc tag (not present) do not match +DeprecationMismatch: android.app.Notification.WearableExtender#getHintHideIcon(): + Method android.app.Notification.WearableExtender.getHintHideIcon(): @Deprecated annotation (present) and @deprecated doc tag (not present) do not match +DeprecationMismatch: android.app.Notification.WearableExtender#getHintScreenTimeout(): + Method android.app.Notification.WearableExtender.getHintScreenTimeout(): @Deprecated annotation (present) and @deprecated doc tag (not present) do not match +DeprecationMismatch: android.app.Notification.WearableExtender#getHintShowBackgroundOnly(): + Method android.app.Notification.WearableExtender.getHintShowBackgroundOnly(): @Deprecated annotation (present) and @deprecated doc tag (not present) do not match +DeprecationMismatch: android.app.Notification.WearableExtender#setContentIcon(int): + Method android.app.Notification.WearableExtender.setContentIcon(int): @Deprecated annotation (present) and @deprecated doc tag (not present) do not match +DeprecationMismatch: android.app.Notification.WearableExtender#setContentIconGravity(int): + Method android.app.Notification.WearableExtender.setContentIconGravity(int): @Deprecated annotation (present) and @deprecated doc tag (not present) do not match +DeprecationMismatch: android.app.Notification.WearableExtender#setCustomContentHeight(int): + Method android.app.Notification.WearableExtender.setCustomContentHeight(int): @Deprecated annotation (present) and @deprecated doc tag (not present) do not match +DeprecationMismatch: android.app.Notification.WearableExtender#setCustomSizePreset(int): + Method android.app.Notification.WearableExtender.setCustomSizePreset(int): @Deprecated annotation (present) and @deprecated doc tag (not present) do not match +DeprecationMismatch: android.app.Notification.WearableExtender#setGravity(int): + Method android.app.Notification.WearableExtender.setGravity(int): @Deprecated annotation (present) and @deprecated doc tag (not present) do not match +DeprecationMismatch: android.app.Notification.WearableExtender#setHintAvoidBackgroundClipping(boolean): + Method android.app.Notification.WearableExtender.setHintAvoidBackgroundClipping(boolean): @Deprecated annotation (present) and @deprecated doc tag (not present) do not match +DeprecationMismatch: android.app.Notification.WearableExtender#setHintHideIcon(boolean): + Method android.app.Notification.WearableExtender.setHintHideIcon(boolean): @Deprecated annotation (present) and @deprecated doc tag (not present) do not match +DeprecationMismatch: android.app.Notification.WearableExtender#setHintScreenTimeout(int): + Method android.app.Notification.WearableExtender.setHintScreenTimeout(int): @Deprecated annotation (present) and @deprecated doc tag (not present) do not match +DeprecationMismatch: android.app.Notification.WearableExtender#setHintShowBackgroundOnly(boolean): + Method android.app.Notification.WearableExtender.setHintShowBackgroundOnly(boolean): @Deprecated annotation (present) and @deprecated doc tag (not present) do not match +DeprecationMismatch: android.app.backup.BackupManager#selectBackupTransport(String): + Method android.app.backup.BackupManager.selectBackupTransport(String): @Deprecated annotation (present) and @deprecated doc tag (not present) do not match +DeprecationMismatch: android.content.Context#BIND_ALLOW_FOREGROUND_SERVICE_STARTS_FROM_BACKGROUND: + Field Context.BIND_ALLOW_FOREGROUND_SERVICE_STARTS_FROM_BACKGROUND: @Deprecated annotation (present) and @deprecated doc tag (not present) do not match +DeprecationMismatch: android.content.Context#WIFI_RTT_SERVICE: + Field Context.WIFI_RTT_SERVICE: @Deprecated annotation (present) and @deprecated doc tag (not present) do not match +DeprecationMismatch: android.graphics.ComposeShader#ComposeShader(android.graphics.Shader, android.graphics.Shader, android.graphics.Xfermode): + Constructor android.graphics.ComposeShader.ComposeShader(android.graphics.Shader, android.graphics.Shader, android.graphics.Xfermode): @Deprecated annotation (present) and @deprecated doc tag (not present) do not match +DeprecationMismatch: android.graphics.PixelFormat#A_8: + Field PixelFormat.A_8: @Deprecated annotation (present) and @deprecated doc tag (not present) do not match +DeprecationMismatch: android.graphics.PixelFormat#LA_88: + Field PixelFormat.LA_88: @Deprecated annotation (present) and @deprecated doc tag (not present) do not match +DeprecationMismatch: android.graphics.PixelFormat#L_8: + Field PixelFormat.L_8: @Deprecated annotation (present) and @deprecated doc tag (not present) do not match +DeprecationMismatch: android.graphics.PixelFormat#RGBA_4444: + Field PixelFormat.RGBA_4444: @Deprecated annotation (present) and @deprecated doc tag (not present) do not match +DeprecationMismatch: android.graphics.PixelFormat#RGBA_5551: + Field PixelFormat.RGBA_5551: @Deprecated annotation (present) and @deprecated doc tag (not present) do not match +DeprecationMismatch: android.graphics.PixelFormat#RGB_332: + Field PixelFormat.RGB_332: @Deprecated annotation (present) and @deprecated doc tag (not present) do not match +DeprecationMismatch: android.hardware.hdmi.HdmiControlManager#RESULT_ALREADY_IN_PROGRESS: + Field HdmiControlManager.RESULT_ALREADY_IN_PROGRESS: @Deprecated annotation (present) and @deprecated doc tag (not present) do not match +DeprecationMismatch: android.media.tv.tuner.frontend.IsdbtFrontendSettings.Builder#setCodeRate(int): + Method android.media.tv.tuner.frontend.IsdbtFrontendSettings.Builder.setCodeRate(int): @Deprecated annotation (present) and @deprecated doc tag (not present) do not match +DeprecationMismatch: android.media.tv.tuner.frontend.IsdbtFrontendSettings.Builder#setModulation(int): + Method android.media.tv.tuner.frontend.IsdbtFrontendSettings.Builder.setModulation(int): @Deprecated annotation (present) and @deprecated doc tag (not present) do not match +DeprecationMismatch: android.opengl.EGL14#eglCreatePixmapSurface(android.opengl.EGLDisplay, android.opengl.EGLConfig, int, int[], int): + Method android.opengl.EGL14.eglCreatePixmapSurface(android.opengl.EGLDisplay, android.opengl.EGLConfig, int, int[], int): @Deprecated annotation (present) and @deprecated doc tag (not present) do not match +DeprecationMismatch: android.opengl.GLES20#GL_STENCIL_INDEX: + Field GLES20.GL_STENCIL_INDEX: @Deprecated annotation (present) and @deprecated doc tag (not present) do not match +DeprecationMismatch: android.opengl.GLSurfaceView#surfaceRedrawNeeded(android.view.SurfaceHolder): + Method android.opengl.GLSurfaceView.surfaceRedrawNeeded(android.view.SurfaceHolder): @Deprecated annotation (present) and @deprecated doc tag (not present) do not match +DeprecationMismatch: android.os.UserManager#setUserRestrictions(android.os.Bundle): + Method android.os.UserManager.setUserRestrictions(android.os.Bundle): @Deprecated annotation (present) and @deprecated doc tag (not present) do not match +DeprecationMismatch: android.os.UserManager#setUserRestrictions(android.os.Bundle, android.os.UserHandle): + Method android.os.UserManager.setUserRestrictions(android.os.Bundle, android.os.UserHandle): @Deprecated annotation (present) and @deprecated doc tag (not present) do not match +DeprecationMismatch: android.provider.Contacts.People#markAsContacted(android.content.ContentResolver, long): + Method android.provider.Contacts.People.markAsContacted(android.content.ContentResolver, long): @Deprecated annotation (present) and @deprecated doc tag (not present) do not match +DeprecationMismatch: android.renderscript.Type.CubemapFace#POSITVE_X: + Field Type.CubemapFace.POSITVE_X: @Deprecated annotation (present) and @deprecated doc tag (not present) do not match +DeprecationMismatch: android.renderscript.Type.CubemapFace#POSITVE_Y: + Field Type.CubemapFace.POSITVE_Y: @Deprecated annotation (present) and @deprecated doc tag (not present) do not match +DeprecationMismatch: android.renderscript.Type.CubemapFace#POSITVE_Z: + Field Type.CubemapFace.POSITVE_Z: @Deprecated annotation (present) and @deprecated doc tag (not present) do not match +DeprecationMismatch: android.speech.tts.TextToSpeech#areDefaultsEnforced(): + Method android.speech.tts.TextToSpeech.areDefaultsEnforced(): @Deprecated annotation (present) and @deprecated doc tag (not present) do not match +DeprecationMismatch: android.telecom.StatusHints#StatusHints(android.content.ComponentName, CharSequence, int, android.os.Bundle): + Constructor android.telecom.StatusHints.StatusHints(android.content.ComponentName, CharSequence, int, android.os.Bundle): @Deprecated annotation (present) and @deprecated doc tag (not present) do not match +DeprecationMismatch: android.telecom.StatusHints#getIcon(android.content.Context): + Method android.telecom.StatusHints.getIcon(android.content.Context): @Deprecated annotation (present) and @deprecated doc tag (not present) do not match +DeprecationMismatch: android.telecom.StatusHints#getIconResId(): + Method android.telecom.StatusHints.getIconResId(): @Deprecated annotation (present) and @deprecated doc tag (not present) do not match +DeprecationMismatch: android.telecom.StatusHints#getPackageName(): + Method android.telecom.StatusHints.getPackageName(): @Deprecated annotation (present) and @deprecated doc tag (not present) do not match +DeprecationMismatch: android.telephony.PhoneStateListener#PhoneStateListener(java.util.concurrent.Executor): + Constructor android.telephony.PhoneStateListener.PhoneStateListener(java.util.concurrent.Executor): @Deprecated annotation (present) and @deprecated doc tag (not present) do not match +DeprecationMismatch: android.telephony.SubscriptionManager#PROFILE_CLASS_DEFAULT: + Field SubscriptionManager.PROFILE_CLASS_DEFAULT: @Deprecated annotation (present) and @deprecated doc tag (not present) do not match +DeprecationMismatch: android.telephony.SubscriptionPlan.Builder#createRecurringDaily(java.time.ZonedDateTime): + Method android.telephony.SubscriptionPlan.Builder.createRecurringDaily(java.time.ZonedDateTime): @Deprecated annotation (present) and @deprecated doc tag (not present) do not match +DeprecationMismatch: android.telephony.SubscriptionPlan.Builder#createRecurringMonthly(java.time.ZonedDateTime): + Method android.telephony.SubscriptionPlan.Builder.createRecurringMonthly(java.time.ZonedDateTime): @Deprecated annotation (present) and @deprecated doc tag (not present) do not match +DeprecationMismatch: android.telephony.SubscriptionPlan.Builder#createRecurringWeekly(java.time.ZonedDateTime): + Method android.telephony.SubscriptionPlan.Builder.createRecurringWeekly(java.time.ZonedDateTime): @Deprecated annotation (present) and @deprecated doc tag (not present) do not match +DeprecationMismatch: android.text.format.DateUtils#FORMAT_12HOUR: + Field DateUtils.FORMAT_12HOUR: @Deprecated annotation (present) and @deprecated doc tag (not present) do not match +DeprecationMismatch: android.text.format.DateUtils#FORMAT_24HOUR: + Field DateUtils.FORMAT_24HOUR: @Deprecated annotation (present) and @deprecated doc tag (not present) do not match +DeprecationMismatch: android.text.format.DateUtils#FORMAT_CAP_AMPM: + Field DateUtils.FORMAT_CAP_AMPM: @Deprecated annotation (present) and @deprecated doc tag (not present) do not match +DeprecationMismatch: android.text.format.DateUtils#FORMAT_CAP_MIDNIGHT: + Field DateUtils.FORMAT_CAP_MIDNIGHT: @Deprecated annotation (present) and @deprecated doc tag (not present) do not match +DeprecationMismatch: android.text.format.DateUtils#FORMAT_CAP_NOON: + Field DateUtils.FORMAT_CAP_NOON: @Deprecated annotation (present) and @deprecated doc tag (not present) do not match +DeprecationMismatch: android.text.format.DateUtils#FORMAT_CAP_NOON_MIDNIGHT: + Field DateUtils.FORMAT_CAP_NOON_MIDNIGHT: @Deprecated annotation (present) and @deprecated doc tag (not present) do not match +DeprecationMismatch: android.text.format.DateUtils#FORMAT_NO_NOON_MIDNIGHT: + Field DateUtils.FORMAT_NO_NOON_MIDNIGHT: @Deprecated annotation (present) and @deprecated doc tag (not present) do not match +DeprecationMismatch: android.view.ViewGroup.LayoutParams#FILL_PARENT: + Field ViewGroup.LayoutParams.FILL_PARENT: @Deprecated annotation (present) and @deprecated doc tag (not present) do not match +DeprecationMismatch: android.view.Window#setTitleColor(int): + Method android.view.Window.setTitleColor(int): @Deprecated annotation (present) and @deprecated doc tag (not present) do not match +DeprecationMismatch: android.view.accessibility.AccessibilityEvent#MAX_TEXT_LENGTH: + Field AccessibilityEvent.MAX_TEXT_LENGTH: @Deprecated annotation (present) and @deprecated doc tag (not present) do not match +DeprecationMismatch: android.webkit.WebSettings#getSaveFormData(): + Method android.webkit.WebSettings.getSaveFormData(): @Deprecated annotation (present) and @deprecated doc tag (not present) do not match +DeprecationMismatch: android.webkit.WebView#shouldDelayChildPressedState(): + Method android.webkit.WebView.shouldDelayChildPressedState(): @Deprecated annotation (present) and @deprecated doc tag (not present) do not match +DeprecationMismatch: android.webkit.WebViewDatabase#clearFormData(): + Method android.webkit.WebViewDatabase.clearFormData(): @Deprecated annotation (present) and @deprecated doc tag (not present) do not match +DeprecationMismatch: android.webkit.WebViewDatabase#hasFormData(): + Method android.webkit.WebViewDatabase.hasFormData(): @Deprecated annotation (present) and @deprecated doc tag (not present) do not match +DeprecationMismatch: javax.microedition.khronos.egl.EGL10#eglCreatePixmapSurface(javax.microedition.khronos.egl.EGLDisplay, javax.microedition.khronos.egl.EGLConfig, Object, int[]): + Method javax.microedition.khronos.egl.EGL10.eglCreatePixmapSurface(javax.microedition.khronos.egl.EGLDisplay, javax.microedition.khronos.egl.EGLConfig, Object, int[]): @Deprecated annotation (present) and @deprecated doc tag (not present) do not match + + GenericException: android.app.prediction.AppPredictor#finalize(): Methods must not throw generic exceptions (`java.lang.Throwable`) GenericException: android.hardware.location.ContextHubClient#finalize(): @@ -19,12 +525,16 @@ ListenerLast: android.telephony.satellite.SatelliteManager#stopSatelliteTransmis Listeners should always be at end of argument list (method `stopSatelliteTransmissionUpdates`) ListenerLast: android.telephony.satellite.SatelliteManager#stopSatelliteTransmissionUpdates(android.telephony.satellite.SatelliteTransmissionUpdateCallback, java.util.concurrent.Executor, java.util.function.Consumer<java.lang.Integer>) parameter #2: Listeners should always be at end of argument list (method `stopSatelliteTransmissionUpdates`) + + MissingGetterMatchingBuilder: android.service.voice.HotwordTrainingData.Builder#addTrainingAudio(android.service.voice.HotwordTrainingAudio): android.service.voice.HotwordTrainingData does not declare a `getTrainingAudios()` method matching method android.service.voice.HotwordTrainingData.Builder.addTrainingAudio(android.service.voice.HotwordTrainingAudio) MissingGetterMatchingBuilder: android.telecom.CallScreeningService.CallResponse.Builder#setShouldScreenCallViaAudioProcessing(boolean): android.telecom.CallScreeningService.CallResponse does not declare a `shouldScreenCallViaAudioProcessing()` method matching method android.telecom.CallScreeningService.CallResponse.Builder.setShouldScreenCallViaAudioProcessing(boolean) MissingGetterMatchingBuilder: android.telephony.mbms.DownloadRequest.Builder#setServiceId(String): android.telephony.mbms.DownloadRequest does not declare a `getServiceId()` method matching method android.telephony.mbms.DownloadRequest.Builder.setServiceId(String) + + MissingNullability: android.media.soundtrigger.SoundTriggerDetectionService#onUnbind(android.content.Intent) parameter #0: Missing nullability on parameter `intent` in method `onUnbind` MissingNullability: android.printservice.recommendation.RecommendationService#attachBaseContext(android.content.Context) parameter #0: @@ -57,6 +567,1196 @@ ProtectedMember: android.service.notification.NotificationAssistantService#attac Protected methods not allowed; must be public: method android.service.notification.NotificationAssistantService.attachBaseContext(android.content.Context)} +RequiresPermission: android.accounts.AccountManager#getAccountsByTypeAndFeatures(String, String[], android.accounts.AccountManagerCallback<android.accounts.Account[]>, android.os.Handler): + Method 'getAccountsByTypeAndFeatures' documentation mentions permissions without declaring @RequiresPermission +RequiresPermission: android.accounts.AccountManager#hasFeatures(android.accounts.Account, String[], android.accounts.AccountManagerCallback<java.lang.Boolean>, android.os.Handler): + Method 'hasFeatures' documentation mentions permissions without declaring @RequiresPermission +RequiresPermission: android.app.ActivityManager#addOnUidImportanceListener(android.app.ActivityManager.OnUidImportanceListener, int): + Method 'addOnUidImportanceListener' documentation mentions permissions already declared by @RequiresPermission +RequiresPermission: android.app.ActivityManager#getHistoricalProcessExitReasons(String, int, int): + Method 'getHistoricalProcessExitReasons' documentation mentions permissions without declaring @RequiresPermission +RequiresPermission: android.app.ActivityManager#getProcessesInErrorState(): + Method 'getProcessesInErrorState' documentation mentions permissions without declaring @RequiresPermission +RequiresPermission: android.app.ActivityManager#killProcessesWhenImperceptible(int[], String): + Method 'killProcessesWhenImperceptible' documentation mentions permissions already declared by @RequiresPermission +RequiresPermission: android.app.ActivityManager#setDeviceLocales(android.os.LocaleList): + Method 'setDeviceLocales' documentation mentions permissions without declaring @RequiresPermission +RequiresPermission: android.app.AlarmManager#setAlarmClock(android.app.AlarmManager.AlarmClockInfo, android.app.PendingIntent): + Method 'setAlarmClock' documentation mentions permissions already declared by @RequiresPermission +RequiresPermission: android.app.AlarmManager#setExact(int, long, android.app.PendingIntent): + Method 'setExact' documentation mentions permissions already declared by @RequiresPermission +RequiresPermission: android.app.AlarmManager#setExactAndAllowWhileIdle(int, long, android.app.PendingIntent): + Method 'setExactAndAllowWhileIdle' documentation mentions permissions already declared by @RequiresPermission +RequiresPermission: android.app.AlarmManager#setTime(long): + Method 'setTime' documentation mentions permissions already declared by @RequiresPermission +RequiresPermission: android.app.AppOpsManager#isOpActive(String, int, String): + Method 'isOpActive' documentation mentions permissions without declaring @RequiresPermission +RequiresPermission: android.app.AppOpsManager#startWatchingActive(String[], java.util.concurrent.Executor, android.app.AppOpsManager.OnOpActiveChangedListener): + Method 'startWatchingActive' documentation mentions permissions without declaring @RequiresPermission +RequiresPermission: android.app.AppOpsManager#startWatchingNoted(String[], java.util.concurrent.Executor, android.app.AppOpsManager.OnOpNotedListener): + Method 'startWatchingNoted' documentation mentions permissions already declared by @RequiresPermission +RequiresPermission: android.app.DownloadManager.Request#setDestinationInExternalPublicDir(String, String): + Method 'setDestinationInExternalPublicDir' documentation mentions permissions without declaring @RequiresPermission +RequiresPermission: android.app.DownloadManager.Request#setDestinationUri(android.net.Uri): + Method 'setDestinationUri' documentation mentions permissions without declaring @RequiresPermission +RequiresPermission: android.app.DownloadManager.Request#setNotificationVisibility(int): + Method 'setNotificationVisibility' documentation mentions permissions without declaring @RequiresPermission +RequiresPermission: android.app.DownloadManager.Request#setShowRunningNotification(boolean): + Method 'setShowRunningNotification' documentation mentions permissions without declaring @RequiresPermission +RequiresPermission: android.app.GameManager#setGameMode(String, int): + Method 'setGameMode' documentation mentions permissions already declared by @RequiresPermission +RequiresPermission: android.app.GameManager#updateCustomGameModeConfiguration(String, android.app.GameModeConfiguration): + Method 'updateCustomGameModeConfiguration' documentation mentions permissions already declared by @RequiresPermission +RequiresPermission: android.app.LocaleManager#getApplicationLocales(String): + Method 'getApplicationLocales' documentation mentions permissions already declared by @RequiresPermission +RequiresPermission: android.app.Notification.Builder#setFullScreenIntent(android.app.PendingIntent, boolean): + Method 'setFullScreenIntent' documentation mentions permissions without declaring @RequiresPermission +RequiresPermission: android.app.NotificationManager#canUseFullScreenIntent(): + Method 'canUseFullScreenIntent' documentation mentions permissions without declaring @RequiresPermission +RequiresPermission: android.app.Service#startForeground(int, android.app.Notification): + Method 'startForeground' documentation mentions permissions without declaring @RequiresPermission +RequiresPermission: android.app.StatusBarManager#canLaunchCaptureContentActivityForNote(android.app.Activity): + Method 'canLaunchCaptureContentActivityForNote' documentation mentions permissions already declared by @RequiresPermission +RequiresPermission: android.app.UiModeManager#releaseProjection(int): + Method 'releaseProjection' documentation mentions permissions already declared by @RequiresPermission +RequiresPermission: android.app.UiModeManager#requestProjection(int): + Method 'requestProjection' documentation mentions permissions already declared by @RequiresPermission +RequiresPermission: android.app.WallpaperInfo#getSettingsSliceUri(): + Method 'getSettingsSliceUri' documentation mentions permissions without declaring @RequiresPermission +RequiresPermission: android.app.WallpaperManager#clear(): + Method 'clear' documentation mentions permissions already declared by @RequiresPermission +RequiresPermission: android.app.WallpaperManager#clearWallpaper(int, int): + Method 'clearWallpaper' documentation mentions permissions already declared by @RequiresPermission +RequiresPermission: android.app.WallpaperManager#getDrawable(): + Method 'getDrawable' documentation mentions permissions already declared by @RequiresPermission +RequiresPermission: android.app.WallpaperManager#getDrawable(int): + Method 'getDrawable' documentation mentions permissions already declared by @RequiresPermission +RequiresPermission: android.app.WallpaperManager#getFastDrawable(): + Method 'getFastDrawable' documentation mentions permissions already declared by @RequiresPermission +RequiresPermission: android.app.WallpaperManager#getFastDrawable(int): + Method 'getFastDrawable' documentation mentions permissions already declared by @RequiresPermission +RequiresPermission: android.app.WallpaperManager#getWallpaperFile(int): + Method 'getWallpaperFile' documentation mentions permissions already declared by @RequiresPermission +RequiresPermission: android.app.WallpaperManager#getWallpaperInfo(int): + Method 'getWallpaperInfo' documentation mentions permissions without declaring @RequiresPermission +RequiresPermission: android.app.WallpaperManager#peekDrawable(): + Method 'peekDrawable' documentation mentions permissions already declared by @RequiresPermission +RequiresPermission: android.app.WallpaperManager#peekDrawable(int): + Method 'peekDrawable' documentation mentions permissions already declared by @RequiresPermission +RequiresPermission: android.app.WallpaperManager#peekFastDrawable(): + Method 'peekFastDrawable' documentation mentions permissions already declared by @RequiresPermission +RequiresPermission: android.app.WallpaperManager#peekFastDrawable(int): + Method 'peekFastDrawable' documentation mentions permissions already declared by @RequiresPermission +RequiresPermission: android.app.WallpaperManager#setBitmap(android.graphics.Bitmap): + Method 'setBitmap' documentation mentions permissions already declared by @RequiresPermission +RequiresPermission: android.app.WallpaperManager#setBitmap(android.graphics.Bitmap, android.graphics.Rect, boolean): + Method 'setBitmap' documentation mentions permissions already declared by @RequiresPermission +RequiresPermission: android.app.WallpaperManager#setDisplayPadding(android.graphics.Rect): + Method 'setDisplayPadding' documentation mentions permissions already declared by @RequiresPermission +RequiresPermission: android.app.WallpaperManager#setResource(int): + Method 'setResource' documentation mentions permissions already declared by @RequiresPermission +RequiresPermission: android.app.WallpaperManager#setStream(java.io.InputStream): + Method 'setStream' documentation mentions permissions already declared by @RequiresPermission +RequiresPermission: android.app.WallpaperManager#setStream(java.io.InputStream, android.graphics.Rect, boolean): + Method 'setStream' documentation mentions permissions already declared by @RequiresPermission +RequiresPermission: android.app.WallpaperManager#setWallpaperComponentWithFlags(android.content.ComponentName, int): + Method 'setWallpaperComponentWithFlags' documentation mentions permissions already declared by @RequiresPermission +RequiresPermission: android.app.WallpaperManager#suggestDesiredDimensions(int, int): + Method 'suggestDesiredDimensions' documentation mentions permissions without declaring @RequiresPermission +RequiresPermission: android.app.admin.DevicePolicyManager#addCrossProfileWidgetProvider(android.content.ComponentName, String): + Method 'addCrossProfileWidgetProvider' documentation mentions permissions already declared by @RequiresPermission +RequiresPermission: android.app.admin.DevicePolicyManager#addPersistentPreferredActivity(android.content.ComponentName, android.content.IntentFilter, android.content.ComponentName): + Method 'addPersistentPreferredActivity' documentation mentions permissions already declared by @RequiresPermission +RequiresPermission: android.app.admin.DevicePolicyManager#bindDeviceAdminServiceAsUser(android.content.ComponentName, android.content.Intent, android.content.ServiceConnection, int, android.os.UserHandle): + Method 'bindDeviceAdminServiceAsUser' documentation mentions permissions without declaring @RequiresPermission +RequiresPermission: android.app.admin.DevicePolicyManager#clearPackagePersistentPreferredActivities(android.content.ComponentName, String): + Method 'clearPackagePersistentPreferredActivities' documentation mentions permissions already declared by @RequiresPermission +RequiresPermission: android.app.admin.DevicePolicyManager#clearResetPasswordToken(android.content.ComponentName): + Method 'clearResetPasswordToken' documentation mentions permissions already declared by @RequiresPermission +RequiresPermission: android.app.admin.DevicePolicyManager#createAndProvisionManagedProfile(android.app.admin.ManagedProfileProvisioningParams): + Method 'createAndProvisionManagedProfile' documentation mentions permissions already declared by @RequiresPermission +RequiresPermission: android.app.admin.DevicePolicyManager#finalizeWorkProfileProvisioning(android.os.UserHandle, android.accounts.Account): + Method 'finalizeWorkProfileProvisioning' documentation mentions permissions already declared by @RequiresPermission +RequiresPermission: android.app.admin.DevicePolicyManager#generateKeyPair(android.content.ComponentName, String, android.security.keystore.KeyGenParameterSpec, int): + Method 'generateKeyPair' documentation mentions permissions already declared by @RequiresPermission +RequiresPermission: android.app.admin.DevicePolicyManager#getApplicationExemptions(String): + Method 'getApplicationExemptions' documentation mentions permissions already declared by @RequiresPermission +RequiresPermission: android.app.admin.DevicePolicyManager#getCrossProfileWidgetProviders(android.content.ComponentName): + Method 'getCrossProfileWidgetProviders' documentation mentions permissions already declared by @RequiresPermission +RequiresPermission: android.app.admin.DevicePolicyManager#getLockTaskFeatures(android.content.ComponentName): + Method 'getLockTaskFeatures' documentation mentions permissions already declared by @RequiresPermission +RequiresPermission: android.app.admin.DevicePolicyManager#getLockTaskPackages(android.content.ComponentName): + Method 'getLockTaskPackages' documentation mentions permissions already declared by @RequiresPermission +RequiresPermission: android.app.admin.DevicePolicyManager#getNearbyAppStreamingPolicy(): + Method 'getNearbyAppStreamingPolicy' documentation mentions permissions already declared by @RequiresPermission +RequiresPermission: android.app.admin.DevicePolicyManager#getNearbyNotificationStreamingPolicy(): + Method 'getNearbyNotificationStreamingPolicy' documentation mentions permissions already declared by @RequiresPermission +RequiresPermission: android.app.admin.DevicePolicyManager#getOrganizationName(android.content.ComponentName): + Method 'getOrganizationName' documentation mentions permissions already declared by @RequiresPermission +RequiresPermission: android.app.admin.DevicePolicyManager#getPasswordComplexity(): + Method 'getPasswordComplexity' documentation mentions permissions already declared by @RequiresPermission +RequiresPermission: android.app.admin.DevicePolicyManager#getShortSupportMessage(android.content.ComponentName): + Method 'getShortSupportMessage' documentation mentions permissions already declared by @RequiresPermission +RequiresPermission: android.app.admin.DevicePolicyManager#getUserControlDisabledPackages(android.content.ComponentName): + Method 'getUserControlDisabledPackages' documentation mentions permissions already declared by @RequiresPermission +RequiresPermission: android.app.admin.DevicePolicyManager#hasKeyPair(String): + Method 'hasKeyPair' documentation mentions permissions already declared by @RequiresPermission +RequiresPermission: android.app.admin.DevicePolicyManager#installKeyPair(android.content.ComponentName, java.security.PrivateKey, java.security.cert.Certificate, String): + Method 'installKeyPair' documentation mentions permissions already declared by @RequiresPermission +RequiresPermission: android.app.admin.DevicePolicyManager#installKeyPair(android.content.ComponentName, java.security.PrivateKey, java.security.cert.Certificate[], String, boolean): + Method 'installKeyPair' documentation mentions permissions already declared by @RequiresPermission +RequiresPermission: android.app.admin.DevicePolicyManager#installKeyPair(android.content.ComponentName, java.security.PrivateKey, java.security.cert.Certificate[], String, int): + Method 'installKeyPair' documentation mentions permissions already declared by @RequiresPermission +RequiresPermission: android.app.admin.DevicePolicyManager#isDeviceProvisioningConfigApplied(): + Method 'isDeviceProvisioningConfigApplied' documentation mentions permissions already declared by @RequiresPermission +RequiresPermission: android.app.admin.DevicePolicyManager#isPackageSuspended(android.content.ComponentName, String): + Method 'isPackageSuspended' documentation mentions permissions already declared by @RequiresPermission +RequiresPermission: android.app.admin.DevicePolicyManager#isResetPasswordTokenActive(android.content.ComponentName): + Method 'isResetPasswordTokenActive' documentation mentions permissions already declared by @RequiresPermission +RequiresPermission: android.app.admin.DevicePolicyManager#lockNow(int): + Method 'lockNow' documentation mentions permissions already declared by @RequiresPermission +RequiresPermission: android.app.admin.DevicePolicyManager#provisionFullyManagedDevice(android.app.admin.FullyManagedDeviceProvisioningParams): + Method 'provisionFullyManagedDevice' documentation mentions permissions already declared by @RequiresPermission +RequiresPermission: android.app.admin.DevicePolicyManager#removeCrossProfileWidgetProvider(android.content.ComponentName, String): + Method 'removeCrossProfileWidgetProvider' documentation mentions permissions already declared by @RequiresPermission +RequiresPermission: android.app.admin.DevicePolicyManager#sendLostModeLocationUpdate(java.util.concurrent.Executor, java.util.function.Consumer<java.lang.Boolean>): + Method 'sendLostModeLocationUpdate' documentation mentions permissions already declared by @RequiresPermission +RequiresPermission: android.app.admin.DevicePolicyManager#setActiveProfileOwner(android.content.ComponentName, String): + Method 'setActiveProfileOwner' documentation mentions permissions already declared by @RequiresPermission +RequiresPermission: android.app.admin.DevicePolicyManager#setAlwaysOnVpnPackage(android.content.ComponentName, String, boolean): + Method 'setAlwaysOnVpnPackage' documentation mentions permissions without declaring @RequiresPermission +RequiresPermission: android.app.admin.DevicePolicyManager#setApplicationExemptions(String, java.util.Set<java.lang.Integer>): + Method 'setApplicationExemptions' documentation mentions permissions already declared by @RequiresPermission +RequiresPermission: android.app.admin.DevicePolicyManager#setDeviceProvisioningConfigApplied(): + Method 'setDeviceProvisioningConfigApplied' documentation mentions permissions already declared by @RequiresPermission +RequiresPermission: android.app.admin.DevicePolicyManager#setLockTaskFeatures(android.content.ComponentName, int): + Method 'setLockTaskFeatures' documentation mentions permissions already declared by @RequiresPermission +RequiresPermission: android.app.admin.DevicePolicyManager#setLockTaskPackages(android.content.ComponentName, String[]): + Method 'setLockTaskPackages' documentation mentions permissions already declared by @RequiresPermission +RequiresPermission: android.app.admin.DevicePolicyManager#setPermittedInputMethods(android.content.ComponentName, java.util.List<java.lang.String>): + Method 'setPermittedInputMethods' documentation mentions permissions already declared by @RequiresPermission +RequiresPermission: android.app.admin.DevicePolicyManager#setUninstallBlocked(android.content.ComponentName, String, boolean): + Method 'setUninstallBlocked' documentation mentions permissions already declared by @RequiresPermission +RequiresPermission: android.app.admin.DevicePolicyManager#setUserControlDisabledPackages(android.content.ComponentName, java.util.List<java.lang.String>): + Method 'setUserControlDisabledPackages' documentation mentions permissions already declared by @RequiresPermission +RequiresPermission: android.app.admin.DevicePolicyManager#wipeData(int): + Method 'wipeData' documentation mentions permissions already declared by @RequiresPermission +RequiresPermission: android.app.admin.DevicePolicyManager#wipeData(int, CharSequence): + Method 'wipeData' documentation mentions permissions already declared by @RequiresPermission +RequiresPermission: android.app.admin.DevicePolicyManager#wipeDevice(int): + Method 'wipeDevice' documentation mentions permissions already declared by @RequiresPermission +RequiresPermission: android.app.admin.PolicyUpdateReceiver#onPolicyChanged(android.content.Context, String, android.os.Bundle, android.app.admin.TargetUser, android.app.admin.PolicyUpdateResult): + Method 'onPolicyChanged' documentation mentions permissions without declaring @RequiresPermission +RequiresPermission: android.app.admin.PolicyUpdateReceiver#onPolicySetResult(android.content.Context, String, android.os.Bundle, android.app.admin.TargetUser, android.app.admin.PolicyUpdateResult): + Method 'onPolicySetResult' documentation mentions permissions without declaring @RequiresPermission +RequiresPermission: android.app.backup.BackupManager#dataChanged(String): + Method 'dataChanged' documentation mentions permissions without declaring @RequiresPermission +RequiresPermission: android.app.backup.BackupManager#requestBackup(String[], android.app.backup.BackupObserver, android.app.backup.BackupManagerMonitor, int): + Method 'requestBackup' documentation mentions permissions already declared by @RequiresPermission +RequiresPermission: android.app.backup.BackupManager#setFrameworkSchedulingEnabled(boolean): + Method 'setFrameworkSchedulingEnabled' documentation mentions permissions already declared by @RequiresPermission +RequiresPermission: android.app.backup.BackupManager#updateTransportAttributes(android.content.ComponentName, String, android.content.Intent, String, android.content.Intent, CharSequence): + Method 'updateTransportAttributes' documentation mentions permissions already declared by @RequiresPermission +RequiresPermission: android.app.backup.BackupManager#updateTransportAttributes(android.content.ComponentName, String, android.content.Intent, String, android.content.Intent, String): + Method 'updateTransportAttributes' documentation mentions permissions already declared by @RequiresPermission +RequiresPermission: android.app.backup.RestoreSession#restoreAll(long, android.app.backup.RestoreObserver): + Method 'restoreAll' documentation mentions permissions without declaring @RequiresPermission +RequiresPermission: android.app.backup.RestoreSession#restoreAll(long, android.app.backup.RestoreObserver, android.app.backup.BackupManagerMonitor): + Method 'restoreAll' documentation mentions permissions without declaring @RequiresPermission +RequiresPermission: android.app.backup.RestoreSession#restorePackage(String, android.app.backup.RestoreObserver): + Method 'restorePackage' documentation mentions permissions without declaring @RequiresPermission +RequiresPermission: android.app.backup.RestoreSession#restorePackage(String, android.app.backup.RestoreObserver, android.app.backup.BackupManagerMonitor): + Method 'restorePackage' documentation mentions permissions without declaring @RequiresPermission +RequiresPermission: android.app.backup.RestoreSession#restorePackages(long, android.app.backup.RestoreObserver, java.util.Set<java.lang.String>): + Method 'restorePackages' documentation mentions permissions without declaring @RequiresPermission +RequiresPermission: android.app.backup.RestoreSession#restorePackages(long, android.app.backup.RestoreObserver, java.util.Set<java.lang.String>, android.app.backup.BackupManagerMonitor): + Method 'restorePackages' documentation mentions permissions without declaring @RequiresPermission +RequiresPermission: android.app.job.JobInfo.Builder#setRequiredNetwork(android.net.NetworkRequest): + Method 'setRequiredNetwork' documentation mentions permissions without declaring @RequiresPermission +RequiresPermission: android.app.job.JobInfo.Builder#setRequiredNetworkType(int): + Method 'setRequiredNetworkType' documentation mentions permissions without declaring @RequiresPermission +RequiresPermission: android.app.job.JobInfo.Builder#setUserInitiated(boolean): + Method 'setUserInitiated' documentation mentions permissions already declared by @RequiresPermission +RequiresPermission: android.app.job.JobParameters#isUserInitiatedJob(): + Method 'isUserInitiatedJob' documentation mentions permissions without declaring @RequiresPermission +RequiresPermission: android.app.job.JobScheduler#canRunUserInitiatedJobs(): + Method 'canRunUserInitiatedJobs' documentation mentions permissions without declaring @RequiresPermission +RequiresPermission: android.app.people.PeopleManager#isConversation(String, String): + Method 'isConversation' documentation mentions permissions already declared by @RequiresPermission +RequiresPermission: android.app.usage.StorageStatsManager#queryExternalStatsForUser(java.util.UUID, android.os.UserHandle): + Method 'queryExternalStatsForUser' documentation mentions permissions without declaring @RequiresPermission +RequiresPermission: android.app.usage.StorageStatsManager#queryStatsForPackage(java.util.UUID, String, android.os.UserHandle): + Method 'queryStatsForPackage' documentation mentions permissions without declaring @RequiresPermission +RequiresPermission: android.app.usage.StorageStatsManager#queryStatsForUid(java.util.UUID, int): + Method 'queryStatsForUid' documentation mentions permissions without declaring @RequiresPermission +RequiresPermission: android.app.usage.StorageStatsManager#queryStatsForUser(java.util.UUID, android.os.UserHandle): + Method 'queryStatsForUser' documentation mentions permissions without declaring @RequiresPermission +RequiresPermission: android.app.usage.UsageEvents.Event#getTaskRootClassName(): + Method 'getTaskRootClassName' documentation mentions permissions without declaring @RequiresPermission +RequiresPermission: android.app.usage.UsageEvents.Event#getTaskRootPackageName(): + Method 'getTaskRootPackageName' documentation mentions permissions without declaring @RequiresPermission +RequiresPermission: android.app.usage.UsageStatsManager#getAppStandbyBucket(String): + Method 'getAppStandbyBucket' documentation mentions permissions already declared by @RequiresPermission +RequiresPermission: android.app.usage.UsageStatsManager#getAppStandbyBuckets(): + Method 'getAppStandbyBuckets' documentation mentions permissions already declared by @RequiresPermission +RequiresPermission: android.app.usage.UsageStatsManager#isAppInactive(String): + Method 'isAppInactive' documentation mentions permissions without declaring @RequiresPermission +RequiresPermission: android.app.usage.UsageStatsManager#onCarrierPrivilegedAppsChanged(): + Method 'onCarrierPrivilegedAppsChanged' documentation mentions permissions already declared by @RequiresPermission +RequiresPermission: android.app.usage.UsageStatsManager#queryAndAggregateUsageStats(long, long): + Method 'queryAndAggregateUsageStats' documentation mentions permissions without declaring @RequiresPermission +RequiresPermission: android.app.usage.UsageStatsManager#queryConfigurations(int, long, long): + Method 'queryConfigurations' documentation mentions permissions without declaring @RequiresPermission +RequiresPermission: android.app.usage.UsageStatsManager#queryEventStats(int, long, long): + Method 'queryEventStats' documentation mentions permissions without declaring @RequiresPermission +RequiresPermission: android.app.usage.UsageStatsManager#queryEvents(long, long): + Method 'queryEvents' documentation mentions permissions without declaring @RequiresPermission +RequiresPermission: android.app.usage.UsageStatsManager#queryUsageStats(int, long, long): + Method 'queryUsageStats' documentation mentions permissions without declaring @RequiresPermission +RequiresPermission: android.app.usage.UsageStatsManager#registerAppUsageLimitObserver(int, String[], java.time.Duration, java.time.Duration, android.app.PendingIntent): + Method 'registerAppUsageLimitObserver' documentation mentions permissions already declared by @RequiresPermission +RequiresPermission: android.app.usage.UsageStatsManager#registerAppUsageObserver(int, String[], long, java.util.concurrent.TimeUnit, android.app.PendingIntent): + Method 'registerAppUsageObserver' documentation mentions permissions already declared by @RequiresPermission +RequiresPermission: android.app.usage.UsageStatsManager#registerUsageSessionObserver(int, String[], java.time.Duration, java.time.Duration, android.app.PendingIntent, android.app.PendingIntent): + Method 'registerUsageSessionObserver' documentation mentions permissions already declared by @RequiresPermission +RequiresPermission: android.app.usage.UsageStatsManager#reportUsageStart(android.app.Activity, String): + Method 'reportUsageStart' documentation mentions permissions without declaring @RequiresPermission +RequiresPermission: android.app.usage.UsageStatsManager#reportUsageStart(android.app.Activity, String, long): + Method 'reportUsageStart' documentation mentions permissions without declaring @RequiresPermission +RequiresPermission: android.app.usage.UsageStatsManager#unregisterAppUsageLimitObserver(int): + Method 'unregisterAppUsageLimitObserver' documentation mentions permissions already declared by @RequiresPermission +RequiresPermission: android.app.usage.UsageStatsManager#unregisterAppUsageObserver(int): + Method 'unregisterAppUsageObserver' documentation mentions permissions already declared by @RequiresPermission +RequiresPermission: android.app.usage.UsageStatsManager#unregisterUsageSessionObserver(int): + Method 'unregisterUsageSessionObserver' documentation mentions permissions already declared by @RequiresPermission +RequiresPermission: android.appwidget.AppWidgetManager#bindAppWidgetIdIfAllowed(int, android.os.UserHandle, android.content.ComponentName, android.os.Bundle): + Method 'bindAppWidgetIdIfAllowed' documentation mentions permissions without declaring @RequiresPermission +RequiresPermission: android.companion.CompanionDeviceManager#isDeviceAssociatedForWifiConnection(String, android.net.MacAddress, android.os.UserHandle): + Method 'isDeviceAssociatedForWifiConnection' documentation mentions permissions already declared by @RequiresPermission +RequiresPermission: android.companion.CompanionDeviceManager#startObservingDevicePresence(String): + Method 'startObservingDevicePresence' documentation mentions permissions already declared by @RequiresPermission +RequiresPermission: android.companion.CompanionDeviceManager#stopObservingDevicePresence(String): + Method 'stopObservingDevicePresence' documentation mentions permissions already declared by @RequiresPermission +RequiresPermission: android.companion.virtual.VirtualDeviceManager#createVirtualDevice(int, android.companion.virtual.VirtualDeviceParams): + Method 'createVirtualDevice' documentation mentions permissions already declared by @RequiresPermission +RequiresPermission: android.companion.virtual.VirtualDeviceParams.Builder#setLockState(int): + Method 'setLockState' documentation mentions permissions already declared by @RequiresPermission +RequiresPermission: android.content.ContentResolver#addPeriodicSync(android.accounts.Account, String, android.os.Bundle, long): + Method 'addPeriodicSync' documentation mentions permissions without declaring @RequiresPermission +RequiresPermission: android.content.ContentResolver#cancelSync(android.content.SyncRequest): + Method 'cancelSync' documentation mentions permissions without declaring @RequiresPermission +RequiresPermission: android.content.ContentResolver#getCurrentSync(): + Method 'getCurrentSync' documentation mentions permissions without declaring @RequiresPermission +RequiresPermission: android.content.ContentResolver#getCurrentSyncs(): + Method 'getCurrentSyncs' documentation mentions permissions without declaring @RequiresPermission +RequiresPermission: android.content.ContentResolver#getIsSyncable(android.accounts.Account, String): + Method 'getIsSyncable' documentation mentions permissions without declaring @RequiresPermission +RequiresPermission: android.content.ContentResolver#getMasterSyncAutomatically(): + Method 'getMasterSyncAutomatically' documentation mentions permissions without declaring @RequiresPermission +RequiresPermission: android.content.ContentResolver#getPeriodicSyncs(android.accounts.Account, String): + Method 'getPeriodicSyncs' documentation mentions permissions without declaring @RequiresPermission +RequiresPermission: android.content.ContentResolver#getSyncAutomatically(android.accounts.Account, String): + Method 'getSyncAutomatically' documentation mentions permissions without declaring @RequiresPermission +RequiresPermission: android.content.ContentResolver#isSyncActive(android.accounts.Account, String): + Method 'isSyncActive' documentation mentions permissions without declaring @RequiresPermission +RequiresPermission: android.content.ContentResolver#isSyncPending(android.accounts.Account, String): + Method 'isSyncPending' documentation mentions permissions without declaring @RequiresPermission +RequiresPermission: android.content.ContentResolver#removePeriodicSync(android.accounts.Account, String, android.os.Bundle): + Method 'removePeriodicSync' documentation mentions permissions without declaring @RequiresPermission +RequiresPermission: android.content.ContentResolver#setIsSyncable(android.accounts.Account, String, int): + Method 'setIsSyncable' documentation mentions permissions without declaring @RequiresPermission +RequiresPermission: android.content.ContentResolver#setMasterSyncAutomatically(boolean): + Method 'setMasterSyncAutomatically' documentation mentions permissions without declaring @RequiresPermission +RequiresPermission: android.content.ContentResolver#setSyncAutomatically(android.accounts.Account, String, boolean): + Method 'setSyncAutomatically' documentation mentions permissions without declaring @RequiresPermission +RequiresPermission: android.content.Context#bindServiceAsUser(android.content.Intent, android.content.ServiceConnection, int, android.os.UserHandle): + Method 'bindServiceAsUser' documentation mentions permissions already declared by @RequiresPermission +RequiresPermission: android.content.Context#clearWallpaper(): + Method 'clearWallpaper' documentation mentions permissions without declaring @RequiresPermission +RequiresPermission: android.content.Context#getExternalCacheDir(): + Method 'getExternalCacheDir' documentation mentions permissions without declaring @RequiresPermission +RequiresPermission: android.content.Context#getExternalCacheDirs(): + Method 'getExternalCacheDirs' documentation mentions permissions without declaring @RequiresPermission +RequiresPermission: android.content.Context#getExternalFilesDir(String): + Method 'getExternalFilesDir' documentation mentions permissions without declaring @RequiresPermission +RequiresPermission: android.content.Context#getExternalFilesDirs(String): + Method 'getExternalFilesDirs' documentation mentions permissions without declaring @RequiresPermission +RequiresPermission: android.content.Context#getExternalMediaDirs(): + Method 'getExternalMediaDirs' documentation mentions permissions without declaring @RequiresPermission +RequiresPermission: android.content.Context#getObbDir(): + Method 'getObbDir' documentation mentions permissions without declaring @RequiresPermission +RequiresPermission: android.content.Context#getObbDirs(): + Method 'getObbDirs' documentation mentions permissions without declaring @RequiresPermission +RequiresPermission: android.content.Context#removeStickyBroadcastAsUser(android.content.Intent, android.os.UserHandle): + Method 'removeStickyBroadcastAsUser' documentation mentions permissions already declared by @RequiresPermission +RequiresPermission: android.content.Context#setWallpaper(android.graphics.Bitmap): + Method 'setWallpaper' documentation mentions permissions without declaring @RequiresPermission +RequiresPermission: android.content.Context#setWallpaper(java.io.InputStream): + Method 'setWallpaper' documentation mentions permissions without declaring @RequiresPermission +RequiresPermission: android.content.pm.CrossProfileApps#canRequestInteractAcrossProfiles(): + Method 'canRequestInteractAcrossProfiles' documentation mentions permissions without declaring @RequiresPermission +RequiresPermission: android.content.pm.CrossProfileApps#startActivity(android.content.ComponentName, android.os.UserHandle): + Method 'startActivity' documentation mentions permissions already declared by @RequiresPermission +RequiresPermission: android.content.pm.CrossProfileApps#startActivity(android.content.ComponentName, android.os.UserHandle, android.app.Activity, android.os.Bundle): + Method 'startActivity' documentation mentions permissions already declared by @RequiresPermission +RequiresPermission: android.content.pm.CrossProfileApps#startActivity(android.content.Intent, android.os.UserHandle, android.app.Activity): + Method 'startActivity' documentation mentions permissions already declared by @RequiresPermission +RequiresPermission: android.content.pm.CrossProfileApps#startActivity(android.content.Intent, android.os.UserHandle, android.app.Activity, android.os.Bundle): + Method 'startActivity' documentation mentions permissions already declared by @RequiresPermission +RequiresPermission: android.content.pm.LauncherApps#getAllPackageInstallerSessions(): + Method 'getAllPackageInstallerSessions' documentation mentions permissions without declaring @RequiresPermission +RequiresPermission: android.content.pm.LauncherApps#registerPackageInstallerSessionCallback(java.util.concurrent.Executor, android.content.pm.PackageInstaller.SessionCallback): + Method 'registerPackageInstallerSessionCallback' documentation mentions permissions without declaring @RequiresPermission +RequiresPermission: android.content.pm.LauncherApps.Callback#onPackagesSuspended(String[], android.os.UserHandle, android.os.Bundle): + Method 'onPackagesSuspended' documentation mentions permissions without declaring @RequiresPermission +RequiresPermission: android.content.pm.PackageInstaller#getAllSessions(): + Method 'getAllSessions' documentation mentions permissions without declaring @RequiresPermission +RequiresPermission: android.content.pm.PackageInstaller#getSessionInfo(int): + Method 'getSessionInfo' documentation mentions permissions without declaring @RequiresPermission +RequiresPermission: android.content.pm.PackageInstaller#getStagedSessions(): + Method 'getStagedSessions' documentation mentions permissions without declaring @RequiresPermission +RequiresPermission: android.content.pm.PackageInstaller#registerSessionCallback(android.content.pm.PackageInstaller.SessionCallback): + Method 'registerSessionCallback' documentation mentions permissions without declaring @RequiresPermission +RequiresPermission: android.content.pm.PackageInstaller.Session#requestUserPreapproval(android.content.pm.PackageInstaller.PreapprovalDetails, android.content.IntentSender): + Method 'requestUserPreapproval' documentation mentions permissions without declaring @RequiresPermission +RequiresPermission: android.content.pm.PackageInstaller.SessionParams#setInstallerPackageName(String): + Method 'setInstallerPackageName' documentation mentions permissions without declaring @RequiresPermission +RequiresPermission: android.content.pm.PackageInstaller.SessionParams#setPermissionState(String, int): + Method 'setPermissionState' documentation mentions permissions already declared by @RequiresPermission +RequiresPermission: android.content.pm.PackageInstaller.SessionParams#setRequestUpdateOwnership(boolean): + Method 'setRequestUpdateOwnership' documentation mentions permissions already declared by @RequiresPermission +RequiresPermission: android.content.pm.PackageInstaller.SessionParams#setRequireUserAction(int): + Method 'setRequireUserAction' documentation mentions permissions without declaring @RequiresPermission +RequiresPermission: android.content.pm.PackageManager#canRequestPackageInstalls(): + Method 'canRequestPackageInstalls' documentation mentions permissions without declaring @RequiresPermission +RequiresPermission: android.content.pm.PackageManager#getSuspendedPackageAppExtras(): + Method 'getSuspendedPackageAppExtras' documentation mentions permissions without declaring @RequiresPermission +RequiresPermission: android.content.pm.PackageManager#getUnsuspendablePackages(String[]): + Method 'getUnsuspendablePackages' documentation mentions permissions already declared by @RequiresPermission +RequiresPermission: android.content.pm.PackageManager#grantRuntimePermission(String, String, android.os.UserHandle): + Method 'grantRuntimePermission' documentation mentions permissions already declared by @RequiresPermission +RequiresPermission: android.content.pm.PackageManager#isAutoRevokeWhitelisted(String): + Method 'isAutoRevokeWhitelisted' documentation mentions permissions already declared by @RequiresPermission +RequiresPermission: android.content.pm.PackageManager#isPackageSuspended(): + Method 'isPackageSuspended' documentation mentions permissions without declaring @RequiresPermission +RequiresPermission: android.content.pm.PackageManager#revokeRuntimePermission(String, String, android.os.UserHandle): + Method 'revokeRuntimePermission' documentation mentions permissions already declared by @RequiresPermission +RequiresPermission: android.content.pm.PackageManager#revokeRuntimePermission(String, String, android.os.UserHandle, String): + Method 'revokeRuntimePermission' documentation mentions permissions already declared by @RequiresPermission +RequiresPermission: android.content.pm.PackageManager#setDistractingPackageRestrictions(String[], int): + Method 'setDistractingPackageRestrictions' documentation mentions permissions already declared by @RequiresPermission +RequiresPermission: android.content.pm.PackageManager#setPackagesSuspended(String[], boolean, android.os.PersistableBundle, android.os.PersistableBundle, String): + Method 'setPackagesSuspended' documentation mentions permissions already declared by @RequiresPermission +RequiresPermission: android.content.pm.PackageManager#setPackagesSuspended(String[], boolean, android.os.PersistableBundle, android.os.PersistableBundle, android.content.pm.SuspendDialogInfo): + Method 'setPackagesSuspended' documentation mentions permissions already declared by @RequiresPermission +RequiresPermission: android.content.pm.PackageManager#setPackagesSuspended(String[], boolean, android.os.PersistableBundle, android.os.PersistableBundle, android.content.pm.SuspendDialogInfo, int): + Method 'setPackagesSuspended' documentation mentions permissions already declared by @RequiresPermission +RequiresPermission: android.content.pm.PackageManager#verifyIntentFilter(int, int, java.util.List<java.lang.String>): + Method 'verifyIntentFilter' documentation mentions permissions already declared by @RequiresPermission +RequiresPermission: android.hardware.Sensor#getHighestDirectReportRateLevel(): + Method 'getHighestDirectReportRateLevel' documentation mentions permissions without declaring @RequiresPermission +RequiresPermission: android.hardware.Sensor#getMinDelay(): + Method 'getMinDelay' documentation mentions permissions without declaring @RequiresPermission +RequiresPermission: android.hardware.camera2.CameraCharacteristics#getKeysNeedingPermission(): + Method 'getKeysNeedingPermission' documentation mentions permissions without declaring @RequiresPermission +RequiresPermission: android.hardware.camera2.CameraManager.AvailabilityCallback#onCameraClosed(String): + Method 'onCameraClosed' documentation mentions permissions already declared by @RequiresPermission +RequiresPermission: android.hardware.camera2.CameraManager.AvailabilityCallback#onCameraOpened(String, String): + Method 'onCameraOpened' documentation mentions permissions already declared by @RequiresPermission +RequiresPermission: android.hardware.hdmi.HdmiControlManager#getHdmiCecVersion(): + Method 'getHdmiCecVersion' documentation mentions permissions already declared by @RequiresPermission +RequiresPermission: android.hardware.hdmi.HdmiControlManager#setHdmiCecVersion(int): + Method 'setHdmiCecVersion' documentation mentions permissions already declared by @RequiresPermission +RequiresPermission: android.hardware.location.GeofenceHardware#addGeofence(int, int, android.hardware.location.GeofenceHardwareRequest, android.hardware.location.GeofenceHardwareCallback): + Method 'addGeofence' documentation mentions permissions without declaring @RequiresPermission +RequiresPermission: android.hardware.location.GeofenceHardware#getMonitoringTypes(): + Method 'getMonitoringTypes' documentation mentions permissions without declaring @RequiresPermission +RequiresPermission: android.hardware.location.GeofenceHardware#pauseGeofence(int, int): + Method 'pauseGeofence' documentation mentions permissions without declaring @RequiresPermission +RequiresPermission: android.hardware.location.GeofenceHardware#registerForMonitorStateChangeCallback(int, android.hardware.location.GeofenceHardwareMonitorCallback): + Method 'registerForMonitorStateChangeCallback' documentation mentions permissions without declaring @RequiresPermission +RequiresPermission: android.hardware.location.GeofenceHardware#removeGeofence(int, int): + Method 'removeGeofence' documentation mentions permissions without declaring @RequiresPermission +RequiresPermission: android.hardware.location.GeofenceHardware#resumeGeofence(int, int, int): + Method 'resumeGeofence' documentation mentions permissions without declaring @RequiresPermission +RequiresPermission: android.hardware.location.GeofenceHardware#unregisterForMonitorStateChangeCallback(int, android.hardware.location.GeofenceHardwareMonitorCallback): + Method 'unregisterForMonitorStateChangeCallback' documentation mentions permissions without declaring @RequiresPermission +RequiresPermission: android.hardware.usb.UsbManager#grantPermission(android.hardware.usb.UsbDevice, String): + Method 'grantPermission' documentation mentions permissions already declared by @RequiresPermission +RequiresPermission: android.hardware.usb.UsbManager#hasPermission(android.hardware.usb.UsbDevice): + Method 'hasPermission' documentation mentions permissions without declaring @RequiresPermission +RequiresPermission: android.hardware.usb.UsbManager#requestPermission(android.hardware.usb.UsbDevice, android.app.PendingIntent): + Method 'requestPermission' documentation mentions permissions without declaring @RequiresPermission +RequiresPermission: android.media.AudioAttributes.Builder#setHapticChannelsMuted(boolean): + Method 'setHapticChannelsMuted' documentation mentions permissions without declaring @RequiresPermission +RequiresPermission: android.media.AudioManager#getCallDownlinkExtractionAudioRecord(android.media.AudioFormat): + Method 'getCallDownlinkExtractionAudioRecord' documentation mentions permissions already declared by @RequiresPermission +RequiresPermission: android.media.AudioManager#getCallUplinkInjectionAudioTrack(android.media.AudioFormat): + Method 'getCallUplinkInjectionAudioTrack' documentation mentions permissions already declared by @RequiresPermission +RequiresPermission: android.media.AudioManager#registerAudioPolicy(android.media.audiopolicy.AudioPolicy): + Method 'registerAudioPolicy' documentation mentions permissions already declared by @RequiresPermission +RequiresPermission: android.media.AudioRecord#shareAudioHistory(String, long): + Method 'shareAudioHistory' documentation mentions permissions already declared by @RequiresPermission +RequiresPermission: android.media.AudioRecordingConfiguration#getClientUid(): + Method 'getClientUid' documentation mentions permissions already declared by @RequiresPermission +RequiresPermission: android.media.MediaCodec#createByCodecNameForClient(String, int, int): + Method 'createByCodecNameForClient' documentation mentions permissions already declared by @RequiresPermission +RequiresPermission: android.media.MediaExtractor#setDataSource(String): + Method 'setDataSource' documentation mentions permissions without declaring @RequiresPermission +RequiresPermission: android.media.MediaExtractor#setDataSource(String, java.util.Map<java.lang.String,java.lang.String>): + Method 'setDataSource' documentation mentions permissions without declaring @RequiresPermission +RequiresPermission: android.media.MediaExtractor#setDataSource(android.content.Context, android.net.Uri, java.util.Map<java.lang.String,java.lang.String>): + Method 'setDataSource' documentation mentions permissions without declaring @RequiresPermission +RequiresPermission: android.media.MediaPlayer#setWakeMode(android.content.Context, int): + Method 'setWakeMode' documentation mentions permissions without declaring @RequiresPermission +RequiresPermission: android.media.MediaRouter2#getInstance(android.content.Context, String): + Method 'getInstance' documentation mentions permissions already declared by @RequiresPermission +RequiresPermission: android.media.RingtoneManager#getCursor(): + Method 'getCursor' documentation mentions permissions without declaring @RequiresPermission +RequiresPermission: android.media.RingtoneManager#getValidRingtoneUri(android.content.Context): + Method 'getValidRingtoneUri' documentation mentions permissions without declaring @RequiresPermission +RequiresPermission: android.media.audiofx.HapticGenerator#setEnabled(boolean): + Method 'setEnabled' documentation mentions permissions without declaring @RequiresPermission +RequiresPermission: android.media.projection.MediaProjection#createVirtualDisplay(String, int, int, int, int, android.view.Surface, android.hardware.display.VirtualDisplay.Callback, android.os.Handler): + Method 'createVirtualDisplay' documentation mentions permissions without declaring @RequiresPermission +RequiresPermission: android.media.projection.MediaProjectionManager#getMediaProjection(int, android.content.Intent): + Method 'getMediaProjection' documentation mentions permissions without declaring @RequiresPermission +RequiresPermission: android.media.session.MediaSessionManager#addOnActiveSessionsChangedListener(android.media.session.MediaSessionManager.OnActiveSessionsChangedListener, android.content.ComponentName): + Method 'addOnActiveSessionsChangedListener' documentation mentions permissions without declaring @RequiresPermission +RequiresPermission: android.media.session.MediaSessionManager#addOnActiveSessionsChangedListener(android.media.session.MediaSessionManager.OnActiveSessionsChangedListener, android.content.ComponentName, android.os.Handler): + Method 'addOnActiveSessionsChangedListener' documentation mentions permissions without declaring @RequiresPermission +RequiresPermission: android.media.session.MediaSessionManager#addOnMediaKeyEventSessionChangedListener(java.util.concurrent.Executor, android.media.session.MediaSessionManager.OnMediaKeyEventSessionChangedListener): + Method 'addOnMediaKeyEventSessionChangedListener' documentation mentions permissions without declaring @RequiresPermission +RequiresPermission: android.media.session.MediaSessionManager#getActiveSessions(android.content.ComponentName): + Method 'getActiveSessions' documentation mentions permissions without declaring @RequiresPermission +RequiresPermission: android.media.session.MediaSessionManager#getMediaKeyEventSession(): + Method 'getMediaKeyEventSession' documentation mentions permissions without declaring @RequiresPermission +RequiresPermission: android.media.session.MediaSessionManager#getMediaKeyEventSessionPackageName(): + Method 'getMediaKeyEventSessionPackageName' documentation mentions permissions without declaring @RequiresPermission +RequiresPermission: android.media.session.MediaSessionManager#isTrustedForMediaControl(android.media.session.MediaSessionManager.RemoteUserInfo): + Method 'isTrustedForMediaControl' documentation mentions permissions without declaring @RequiresPermission +RequiresPermission: android.media.voice.KeyphraseModelManager#deleteKeyphraseSoundModel(int, java.util.Locale): + Method 'deleteKeyphraseSoundModel' documentation mentions permissions already declared by @RequiresPermission +RequiresPermission: android.media.voice.KeyphraseModelManager#getKeyphraseSoundModel(int, java.util.Locale): + Method 'getKeyphraseSoundModel' documentation mentions permissions already declared by @RequiresPermission +RequiresPermission: android.media.voice.KeyphraseModelManager#updateKeyphraseSoundModel(android.hardware.soundtrigger.SoundTrigger.KeyphraseSoundModel): + Method 'updateKeyphraseSoundModel' documentation mentions permissions already declared by @RequiresPermission +RequiresPermission: android.net.NetworkScoreManager#clearScores(): + Method 'clearScores' documentation mentions permissions already declared by @RequiresPermission +RequiresPermission: android.net.NetworkScoreManager#disableScoring(): + Method 'disableScoring' documentation mentions permissions already declared by @RequiresPermission +RequiresPermission: android.net.NetworkScoreManager#getActiveScorerPackage(): + Method 'getActiveScorerPackage' documentation mentions permissions already declared by @RequiresPermission +RequiresPermission: android.net.NetworkScoreManager#registerNetworkScoreCallback(int, int, java.util.concurrent.Executor, android.net.NetworkScoreManager.NetworkScoreCallback): + Method 'registerNetworkScoreCallback' documentation mentions permissions already declared by @RequiresPermission +RequiresPermission: android.net.NetworkScoreManager#requestScores(java.util.Collection<android.net.NetworkKey>): + Method 'requestScores' documentation mentions permissions already declared by @RequiresPermission +RequiresPermission: android.net.NetworkScoreManager#setActiveScorer(String): + Method 'setActiveScorer' documentation mentions permissions already declared by @RequiresPermission +RequiresPermission: android.net.VpnService#prepareAndAuthorize(android.content.Context): + Method 'prepareAndAuthorize' documentation mentions permissions already declared by @RequiresPermission +RequiresPermission: android.net.sip.SipAudioCall#setSpeakerMode(boolean): + Method 'setSpeakerMode' documentation mentions permissions without declaring @RequiresPermission +RequiresPermission: android.net.sip.SipAudioCall#startAudio(): + Method 'startAudio' documentation mentions permissions without declaring @RequiresPermission +RequiresPermission: android.net.vcn.VcnManager#addVcnNetworkPolicyChangeListener(java.util.concurrent.Executor, android.net.vcn.VcnManager.VcnNetworkPolicyChangeListener): + Method 'addVcnNetworkPolicyChangeListener' documentation mentions permissions already declared by @RequiresPermission +RequiresPermission: android.net.vcn.VcnManager#applyVcnNetworkPolicy(android.net.NetworkCapabilities, android.net.LinkProperties): + Method 'applyVcnNetworkPolicy' documentation mentions permissions already declared by @RequiresPermission +RequiresPermission: android.net.vcn.VcnManager#removeVcnNetworkPolicyChangeListener(android.net.vcn.VcnManager.VcnNetworkPolicyChangeListener): + Method 'removeVcnNetworkPolicyChangeListener' documentation mentions permissions already declared by @RequiresPermission +RequiresPermission: android.nfc.NfcAdapter#disableForegroundDispatch(android.app.Activity): + Method 'disableForegroundDispatch' documentation mentions permissions without declaring @RequiresPermission +RequiresPermission: android.nfc.NfcAdapter#enableForegroundDispatch(android.app.Activity, android.app.PendingIntent, android.content.IntentFilter[], String[][]): + Method 'enableForegroundDispatch' documentation mentions permissions without declaring @RequiresPermission +RequiresPermission: android.nfc.cardemulation.CardEmulation#isDefaultServiceForAid(android.content.ComponentName, String): + Method 'isDefaultServiceForAid' documentation mentions permissions without declaring @RequiresPermission +RequiresPermission: android.nfc.cardemulation.CardEmulation#isDefaultServiceForCategory(android.content.ComponentName, String): + Method 'isDefaultServiceForCategory' documentation mentions permissions without declaring @RequiresPermission +RequiresPermission: android.nfc.cardemulation.CardEmulation#setOffHostForService(android.content.ComponentName, String): + Method 'setOffHostForService' documentation mentions permissions already declared by @RequiresPermission +RequiresPermission: android.nfc.tech.IsoDep#getTimeout(): + Method 'getTimeout' documentation mentions permissions without declaring @RequiresPermission +RequiresPermission: android.nfc.tech.IsoDep#setTimeout(int): + Method 'setTimeout' documentation mentions permissions without declaring @RequiresPermission +RequiresPermission: android.nfc.tech.IsoDep#transceive(byte[]): + Method 'transceive' documentation mentions permissions without declaring @RequiresPermission +RequiresPermission: android.nfc.tech.MifareClassic#authenticateSectorWithKeyA(int, byte[]): + Method 'authenticateSectorWithKeyA' documentation mentions permissions without declaring @RequiresPermission +RequiresPermission: android.nfc.tech.MifareClassic#authenticateSectorWithKeyB(int, byte[]): + Method 'authenticateSectorWithKeyB' documentation mentions permissions without declaring @RequiresPermission +RequiresPermission: android.nfc.tech.MifareClassic#decrement(int, int): + Method 'decrement' documentation mentions permissions without declaring @RequiresPermission +RequiresPermission: android.nfc.tech.MifareClassic#getTimeout(): + Method 'getTimeout' documentation mentions permissions without declaring @RequiresPermission +RequiresPermission: android.nfc.tech.MifareClassic#increment(int, int): + Method 'increment' documentation mentions permissions without declaring @RequiresPermission +RequiresPermission: android.nfc.tech.MifareClassic#readBlock(int): + Method 'readBlock' documentation mentions permissions without declaring @RequiresPermission +RequiresPermission: android.nfc.tech.MifareClassic#restore(int): + Method 'restore' documentation mentions permissions without declaring @RequiresPermission +RequiresPermission: android.nfc.tech.MifareClassic#setTimeout(int): + Method 'setTimeout' documentation mentions permissions without declaring @RequiresPermission +RequiresPermission: android.nfc.tech.MifareClassic#transceive(byte[]): + Method 'transceive' documentation mentions permissions without declaring @RequiresPermission +RequiresPermission: android.nfc.tech.MifareClassic#transfer(int): + Method 'transfer' documentation mentions permissions without declaring @RequiresPermission +RequiresPermission: android.nfc.tech.MifareClassic#writeBlock(int, byte[]): + Method 'writeBlock' documentation mentions permissions without declaring @RequiresPermission +RequiresPermission: android.nfc.tech.MifareUltralight#getTimeout(): + Method 'getTimeout' documentation mentions permissions without declaring @RequiresPermission +RequiresPermission: android.nfc.tech.MifareUltralight#readPages(int): + Method 'readPages' documentation mentions permissions without declaring @RequiresPermission +RequiresPermission: android.nfc.tech.MifareUltralight#setTimeout(int): + Method 'setTimeout' documentation mentions permissions without declaring @RequiresPermission +RequiresPermission: android.nfc.tech.MifareUltralight#transceive(byte[]): + Method 'transceive' documentation mentions permissions without declaring @RequiresPermission +RequiresPermission: android.nfc.tech.MifareUltralight#writePage(int, byte[]): + Method 'writePage' documentation mentions permissions without declaring @RequiresPermission +RequiresPermission: android.nfc.tech.Ndef#getNdefMessage(): + Method 'getNdefMessage' documentation mentions permissions without declaring @RequiresPermission +RequiresPermission: android.nfc.tech.Ndef#isWritable(): + Method 'isWritable' documentation mentions permissions without declaring @RequiresPermission +RequiresPermission: android.nfc.tech.Ndef#makeReadOnly(): + Method 'makeReadOnly' documentation mentions permissions without declaring @RequiresPermission +RequiresPermission: android.nfc.tech.Ndef#writeNdefMessage(android.nfc.NdefMessage): + Method 'writeNdefMessage' documentation mentions permissions without declaring @RequiresPermission +RequiresPermission: android.nfc.tech.NdefFormatable#format(android.nfc.NdefMessage): + Method 'format' documentation mentions permissions without declaring @RequiresPermission +RequiresPermission: android.nfc.tech.NdefFormatable#formatReadOnly(android.nfc.NdefMessage): + Method 'formatReadOnly' documentation mentions permissions without declaring @RequiresPermission +RequiresPermission: android.nfc.tech.NfcA#getTimeout(): + Method 'getTimeout' documentation mentions permissions without declaring @RequiresPermission +RequiresPermission: android.nfc.tech.NfcA#setTimeout(int): + Method 'setTimeout' documentation mentions permissions without declaring @RequiresPermission +RequiresPermission: android.nfc.tech.NfcA#transceive(byte[]): + Method 'transceive' documentation mentions permissions without declaring @RequiresPermission +RequiresPermission: android.nfc.tech.NfcB#transceive(byte[]): + Method 'transceive' documentation mentions permissions without declaring @RequiresPermission +RequiresPermission: android.nfc.tech.NfcF#getTimeout(): + Method 'getTimeout' documentation mentions permissions without declaring @RequiresPermission +RequiresPermission: android.nfc.tech.NfcF#setTimeout(int): + Method 'setTimeout' documentation mentions permissions without declaring @RequiresPermission +RequiresPermission: android.nfc.tech.NfcF#transceive(byte[]): + Method 'transceive' documentation mentions permissions without declaring @RequiresPermission +RequiresPermission: android.nfc.tech.NfcV#transceive(byte[]): + Method 'transceive' documentation mentions permissions without declaring @RequiresPermission +RequiresPermission: android.nfc.tech.TagTechnology#close(): + Method 'close' documentation mentions permissions without declaring @RequiresPermission +RequiresPermission: android.nfc.tech.TagTechnology#connect(): + Method 'connect' documentation mentions permissions without declaring @RequiresPermission +RequiresPermission: android.os.BugreportManager#cancelBugreport(): + Method 'cancelBugreport' documentation mentions permissions without declaring @RequiresPermission +RequiresPermission: android.os.BugreportManager#preDumpUiData(): + Method 'preDumpUiData' documentation mentions permissions already declared by @RequiresPermission +RequiresPermission: android.os.Build#getSerial(): + Method 'getSerial' documentation mentions permissions already declared by @RequiresPermission +RequiresPermission: android.os.Debug#dumpService(String, java.io.FileDescriptor, String[]): + Method 'dumpService' documentation mentions permissions without declaring @RequiresPermission +RequiresPermission: android.os.DropBoxManager#getNextEntry(String, long): + Method 'getNextEntry' documentation mentions permissions already declared by @RequiresPermission +RequiresPermission: android.os.Environment#getExternalStorageDirectory(): + Method 'getExternalStorageDirectory' documentation mentions permissions without declaring @RequiresPermission +RequiresPermission: android.os.Environment#isExternalStorageManager(): + Method 'isExternalStorageManager' documentation mentions permissions without declaring @RequiresPermission +RequiresPermission: android.os.Environment#isExternalStorageManager(java.io.File): + Method 'isExternalStorageManager' documentation mentions permissions without declaring @RequiresPermission +RequiresPermission: android.os.PowerManager#dream(long): + Method 'dream' documentation mentions permissions already declared by @RequiresPermission +RequiresPermission: android.os.PowerManager#forceSuspend(): + Method 'forceSuspend' documentation mentions permissions already declared by @RequiresPermission +RequiresPermission: android.os.PowerManager#getPowerSaveModeTrigger(): + Method 'getPowerSaveModeTrigger' documentation mentions permissions without declaring @RequiresPermission +RequiresPermission: android.os.PowerManager#newWakeLock(int, String): + Method 'newWakeLock' documentation mentions permissions without declaring @RequiresPermission +RequiresPermission: android.os.PowerManager#reboot(String): + Method 'reboot' documentation mentions permissions already declared by @RequiresPermission +RequiresPermission: android.os.PowerManager#setBatteryDischargePrediction(java.time.Duration, boolean): + Method 'setBatteryDischargePrediction' documentation mentions permissions already declared by @RequiresPermission +RequiresPermission: android.os.PowerManager#setDynamicPowerSaveHint(boolean, int): + Method 'setDynamicPowerSaveHint' documentation mentions permissions already declared by @RequiresPermission +RequiresPermission: android.os.PowerManager#userActivity(long, int, int): + Method 'userActivity' documentation mentions permissions already declared by @RequiresPermission +RequiresPermission: android.os.RecoverySystem#rebootWipeUserData(android.content.Context): + Method 'rebootWipeUserData' documentation mentions permissions without declaring @RequiresPermission +RequiresPermission: android.os.StrictMode.VmPolicy.Builder#detectFileUriExposure(): + Method 'detectFileUriExposure' documentation mentions permissions without declaring @RequiresPermission +RequiresPermission: android.os.SystemUpdateManager#retrieveSystemUpdateInfo(): + Method 'retrieveSystemUpdateInfo' documentation mentions permissions already declared by @RequiresPermission +RequiresPermission: android.os.SystemUpdateManager#updateSystemUpdateInfo(android.os.PersistableBundle): + Method 'updateSystemUpdateInfo' documentation mentions permissions already declared by @RequiresPermission +RequiresPermission: android.os.UserManager#getUserProperties(android.os.UserHandle): + Method 'getUserProperties' documentation mentions permissions already declared by @RequiresPermission +RequiresPermission: android.os.UserManager#getUserRestrictions(android.os.UserHandle): + Method 'getUserRestrictions' documentation mentions permissions already declared by @RequiresPermission +RequiresPermission: android.os.UserManager#hasUserRestrictionForUser(String, android.os.UserHandle): + Method 'hasUserRestrictionForUser' documentation mentions permissions already declared by @RequiresPermission +RequiresPermission: android.os.UserManager#isManagedProfile(int): + Method 'isManagedProfile' documentation mentions permissions already declared by @RequiresPermission +RequiresPermission: android.os.UserManager#isRestrictedProfile(): + Method 'isRestrictedProfile' documentation mentions permissions without declaring @RequiresPermission +RequiresPermission: android.os.UserManager#isRestrictedProfile(android.os.UserHandle): + Method 'isRestrictedProfile' documentation mentions permissions already declared by @RequiresPermission +RequiresPermission: android.os.UserManager#isUserUnlocked(android.os.UserHandle): + Method 'isUserUnlocked' documentation mentions permissions already declared by @RequiresPermission +RequiresPermission: android.os.UserManager#isUserUnlockingOrUnlocked(android.os.UserHandle): + Method 'isUserUnlockingOrUnlocked' documentation mentions permissions already declared by @RequiresPermission +RequiresPermission: android.os.UserManager#requestQuietModeEnabled(boolean, android.os.UserHandle): + Method 'requestQuietModeEnabled' documentation mentions permissions already declared by @RequiresPermission +RequiresPermission: android.os.UserManager#setUserRestriction(String, boolean): + Method 'setUserRestriction' documentation mentions permissions already declared by @RequiresPermission +RequiresPermission: android.os.health.SystemHealthManager#takeUidSnapshot(int): + Method 'takeUidSnapshot' documentation mentions permissions without declaring @RequiresPermission +RequiresPermission: android.os.health.SystemHealthManager#takeUidSnapshots(int[]): + Method 'takeUidSnapshots' documentation mentions permissions without declaring @RequiresPermission +RequiresPermission: android.os.storage.StorageManager#getManageSpaceActivityIntent(String, int): + Method 'getManageSpaceActivityIntent' documentation mentions permissions already declared by @RequiresPermission +RequiresPermission: android.os.storage.StorageVolume#createAccessIntent(String): + Method 'createAccessIntent' documentation mentions permissions without declaring @RequiresPermission +RequiresPermission: android.permission.PermissionManager#checkPermissionForDataDelivery(String, android.content.AttributionSource, String): + Method 'checkPermissionForDataDelivery' documentation mentions permissions already declared by @RequiresPermission +RequiresPermission: android.permission.PermissionManager#checkPermissionForDataDeliveryFromDataSource(String, android.content.AttributionSource, String): + Method 'checkPermissionForDataDeliveryFromDataSource' documentation mentions permissions already declared by @RequiresPermission +RequiresPermission: android.permission.PermissionManager#checkPermissionForStartDataDelivery(String, android.content.AttributionSource, String): + Method 'checkPermissionForStartDataDelivery' documentation mentions permissions already declared by @RequiresPermission +RequiresPermission: android.provider.Settings#canDrawOverlays(android.content.Context): + Method 'canDrawOverlays' documentation mentions permissions without declaring @RequiresPermission +RequiresPermission: android.provider.Settings.System#canWrite(android.content.Context): + Method 'canWrite' documentation mentions permissions without declaring @RequiresPermission +RequiresPermission: android.security.KeyChain#removeCredentialManagementApp(android.content.Context): + Method 'removeCredentialManagementApp' documentation mentions permissions already declared by @RequiresPermission +RequiresPermission: android.service.credentials.BeginCreateCredentialResponse.Builder#setRemoteCreateEntry(android.service.credentials.RemoteEntry): + Method 'setRemoteCreateEntry' documentation mentions permissions already declared by @RequiresPermission +RequiresPermission: android.service.credentials.BeginGetCredentialResponse.Builder#setRemoteCredentialEntry(android.service.credentials.RemoteEntry): + Method 'setRemoteCredentialEntry' documentation mentions permissions already declared by @RequiresPermission +RequiresPermission: android.service.credentials.CallingAppInfo#getOrigin(): + Method 'getOrigin' documentation mentions permissions without declaring @RequiresPermission +RequiresPermission: android.telecom.Call.Details#getContactDisplayName(): + Method 'getContactDisplayName' documentation mentions permissions without declaring @RequiresPermission +RequiresPermission: android.telecom.Call.Details#getContactPhotoUri(): + Method 'getContactPhotoUri' documentation mentions permissions without declaring @RequiresPermission +RequiresPermission: android.telecom.TelecomManager#acceptHandover(android.net.Uri, int, android.telecom.PhoneAccountHandle): + Method 'acceptHandover' documentation mentions permissions without declaring @RequiresPermission +RequiresPermission: android.telecom.TelecomManager#addNewIncomingCall(android.telecom.PhoneAccountHandle, android.os.Bundle): + Method 'addNewIncomingCall' documentation mentions permissions without declaring @RequiresPermission +RequiresPermission: android.telecom.TelecomManager#addNewIncomingConference(android.telecom.PhoneAccountHandle, android.os.Bundle): + Method 'addNewIncomingConference' documentation mentions permissions without declaring @RequiresPermission +RequiresPermission: android.telecom.TelecomManager#getCallState(): + Method 'getCallState' documentation mentions permissions already declared by @RequiresPermission +RequiresPermission: android.telecom.TelecomManager#getLine1Number(android.telecom.PhoneAccountHandle): + Method 'getLine1Number' documentation mentions permissions already declared by @RequiresPermission +RequiresPermission: android.telecom.TelecomManager#getOwnSelfManagedPhoneAccounts(): + Method 'getOwnSelfManagedPhoneAccounts' documentation mentions permissions already declared by @RequiresPermission +RequiresPermission: android.telecom.TelecomManager#getPhoneAccount(android.telecom.PhoneAccountHandle): + Method 'getPhoneAccount' documentation mentions permissions without declaring @RequiresPermission +RequiresPermission: android.telecom.TelecomManager#getSelfManagedPhoneAccounts(): + Method 'getSelfManagedPhoneAccounts' documentation mentions permissions already declared by @RequiresPermission +RequiresPermission: android.telecom.TelecomManager#hasManageOngoingCallsPermission(): + Method 'hasManageOngoingCallsPermission' documentation mentions permissions without declaring @RequiresPermission +RequiresPermission: android.telecom.TelecomManager#placeCall(android.net.Uri, android.os.Bundle): + Method 'placeCall' documentation mentions permissions already declared by @RequiresPermission +RequiresPermission: android.telecom.TelecomManager#showInCallScreen(boolean): + Method 'showInCallScreen' documentation mentions permissions already declared by @RequiresPermission +RequiresPermission: android.telecom.TelecomManager#silenceRinger(): + Method 'silenceRinger' documentation mentions permissions already declared by @RequiresPermission +RequiresPermission: android.telephony.CarrierConfigManager#getConfig(): + Method 'getConfig' documentation mentions permissions already declared by @RequiresPermission +RequiresPermission: android.telephony.CarrierConfigManager#getConfig(java.lang.String...): + Method 'getConfig' documentation mentions permissions already declared by @RequiresPermission +RequiresPermission: android.telephony.CarrierConfigManager#getConfigByComponentForSubId(String, int): + Method 'getConfigByComponentForSubId' documentation mentions permissions already declared by @RequiresPermission +RequiresPermission: android.telephony.CarrierConfigManager#getConfigForSubId(int): + Method 'getConfigForSubId' documentation mentions permissions already declared by @RequiresPermission +RequiresPermission: android.telephony.CarrierConfigManager#getConfigForSubId(int, java.lang.String...): + Method 'getConfigForSubId' documentation mentions permissions already declared by @RequiresPermission +RequiresPermission: android.telephony.CarrierConfigManager#notifyConfigChangedForSubId(int): + Method 'notifyConfigChangedForSubId' documentation mentions permissions already declared by @RequiresPermission +RequiresPermission: android.telephony.CellLocation#requestLocationUpdate(): + Method 'requestLocationUpdate' documentation mentions permissions without declaring @RequiresPermission +RequiresPermission: android.telephony.NetworkRegistrationInfo#getCellIdentity(): + Method 'getCellIdentity' documentation mentions permissions without declaring @RequiresPermission +RequiresPermission: android.telephony.PhoneStateListener#onActiveDataSubscriptionIdChanged(int): + Method 'onActiveDataSubscriptionIdChanged' documentation mentions permissions already declared by @RequiresPermission +RequiresPermission: android.telephony.PhoneStateListener#onCallAttributesChanged(android.telephony.CallAttributes): + Method 'onCallAttributesChanged' documentation mentions permissions already declared by @RequiresPermission +RequiresPermission: android.telephony.PhoneStateListener#onCallStateChanged(int, String): + Method 'onCallStateChanged' documentation mentions permissions already declared by @RequiresPermission +RequiresPermission: android.telephony.PhoneStateListener#onDisplayInfoChanged(android.telephony.TelephonyDisplayInfo): + Method 'onDisplayInfoChanged' documentation mentions permissions already declared by @RequiresPermission +RequiresPermission: android.telephony.PhoneStateListener#onPreciseDataConnectionStateChanged(android.telephony.PreciseDataConnectionState): + Method 'onPreciseDataConnectionStateChanged' documentation mentions permissions already declared by @RequiresPermission +RequiresPermission: android.telephony.PhoneStateListener#onRadioPowerStateChanged(int): + Method 'onRadioPowerStateChanged' documentation mentions permissions already declared by @RequiresPermission +RequiresPermission: android.telephony.PhoneStateListener#onServiceStateChanged(android.telephony.ServiceState): + Method 'onServiceStateChanged' documentation mentions permissions without declaring @RequiresPermission +RequiresPermission: android.telephony.ServiceState#getCdmaNetworkId(): + Method 'getCdmaNetworkId' documentation mentions permissions already declared by @RequiresPermission +RequiresPermission: android.telephony.ServiceState#getCdmaSystemId(): + Method 'getCdmaSystemId' documentation mentions permissions already declared by @RequiresPermission +RequiresPermission: android.telephony.ServiceState#getOperatorAlphaLong(): + Method 'getOperatorAlphaLong' documentation mentions permissions already declared by @RequiresPermission +RequiresPermission: android.telephony.ServiceState#getOperatorAlphaShort(): + Method 'getOperatorAlphaShort' documentation mentions permissions already declared by @RequiresPermission +RequiresPermission: android.telephony.ServiceState#getOperatorNumeric(): + Method 'getOperatorNumeric' documentation mentions permissions already declared by @RequiresPermission +RequiresPermission: android.telephony.SignalStrengthUpdateRequest.Builder#setSystemThresholdReportingRequestedWhileIdle(boolean): + Method 'setSystemThresholdReportingRequestedWhileIdle' documentation mentions permissions already declared by @RequiresPermission +RequiresPermission: android.telephony.SmsManager#disableCellBroadcastRange(int, int, int): + Method 'disableCellBroadcastRange' documentation mentions permissions without declaring @RequiresPermission +RequiresPermission: android.telephony.SmsManager#enableCellBroadcastRange(int, int, int): + Method 'enableCellBroadcastRange' documentation mentions permissions without declaring @RequiresPermission +RequiresPermission: android.telephony.SmsManager#getSmscAddress(): + Method 'getSmscAddress' documentation mentions permissions already declared by @RequiresPermission +RequiresPermission: android.telephony.SmsManager#injectSmsPdu(byte[], String, android.app.PendingIntent): + Method 'injectSmsPdu' documentation mentions permissions without declaring @RequiresPermission +RequiresPermission: android.telephony.SmsManager#sendDataMessage(String, String, short, byte[], android.app.PendingIntent, android.app.PendingIntent): + Method 'sendDataMessage' documentation mentions permissions without declaring @RequiresPermission +RequiresPermission: android.telephony.SmsManager#sendMultipartTextMessage(String, String, java.util.ArrayList<java.lang.String>, java.util.ArrayList<android.app.PendingIntent>, java.util.ArrayList<android.app.PendingIntent>): + Method 'sendMultipartTextMessage' documentation mentions permissions without declaring @RequiresPermission +RequiresPermission: android.telephony.SmsManager#sendMultipartTextMessageWithoutPersisting(String, String, java.util.List<java.lang.String>, java.util.List<android.app.PendingIntent>, java.util.List<android.app.PendingIntent>): + Method 'sendMultipartTextMessageWithoutPersisting' documentation mentions permissions already declared by @RequiresPermission +RequiresPermission: android.telephony.SmsManager#sendTextMessage(String, String, String, android.app.PendingIntent, android.app.PendingIntent): + Method 'sendTextMessage' documentation mentions permissions without declaring @RequiresPermission +RequiresPermission: android.telephony.SmsManager#sendTextMessageWithoutPersisting(String, String, String, android.app.PendingIntent, android.app.PendingIntent): + Method 'sendTextMessageWithoutPersisting' documentation mentions permissions already declared by @RequiresPermission +RequiresPermission: android.telephony.SmsManager#setSmscAddress(String): + Method 'setSmscAddress' documentation mentions permissions already declared by @RequiresPermission +RequiresPermission: android.telephony.SubscriptionManager#addSubscriptionsIntoGroup(java.util.List<java.lang.Integer>, android.os.ParcelUuid): + Method 'addSubscriptionsIntoGroup' documentation mentions permissions already declared by @RequiresPermission +RequiresPermission: android.telephony.SubscriptionManager#createSubscriptionGroup(java.util.List<java.lang.Integer>): + Method 'createSubscriptionGroup' documentation mentions permissions already declared by @RequiresPermission +RequiresPermission: android.telephony.SubscriptionManager#getActiveSubscriptionInfo(int): + Method 'getActiveSubscriptionInfo' documentation mentions permissions already declared by @RequiresPermission +RequiresPermission: android.telephony.SubscriptionManager#getActiveSubscriptionInfoForSimSlotIndex(int): + Method 'getActiveSubscriptionInfoForSimSlotIndex' documentation mentions permissions already declared by @RequiresPermission +RequiresPermission: android.telephony.SubscriptionManager#getActiveSubscriptionInfoList(): + Method 'getActiveSubscriptionInfoList' documentation mentions permissions already declared by @RequiresPermission +RequiresPermission: android.telephony.SubscriptionManager#getAvailableSubscriptionInfoList(): + Method 'getAvailableSubscriptionInfoList' documentation mentions permissions without declaring @RequiresPermission +RequiresPermission: android.telephony.SubscriptionManager#getCompleteActiveSubscriptionInfoList(): + Method 'getCompleteActiveSubscriptionInfoList' documentation mentions permissions without declaring @RequiresPermission +RequiresPermission: android.telephony.SubscriptionManager#getOpportunisticSubscriptions(): + Method 'getOpportunisticSubscriptions' documentation mentions permissions already declared by @RequiresPermission +RequiresPermission: android.telephony.SubscriptionManager#getResourcesForSubId(android.content.Context, int): + Method 'getResourcesForSubId' documentation mentions permissions without declaring @RequiresPermission +RequiresPermission: android.telephony.SubscriptionManager#getSubscriptionsInGroup(android.os.ParcelUuid): + Method 'getSubscriptionsInGroup' documentation mentions permissions already declared by @RequiresPermission +RequiresPermission: android.telephony.SubscriptionManager#removeSubscriptionsFromGroup(java.util.List<java.lang.Integer>, android.os.ParcelUuid): + Method 'removeSubscriptionsFromGroup' documentation mentions permissions already declared by @RequiresPermission +RequiresPermission: android.telephony.SubscriptionManager#requestEmbeddedSubscriptionInfoListRefresh(): + Method 'requestEmbeddedSubscriptionInfoListRefresh' documentation mentions permissions without declaring @RequiresPermission +RequiresPermission: android.telephony.SubscriptionManager#requestEmbeddedSubscriptionInfoListRefresh(int): + Method 'requestEmbeddedSubscriptionInfoListRefresh' documentation mentions permissions without declaring @RequiresPermission +RequiresPermission: android.telephony.SubscriptionManager#setOpportunistic(boolean, int): + Method 'setOpportunistic' documentation mentions permissions already declared by @RequiresPermission +RequiresPermission: android.telephony.SubscriptionManager#setPreferredDataSubscriptionId(int, boolean, java.util.concurrent.Executor, java.util.function.Consumer<java.lang.Integer>): + Method 'setPreferredDataSubscriptionId' documentation mentions permissions already declared by @RequiresPermission +RequiresPermission: android.telephony.TelephonyCallback.ActiveDataSubscriptionIdListener#onActiveDataSubscriptionIdChanged(int): + Method 'onActiveDataSubscriptionIdChanged' documentation mentions permissions already declared by @RequiresPermission +RequiresPermission: android.telephony.TelephonyCallback.BarringInfoListener#onBarringInfoChanged(android.telephony.BarringInfo): + Method 'onBarringInfoChanged' documentation mentions permissions already declared by @RequiresPermission +RequiresPermission: android.telephony.TelephonyCallback.CallAttributesListener#onCallAttributesChanged(android.telephony.CallAttributes): + Method 'onCallAttributesChanged' documentation mentions permissions already declared by @RequiresPermission +RequiresPermission: android.telephony.TelephonyCallback.CallAttributesListener#onCallStatesChanged(java.util.List<android.telephony.CallState>): + Method 'onCallStatesChanged' documentation mentions permissions already declared by @RequiresPermission +RequiresPermission: android.telephony.TelephonyCallback.CallForwardingIndicatorListener#onCallForwardingIndicatorChanged(boolean): + Method 'onCallForwardingIndicatorChanged' documentation mentions permissions already declared by @RequiresPermission +RequiresPermission: android.telephony.TelephonyCallback.DataEnabledListener#onDataEnabledChanged(boolean, int): + Method 'onDataEnabledChanged' documentation mentions permissions already declared by @RequiresPermission +RequiresPermission: android.telephony.TelephonyCallback.EmergencyNumberListListener#onEmergencyNumberListChanged(java.util.Map<java.lang.Integer,java.util.List<android.telephony.emergency.EmergencyNumber>>): + Method 'onEmergencyNumberListChanged' documentation mentions permissions already declared by @RequiresPermission +RequiresPermission: android.telephony.TelephonyCallback.ImsCallDisconnectCauseListener#onImsCallDisconnectCauseChanged(android.telephony.ims.ImsReasonInfo): + Method 'onImsCallDisconnectCauseChanged' documentation mentions permissions already declared by @RequiresPermission +RequiresPermission: android.telephony.TelephonyCallback.MessageWaitingIndicatorListener#onMessageWaitingIndicatorChanged(boolean): + Method 'onMessageWaitingIndicatorChanged' documentation mentions permissions already declared by @RequiresPermission +RequiresPermission: android.telephony.TelephonyCallback.PhysicalChannelConfigListener#onPhysicalChannelConfigChanged(java.util.List<android.telephony.PhysicalChannelConfig>): + Method 'onPhysicalChannelConfigChanged' documentation mentions permissions already declared by @RequiresPermission +RequiresPermission: android.telephony.TelephonyCallback.PreciseCallStateListener#onPreciseCallStateChanged(android.telephony.PreciseCallState): + Method 'onPreciseCallStateChanged' documentation mentions permissions already declared by @RequiresPermission +RequiresPermission: android.telephony.TelephonyCallback.PreciseDataConnectionStateListener#onPreciseDataConnectionStateChanged(android.telephony.PreciseDataConnectionState): + Method 'onPreciseDataConnectionStateChanged' documentation mentions permissions already declared by @RequiresPermission +RequiresPermission: android.telephony.TelephonyCallback.RegistrationFailedListener#onRegistrationFailed(android.telephony.CellIdentity, String, int, int, int): + Method 'onRegistrationFailed' documentation mentions permissions already declared by @RequiresPermission +RequiresPermission: android.telephony.TelephonyCallback.ServiceStateListener#onServiceStateChanged(android.telephony.ServiceState): + Method 'onServiceStateChanged' documentation mentions permissions without declaring @RequiresPermission +RequiresPermission: android.telephony.TelephonyManager#bootstrapAuthenticationRequest(int, android.net.Uri, android.telephony.gba.UaSecurityProtocolIdentifier, boolean, java.util.concurrent.Executor, android.telephony.TelephonyManager.BootstrapAuthenticationCallback): + Method 'bootstrapAuthenticationRequest' documentation mentions permissions already declared by @RequiresPermission +RequiresPermission: android.telephony.TelephonyManager#changeIccLockPin(String, String): + Method 'changeIccLockPin' documentation mentions permissions already declared by @RequiresPermission +RequiresPermission: android.telephony.TelephonyManager#clearRadioPowerOffForReason(int): + Method 'clearRadioPowerOffForReason' documentation mentions permissions already declared by @RequiresPermission +RequiresPermission: android.telephony.TelephonyManager#clearSignalStrengthUpdateRequest(android.telephony.SignalStrengthUpdateRequest): + Method 'clearSignalStrengthUpdateRequest' documentation mentions permissions already declared by @RequiresPermission +RequiresPermission: android.telephony.TelephonyManager#doesSwitchMultiSimConfigTriggerReboot(): + Method 'doesSwitchMultiSimConfigTriggerReboot' documentation mentions permissions already declared by @RequiresPermission +RequiresPermission: android.telephony.TelephonyManager#enableModemForSlot(int, boolean): + Method 'enableModemForSlot' documentation mentions permissions already declared by @RequiresPermission +RequiresPermission: android.telephony.TelephonyManager#getAidForAppType(int): + Method 'getAidForAppType' documentation mentions permissions already declared by @RequiresPermission +RequiresPermission: android.telephony.TelephonyManager#getAllowedNetworkTypes(): + Method 'getAllowedNetworkTypes' documentation mentions permissions already declared by @RequiresPermission +RequiresPermission: android.telephony.TelephonyManager#getAllowedNetworkTypesBitmask(): + Method 'getAllowedNetworkTypesBitmask' documentation mentions permissions already declared by @RequiresPermission +RequiresPermission: android.telephony.TelephonyManager#getAllowedNetworkTypesForReason(int): + Method 'getAllowedNetworkTypesForReason' documentation mentions permissions already declared by @RequiresPermission +RequiresPermission: android.telephony.TelephonyManager#getCallState(): + Method 'getCallState' documentation mentions permissions already declared by @RequiresPermission +RequiresPermission: android.telephony.TelephonyManager#getCallStateForSubscription(): + Method 'getCallStateForSubscription' documentation mentions permissions already declared by @RequiresPermission +RequiresPermission: android.telephony.TelephonyManager#getCarrierConfig(): + Method 'getCarrierConfig' documentation mentions permissions already declared by @RequiresPermission +RequiresPermission: android.telephony.TelephonyManager#getCarrierInfoForImsiEncryption(int): + Method 'getCarrierInfoForImsiEncryption' documentation mentions permissions already declared by @RequiresPermission +RequiresPermission: android.telephony.TelephonyManager#getCarrierRestrictionStatus(java.util.concurrent.Executor, java.util.function.Consumer<java.lang.Integer>): + Method 'getCarrierRestrictionStatus' documentation mentions permissions already declared by @RequiresPermission +RequiresPermission: android.telephony.TelephonyManager#getCdmaRoamingMode(): + Method 'getCdmaRoamingMode' documentation mentions permissions already declared by @RequiresPermission +RequiresPermission: android.telephony.TelephonyManager#getCdmaSubscriptionMode(): + Method 'getCdmaSubscriptionMode' documentation mentions permissions already declared by @RequiresPermission +RequiresPermission: android.telephony.TelephonyManager#getDataActivationState(): + Method 'getDataActivationState' documentation mentions permissions already declared by @RequiresPermission +RequiresPermission: android.telephony.TelephonyManager#getDataNetworkType(): + Method 'getDataNetworkType' documentation mentions permissions already declared by @RequiresPermission +RequiresPermission: android.telephony.TelephonyManager#getDeviceId(): + Method 'getDeviceId' documentation mentions permissions already declared by @RequiresPermission +RequiresPermission: android.telephony.TelephonyManager#getDeviceId(int): + Method 'getDeviceId' documentation mentions permissions already declared by @RequiresPermission +RequiresPermission: android.telephony.TelephonyManager#getDeviceSoftwareVersion(int): + Method 'getDeviceSoftwareVersion' documentation mentions permissions already declared by @RequiresPermission +RequiresPermission: android.telephony.TelephonyManager#getEmergencyNumberDbVersion(): + Method 'getEmergencyNumberDbVersion' documentation mentions permissions already declared by @RequiresPermission +RequiresPermission: android.telephony.TelephonyManager#getEmergencyNumberList(): + Method 'getEmergencyNumberList' documentation mentions permissions already declared by @RequiresPermission +RequiresPermission: android.telephony.TelephonyManager#getEmergencyNumberList(int): + Method 'getEmergencyNumberList' documentation mentions permissions already declared by @RequiresPermission +RequiresPermission: android.telephony.TelephonyManager#getEquivalentHomePlmns(): + Method 'getEquivalentHomePlmns' documentation mentions permissions already declared by @RequiresPermission +RequiresPermission: android.telephony.TelephonyManager#getForbiddenPlmns(): + Method 'getForbiddenPlmns' documentation mentions permissions already declared by @RequiresPermission +RequiresPermission: android.telephony.TelephonyManager#getGroupIdLevel1(): + Method 'getGroupIdLevel1' documentation mentions permissions already declared by @RequiresPermission +RequiresPermission: android.telephony.TelephonyManager#getImei(int): + Method 'getImei' documentation mentions permissions already declared by @RequiresPermission +RequiresPermission: android.telephony.TelephonyManager#getIsimDomain(): + Method 'getIsimDomain' documentation mentions permissions already declared by @RequiresPermission +RequiresPermission: android.telephony.TelephonyManager#getLine1Number(): + Method 'getLine1Number' documentation mentions permissions already declared by @RequiresPermission +RequiresPermission: android.telephony.TelephonyManager#getManualNetworkSelectionPlmn(): + Method 'getManualNetworkSelectionPlmn' documentation mentions permissions already declared by @RequiresPermission +RequiresPermission: android.telephony.TelephonyManager#getMeid(): + Method 'getMeid' documentation mentions permissions already declared by @RequiresPermission +RequiresPermission: android.telephony.TelephonyManager#getMeid(int): + Method 'getMeid' documentation mentions permissions already declared by @RequiresPermission +RequiresPermission: android.telephony.TelephonyManager#getNai(): + Method 'getNai' documentation mentions permissions already declared by @RequiresPermission +RequiresPermission: android.telephony.TelephonyManager#getNetworkSelectionMode(): + Method 'getNetworkSelectionMode' documentation mentions permissions already declared by @RequiresPermission +RequiresPermission: android.telephony.TelephonyManager#getNetworkSlicingConfiguration(java.util.concurrent.Executor, android.os.OutcomeReceiver<android.telephony.data.NetworkSlicingConfig,android.telephony.TelephonyManager.NetworkSlicingException>): + Method 'getNetworkSlicingConfiguration' documentation mentions permissions already declared by @RequiresPermission +RequiresPermission: android.telephony.TelephonyManager#getPhoneAccountHandle(): + Method 'getPhoneAccountHandle' documentation mentions permissions already declared by @RequiresPermission +RequiresPermission: android.telephony.TelephonyManager#getPreferredNetworkTypeBitmask(): + Method 'getPreferredNetworkTypeBitmask' documentation mentions permissions already declared by @RequiresPermission +RequiresPermission: android.telephony.TelephonyManager#getPreferredOpportunisticDataSubscription(): + Method 'getPreferredOpportunisticDataSubscription' documentation mentions permissions already declared by @RequiresPermission +RequiresPermission: android.telephony.TelephonyManager#getRadioPowerOffReasons(): + Method 'getRadioPowerOffReasons' documentation mentions permissions already declared by @RequiresPermission +RequiresPermission: android.telephony.TelephonyManager#getRadioPowerState(): + Method 'getRadioPowerState' documentation mentions permissions already declared by @RequiresPermission +RequiresPermission: android.telephony.TelephonyManager#getServiceState(): + Method 'getServiceState' documentation mentions permissions already declared by @RequiresPermission +RequiresPermission: android.telephony.TelephonyManager#getServiceState(int): + Method 'getServiceState' documentation mentions permissions already declared by @RequiresPermission +RequiresPermission: android.telephony.TelephonyManager#getSimLocale(): + Method 'getSimLocale' documentation mentions permissions already declared by @RequiresPermission +RequiresPermission: android.telephony.TelephonyManager#getSimSerialNumber(): + Method 'getSimSerialNumber' documentation mentions permissions already declared by @RequiresPermission +RequiresPermission: android.telephony.TelephonyManager#getSubscriberId(): + Method 'getSubscriberId' documentation mentions permissions already declared by @RequiresPermission +RequiresPermission: android.telephony.TelephonyManager#getSupportedRadioAccessFamily(): + Method 'getSupportedRadioAccessFamily' documentation mentions permissions already declared by @RequiresPermission +RequiresPermission: android.telephony.TelephonyManager#getSystemSelectionChannels(): + Method 'getSystemSelectionChannels' documentation mentions permissions already declared by @RequiresPermission +RequiresPermission: android.telephony.TelephonyManager#getTelephonyHistograms(): + Method 'getTelephonyHistograms' documentation mentions permissions already declared by @RequiresPermission +RequiresPermission: android.telephony.TelephonyManager#getVisualVoicemailPackageName(): + Method 'getVisualVoicemailPackageName' documentation mentions permissions already declared by @RequiresPermission +RequiresPermission: android.telephony.TelephonyManager#getVoiceActivationState(): + Method 'getVoiceActivationState' documentation mentions permissions already declared by @RequiresPermission +RequiresPermission: android.telephony.TelephonyManager#getVoiceMailAlphaTag(): + Method 'getVoiceMailAlphaTag' documentation mentions permissions already declared by @RequiresPermission +RequiresPermission: android.telephony.TelephonyManager#getVoiceMailNumber(): + Method 'getVoiceMailNumber' documentation mentions permissions already declared by @RequiresPermission +RequiresPermission: android.telephony.TelephonyManager#getVoiceNetworkType(): + Method 'getVoiceNetworkType' documentation mentions permissions already declared by @RequiresPermission +RequiresPermission: android.telephony.TelephonyManager#iccCloseLogicalChannel(int): + Method 'iccCloseLogicalChannel' documentation mentions permissions without declaring @RequiresPermission +RequiresPermission: android.telephony.TelephonyManager#iccCloseLogicalChannelBySlot(int, int): + Method 'iccCloseLogicalChannelBySlot' documentation mentions permissions already declared by @RequiresPermission +RequiresPermission: android.telephony.TelephonyManager#iccExchangeSimIO(int, int, int, int, int, String): + Method 'iccExchangeSimIO' documentation mentions permissions without declaring @RequiresPermission +RequiresPermission: android.telephony.TelephonyManager#iccOpenLogicalChannel(String): + Method 'iccOpenLogicalChannel' documentation mentions permissions without declaring @RequiresPermission +RequiresPermission: android.telephony.TelephonyManager#iccOpenLogicalChannel(String, int): + Method 'iccOpenLogicalChannel' documentation mentions permissions without declaring @RequiresPermission +RequiresPermission: android.telephony.TelephonyManager#iccOpenLogicalChannelBySlot(int, String, int): + Method 'iccOpenLogicalChannelBySlot' documentation mentions permissions already declared by @RequiresPermission +RequiresPermission: android.telephony.TelephonyManager#iccTransmitApduBasicChannel(int, int, int, int, int, String): + Method 'iccTransmitApduBasicChannel' documentation mentions permissions without declaring @RequiresPermission +RequiresPermission: android.telephony.TelephonyManager#iccTransmitApduBasicChannelBySlot(int, int, int, int, int, int, String): + Method 'iccTransmitApduBasicChannelBySlot' documentation mentions permissions already declared by @RequiresPermission +RequiresPermission: android.telephony.TelephonyManager#iccTransmitApduLogicalChannel(int, int, int, int, int, int, String): + Method 'iccTransmitApduLogicalChannel' documentation mentions permissions without declaring @RequiresPermission +RequiresPermission: android.telephony.TelephonyManager#iccTransmitApduLogicalChannelBySlot(int, int, int, int, int, int, int, String): + Method 'iccTransmitApduLogicalChannelBySlot' documentation mentions permissions already declared by @RequiresPermission +RequiresPermission: android.telephony.TelephonyManager#isApplicationOnUicc(int): + Method 'isApplicationOnUicc' documentation mentions permissions already declared by @RequiresPermission +RequiresPermission: android.telephony.TelephonyManager#isDataEnabled(): + Method 'isDataEnabled' documentation mentions permissions already declared by @RequiresPermission +RequiresPermission: android.telephony.TelephonyManager#isDataEnabledForReason(int): + Method 'isDataEnabledForReason' documentation mentions permissions already declared by @RequiresPermission +RequiresPermission: android.telephony.TelephonyManager#isDataRoamingEnabled(): + Method 'isDataRoamingEnabled' documentation mentions permissions already declared by @RequiresPermission +RequiresPermission: android.telephony.TelephonyManager#isEmergencyAssistanceEnabled(): + Method 'isEmergencyAssistanceEnabled' documentation mentions permissions already declared by @RequiresPermission +RequiresPermission: android.telephony.TelephonyManager#isIccLockEnabled(): + Method 'isIccLockEnabled' documentation mentions permissions already declared by @RequiresPermission +RequiresPermission: android.telephony.TelephonyManager#isManualNetworkSelectionAllowed(): + Method 'isManualNetworkSelectionAllowed' documentation mentions permissions already declared by @RequiresPermission +RequiresPermission: android.telephony.TelephonyManager#isModemEnabledForSlot(int): + Method 'isModemEnabledForSlot' documentation mentions permissions already declared by @RequiresPermission +RequiresPermission: android.telephony.TelephonyManager#isMultiSimSupported(): + Method 'isMultiSimSupported' documentation mentions permissions already declared by @RequiresPermission +RequiresPermission: android.telephony.TelephonyManager#isOpportunisticNetworkEnabled(): + Method 'isOpportunisticNetworkEnabled' documentation mentions permissions already declared by @RequiresPermission +RequiresPermission: android.telephony.TelephonyManager#isPotentialEmergencyNumber(String): + Method 'isPotentialEmergencyNumber' documentation mentions permissions already declared by @RequiresPermission +RequiresPermission: android.telephony.TelephonyManager#isPremiumCapabilityAvailableForPurchase(int): + Method 'isPremiumCapabilityAvailableForPurchase' documentation mentions permissions already declared by @RequiresPermission +RequiresPermission: android.telephony.TelephonyManager#isTetheringApnRequired(): + Method 'isTetheringApnRequired' documentation mentions permissions already declared by @RequiresPermission +RequiresPermission: android.telephony.TelephonyManager#notifyOtaEmergencyNumberDbInstalled(): + Method 'notifyOtaEmergencyNumberDbInstalled' documentation mentions permissions already declared by @RequiresPermission +RequiresPermission: android.telephony.TelephonyManager#prepareForUnattendedReboot(): + Method 'prepareForUnattendedReboot' documentation mentions permissions already declared by @RequiresPermission +RequiresPermission: android.telephony.TelephonyManager#purchasePremiumCapability(int, java.util.concurrent.Executor, java.util.function.Consumer<java.lang.Integer>): + Method 'purchasePremiumCapability' documentation mentions permissions already declared by @RequiresPermission +RequiresPermission: android.telephony.TelephonyManager#rebootModem(): + Method 'rebootModem' documentation mentions permissions already declared by @RequiresPermission +RequiresPermission: android.telephony.TelephonyManager#rebootRadio(): + Method 'rebootRadio' documentation mentions permissions already declared by @RequiresPermission +RequiresPermission: android.telephony.TelephonyManager#reportDefaultNetworkStatus(boolean): + Method 'reportDefaultNetworkStatus' documentation mentions permissions already declared by @RequiresPermission +RequiresPermission: android.telephony.TelephonyManager#requestNetworkScan(android.telephony.NetworkScanRequest, java.util.concurrent.Executor, android.telephony.TelephonyScanManager.NetworkScanCallback): + Method 'requestNetworkScan' documentation mentions permissions already declared by @RequiresPermission +RequiresPermission: android.telephony.TelephonyManager#requestNetworkScan(int, android.telephony.NetworkScanRequest, java.util.concurrent.Executor, android.telephony.TelephonyScanManager.NetworkScanCallback): + Method 'requestNetworkScan' documentation mentions permissions already declared by @RequiresPermission +RequiresPermission: android.telephony.TelephonyManager#requestNumberVerification(android.telephony.PhoneNumberRange, long, java.util.concurrent.Executor, android.telephony.NumberVerificationCallback): + Method 'requestNumberVerification' documentation mentions permissions already declared by @RequiresPermission +RequiresPermission: android.telephony.TelephonyManager#requestRadioPowerOffForReason(int): + Method 'requestRadioPowerOffForReason' documentation mentions permissions already declared by @RequiresPermission +RequiresPermission: android.telephony.TelephonyManager#resetAllCarrierActions(): + Method 'resetAllCarrierActions' documentation mentions permissions already declared by @RequiresPermission +RequiresPermission: android.telephony.TelephonyManager#resetCarrierKeysForImsiEncryption(): + Method 'resetCarrierKeysForImsiEncryption' documentation mentions permissions already declared by @RequiresPermission +RequiresPermission: android.telephony.TelephonyManager#resetOtaEmergencyNumberDbFilePath(): + Method 'resetOtaEmergencyNumberDbFilePath' documentation mentions permissions already declared by @RequiresPermission +RequiresPermission: android.telephony.TelephonyManager#resetRadioConfig(): + Method 'resetRadioConfig' documentation mentions permissions already declared by @RequiresPermission +RequiresPermission: android.telephony.TelephonyManager#sendEnvelopeWithStatus(String): + Method 'sendEnvelopeWithStatus' documentation mentions permissions without declaring @RequiresPermission +RequiresPermission: android.telephony.TelephonyManager#sendThermalMitigationRequest(android.telephony.ThermalMitigationRequest): + Method 'sendThermalMitigationRequest' documentation mentions permissions already declared by @RequiresPermission +RequiresPermission: android.telephony.TelephonyManager#sendUssdRequest(String, android.telephony.TelephonyManager.UssdResponseCallback, android.os.Handler): + Method 'sendUssdRequest' documentation mentions permissions already declared by @RequiresPermission +RequiresPermission: android.telephony.TelephonyManager#sendVisualVoicemailSms(String, int, String, android.app.PendingIntent): + Method 'sendVisualVoicemailSms' documentation mentions permissions without declaring @RequiresPermission +RequiresPermission: android.telephony.TelephonyManager#setAllowedCarriers(int, java.util.List<android.service.carrier.CarrierIdentifier>): + Method 'setAllowedCarriers' documentation mentions permissions already declared by @RequiresPermission +RequiresPermission: android.telephony.TelephonyManager#setAllowedNetworkTypesForReason(int, long): + Method 'setAllowedNetworkTypesForReason' documentation mentions permissions already declared by @RequiresPermission +RequiresPermission: android.telephony.TelephonyManager#setCarrierDataEnabled(boolean): + Method 'setCarrierDataEnabled' documentation mentions permissions already declared by @RequiresPermission +RequiresPermission: android.telephony.TelephonyManager#setCarrierRestrictionRules(android.telephony.CarrierRestrictionRules): + Method 'setCarrierRestrictionRules' documentation mentions permissions already declared by @RequiresPermission +RequiresPermission: android.telephony.TelephonyManager#setCdmaRoamingMode(int): + Method 'setCdmaRoamingMode' documentation mentions permissions already declared by @RequiresPermission +RequiresPermission: android.telephony.TelephonyManager#setCdmaSubscriptionMode(int): + Method 'setCdmaSubscriptionMode' documentation mentions permissions already declared by @RequiresPermission +RequiresPermission: android.telephony.TelephonyManager#setDataActivationState(int): + Method 'setDataActivationState' documentation mentions permissions already declared by @RequiresPermission +RequiresPermission: android.telephony.TelephonyManager#setDataEnabled(boolean): + Method 'setDataEnabled' documentation mentions permissions already declared by @RequiresPermission +RequiresPermission: android.telephony.TelephonyManager#setDataEnabledForReason(int, boolean): + Method 'setDataEnabledForReason' documentation mentions permissions already declared by @RequiresPermission +RequiresPermission: android.telephony.TelephonyManager#setDataRoamingEnabled(boolean): + Method 'setDataRoamingEnabled' documentation mentions permissions already declared by @RequiresPermission +RequiresPermission: android.telephony.TelephonyManager#setForbiddenPlmns(java.util.List<java.lang.String>): + Method 'setForbiddenPlmns' documentation mentions permissions already declared by @RequiresPermission +RequiresPermission: android.telephony.TelephonyManager#setIccLockEnabled(boolean, String): + Method 'setIccLockEnabled' documentation mentions permissions already declared by @RequiresPermission +RequiresPermission: android.telephony.TelephonyManager#setNetworkSelectionModeAutomatic(): + Method 'setNetworkSelectionModeAutomatic' documentation mentions permissions already declared by @RequiresPermission +RequiresPermission: android.telephony.TelephonyManager#setNetworkSelectionModeManual(String, boolean): + Method 'setNetworkSelectionModeManual' documentation mentions permissions already declared by @RequiresPermission +RequiresPermission: android.telephony.TelephonyManager#setNetworkSelectionModeManual(String, boolean, int): + Method 'setNetworkSelectionModeManual' documentation mentions permissions already declared by @RequiresPermission +RequiresPermission: android.telephony.TelephonyManager#setOpportunisticNetworkState(boolean): + Method 'setOpportunisticNetworkState' documentation mentions permissions already declared by @RequiresPermission +RequiresPermission: android.telephony.TelephonyManager#setPreferredNetworkTypeBitmask(long): + Method 'setPreferredNetworkTypeBitmask' documentation mentions permissions already declared by @RequiresPermission +RequiresPermission: android.telephony.TelephonyManager#setPreferredOpportunisticDataSubscription(int, boolean, java.util.concurrent.Executor, java.util.function.Consumer<java.lang.Integer>): + Method 'setPreferredOpportunisticDataSubscription' documentation mentions permissions without declaring @RequiresPermission +RequiresPermission: android.telephony.TelephonyManager#setRadioEnabled(boolean): + Method 'setRadioEnabled' documentation mentions permissions already declared by @RequiresPermission +RequiresPermission: android.telephony.TelephonyManager#setSignalStrengthUpdateRequest(android.telephony.SignalStrengthUpdateRequest): + Method 'setSignalStrengthUpdateRequest' documentation mentions permissions already declared by @RequiresPermission +RequiresPermission: android.telephony.TelephonyManager#setSimPowerState(int): + Method 'setSimPowerState' documentation mentions permissions already declared by @RequiresPermission +RequiresPermission: android.telephony.TelephonyManager#setSimPowerState(int, java.util.concurrent.Executor, java.util.function.Consumer<java.lang.Integer>): + Method 'setSimPowerState' documentation mentions permissions already declared by @RequiresPermission +RequiresPermission: android.telephony.TelephonyManager#setSimPowerStateForSlot(int, int): + Method 'setSimPowerStateForSlot' documentation mentions permissions already declared by @RequiresPermission +RequiresPermission: android.telephony.TelephonyManager#setSimPowerStateForSlot(int, int, java.util.concurrent.Executor, java.util.function.Consumer<java.lang.Integer>): + Method 'setSimPowerStateForSlot' documentation mentions permissions already declared by @RequiresPermission +RequiresPermission: android.telephony.TelephonyManager#setVoiceActivationState(int): + Method 'setVoiceActivationState' documentation mentions permissions already declared by @RequiresPermission +RequiresPermission: android.telephony.TelephonyManager#setVoicemailRingtoneUri(android.telecom.PhoneAccountHandle, android.net.Uri): + Method 'setVoicemailRingtoneUri' documentation mentions permissions without declaring @RequiresPermission +RequiresPermission: android.telephony.TelephonyManager#setVoicemailVibrationEnabled(android.telecom.PhoneAccountHandle, boolean): + Method 'setVoicemailVibrationEnabled' documentation mentions permissions without declaring @RequiresPermission +RequiresPermission: android.telephony.TelephonyManager#supplyIccLockPin(String): + Method 'supplyIccLockPin' documentation mentions permissions already declared by @RequiresPermission +RequiresPermission: android.telephony.TelephonyManager#supplyIccLockPuk(String, String): + Method 'supplyIccLockPuk' documentation mentions permissions already declared by @RequiresPermission +RequiresPermission: android.telephony.TelephonyManager#switchMultiSimConfig(int): + Method 'switchMultiSimConfig' documentation mentions permissions already declared by @RequiresPermission +RequiresPermission: android.telephony.TelephonyManager#updateAvailableNetworks(java.util.List<android.telephony.AvailableNetworkInfo>, java.util.concurrent.Executor, java.util.function.Consumer<java.lang.Integer>): + Method 'updateAvailableNetworks' documentation mentions permissions without declaring @RequiresPermission +RequiresPermission: android.telephony.TelephonyManager#updateOtaEmergencyNumberDbFilePath(android.os.ParcelFileDescriptor): + Method 'updateOtaEmergencyNumberDbFilePath' documentation mentions permissions already declared by @RequiresPermission +RequiresPermission: android.telephony.VisualVoicemailService#sendVisualVoicemailSms(android.content.Context, android.telecom.PhoneAccountHandle, String, short, String, android.app.PendingIntent): + Method 'sendVisualVoicemailSms' documentation mentions permissions without declaring @RequiresPermission +RequiresPermission: android.telephony.VisualVoicemailService#setSmsFilterSettings(android.content.Context, android.telecom.PhoneAccountHandle, android.telephony.VisualVoicemailSmsFilterSettings): + Method 'setSmsFilterSettings' documentation mentions permissions without declaring @RequiresPermission +RequiresPermission: android.telephony.euicc.EuiccManager#continueOperation(android.content.Intent, android.os.Bundle): + Method 'continueOperation' documentation mentions permissions already declared by @RequiresPermission +RequiresPermission: android.telephony.euicc.EuiccManager#deleteSubscription(int, android.app.PendingIntent): + Method 'deleteSubscription' documentation mentions permissions already declared by @RequiresPermission +RequiresPermission: android.telephony.euicc.EuiccManager#downloadSubscription(android.telephony.euicc.DownloadableSubscription, boolean, android.app.PendingIntent): + Method 'downloadSubscription' documentation mentions permissions already declared by @RequiresPermission +RequiresPermission: android.telephony.euicc.EuiccManager#eraseSubscriptions(android.app.PendingIntent): + Method 'eraseSubscriptions' documentation mentions permissions already declared by @RequiresPermission +RequiresPermission: android.telephony.euicc.EuiccManager#eraseSubscriptions(int, android.app.PendingIntent): + Method 'eraseSubscriptions' documentation mentions permissions already declared by @RequiresPermission +RequiresPermission: android.telephony.euicc.EuiccManager#getDefaultDownloadableSubscriptionList(android.app.PendingIntent): + Method 'getDefaultDownloadableSubscriptionList' documentation mentions permissions already declared by @RequiresPermission +RequiresPermission: android.telephony.euicc.EuiccManager#getDownloadableSubscriptionMetadata(android.telephony.euicc.DownloadableSubscription, android.app.PendingIntent): + Method 'getDownloadableSubscriptionMetadata' documentation mentions permissions already declared by @RequiresPermission +RequiresPermission: android.telephony.euicc.EuiccManager#getOtaStatus(): + Method 'getOtaStatus' documentation mentions permissions already declared by @RequiresPermission +RequiresPermission: android.telephony.euicc.EuiccManager#getSupportedCountries(): + Method 'getSupportedCountries' documentation mentions permissions already declared by @RequiresPermission +RequiresPermission: android.telephony.euicc.EuiccManager#getUnsupportedCountries(): + Method 'getUnsupportedCountries' documentation mentions permissions already declared by @RequiresPermission +RequiresPermission: android.telephony.euicc.EuiccManager#setSupportedCountries(java.util.List<java.lang.String>): + Method 'setSupportedCountries' documentation mentions permissions already declared by @RequiresPermission +RequiresPermission: android.telephony.euicc.EuiccManager#setUnsupportedCountries(java.util.List<java.lang.String>): + Method 'setUnsupportedCountries' documentation mentions permissions already declared by @RequiresPermission +RequiresPermission: android.telephony.euicc.EuiccManager#switchToSubscription(int, android.app.PendingIntent): + Method 'switchToSubscription' documentation mentions permissions already declared by @RequiresPermission +RequiresPermission: android.telephony.euicc.EuiccManager#switchToSubscription(int, int, android.app.PendingIntent): + Method 'switchToSubscription' documentation mentions permissions already declared by @RequiresPermission +RequiresPermission: android.telephony.euicc.EuiccManager#updateSubscriptionNickname(int, String, android.app.PendingIntent): + Method 'updateSubscriptionNickname' documentation mentions permissions already declared by @RequiresPermission +RequiresPermission: android.telephony.ims.ImsMmTelManager#createForSubscriptionId(int): + Method 'createForSubscriptionId' documentation mentions permissions already declared by @RequiresPermission +RequiresPermission: android.telephony.ims.ImsMmTelManager#getRegistrationTransportType(java.util.concurrent.Executor, java.util.function.Consumer<java.lang.Integer>): + Method 'getRegistrationTransportType' documentation mentions permissions already declared by @RequiresPermission +RequiresPermission: android.telephony.ims.ImsMmTelManager#getVoWiFiModeSetting(): + Method 'getVoWiFiModeSetting' documentation mentions permissions already declared by @RequiresPermission +RequiresPermission: android.telephony.ims.ImsMmTelManager#isAdvancedCallingSettingEnabled(): + Method 'isAdvancedCallingSettingEnabled' documentation mentions permissions already declared by @RequiresPermission +RequiresPermission: android.telephony.ims.ImsMmTelManager#isCrossSimCallingEnabled(): + Method 'isCrossSimCallingEnabled' documentation mentions permissions already declared by @RequiresPermission +RequiresPermission: android.telephony.ims.ImsMmTelManager#isTtyOverVolteEnabled(): + Method 'isTtyOverVolteEnabled' documentation mentions permissions already declared by @RequiresPermission +RequiresPermission: android.telephony.ims.ImsMmTelManager#isVoWiFiRoamingSettingEnabled(): + Method 'isVoWiFiRoamingSettingEnabled' documentation mentions permissions already declared by @RequiresPermission +RequiresPermission: android.telephony.ims.ImsMmTelManager#isVoWiFiSettingEnabled(): + Method 'isVoWiFiSettingEnabled' documentation mentions permissions already declared by @RequiresPermission +RequiresPermission: android.telephony.ims.ImsMmTelManager#isVtSettingEnabled(): + Method 'isVtSettingEnabled' documentation mentions permissions already declared by @RequiresPermission +RequiresPermission: android.telephony.ims.ImsMmTelManager#registerImsRegistrationCallback(java.util.concurrent.Executor, android.telephony.ims.RegistrationManager.RegistrationCallback): + Method 'registerImsRegistrationCallback' documentation mentions permissions already declared by @RequiresPermission +RequiresPermission: android.telephony.ims.ImsMmTelManager#registerImsStateCallback(java.util.concurrent.Executor, android.telephony.ims.ImsStateCallback): + Method 'registerImsStateCallback' documentation mentions permissions already declared by @RequiresPermission +RequiresPermission: android.telephony.ims.ImsMmTelManager#registerMmTelCapabilityCallback(java.util.concurrent.Executor, android.telephony.ims.ImsMmTelManager.CapabilityCallback): + Method 'registerMmTelCapabilityCallback' documentation mentions permissions already declared by @RequiresPermission +RequiresPermission: android.telephony.ims.ImsMmTelManager#unregisterImsRegistrationCallback(android.telephony.ims.RegistrationManager.RegistrationCallback): + Method 'unregisterImsRegistrationCallback' documentation mentions permissions already declared by @RequiresPermission +RequiresPermission: android.telephony.ims.ImsMmTelManager#unregisterMmTelCapabilityCallback(android.telephony.ims.ImsMmTelManager.CapabilityCallback): + Method 'unregisterMmTelCapabilityCallback' documentation mentions permissions already declared by @RequiresPermission +RequiresPermission: android.telephony.ims.ImsRcsManager#getRegistrationState(java.util.concurrent.Executor, java.util.function.Consumer<java.lang.Integer>): + Method 'getRegistrationState' documentation mentions permissions already declared by @RequiresPermission +RequiresPermission: android.telephony.ims.ImsRcsManager#getRegistrationTransportType(java.util.concurrent.Executor, java.util.function.Consumer<java.lang.Integer>): + Method 'getRegistrationTransportType' documentation mentions permissions already declared by @RequiresPermission +RequiresPermission: android.telephony.ims.ImsRcsManager#registerImsRegistrationCallback(java.util.concurrent.Executor, android.telephony.ims.RegistrationManager.RegistrationCallback): + Method 'registerImsRegistrationCallback' documentation mentions permissions already declared by @RequiresPermission +RequiresPermission: android.telephony.ims.ImsRcsManager#registerImsStateCallback(java.util.concurrent.Executor, android.telephony.ims.ImsStateCallback): + Method 'registerImsStateCallback' documentation mentions permissions already declared by @RequiresPermission +RequiresPermission: android.telephony.ims.ImsRcsManager#unregisterImsRegistrationCallback(android.telephony.ims.RegistrationManager.RegistrationCallback): + Method 'unregisterImsRegistrationCallback' documentation mentions permissions already declared by @RequiresPermission +RequiresPermission: android.telephony.ims.ProvisioningManager#getProvisioningStatusForCapability(int, int): + Method 'getProvisioningStatusForCapability' documentation mentions permissions already declared by @RequiresPermission +RequiresPermission: android.telephony.ims.ProvisioningManager#getRcsProvisioningStatusForCapability(int, int): + Method 'getRcsProvisioningStatusForCapability' documentation mentions permissions already declared by @RequiresPermission +RequiresPermission: android.telephony.ims.ProvisioningManager#isProvisioningRequiredForCapability(int, int): + Method 'isProvisioningRequiredForCapability' documentation mentions permissions already declared by @RequiresPermission +RequiresPermission: android.telephony.ims.ProvisioningManager#isRcsProvisioningRequiredForCapability(int, int): + Method 'isRcsProvisioningRequiredForCapability' documentation mentions permissions already declared by @RequiresPermission +RequiresPermission: android.telephony.ims.ProvisioningManager#isRcsVolteSingleRegistrationCapable(): + Method 'isRcsVolteSingleRegistrationCapable' documentation mentions permissions already declared by @RequiresPermission +RequiresPermission: android.telephony.ims.ProvisioningManager#notifyRcsAutoConfigurationReceived(byte[], boolean): + Method 'notifyRcsAutoConfigurationReceived' documentation mentions permissions already declared by @RequiresPermission +RequiresPermission: android.telephony.ims.ProvisioningManager#registerFeatureProvisioningChangedCallback(java.util.concurrent.Executor, android.telephony.ims.ProvisioningManager.FeatureProvisioningCallback): + Method 'registerFeatureProvisioningChangedCallback' documentation mentions permissions already declared by @RequiresPermission +RequiresPermission: android.telephony.ims.ProvisioningManager#registerProvisioningChangedCallback(java.util.concurrent.Executor, android.telephony.ims.ProvisioningManager.Callback): + Method 'registerProvisioningChangedCallback' documentation mentions permissions already declared by @RequiresPermission +RequiresPermission: android.telephony.ims.ProvisioningManager#registerRcsProvisioningCallback(java.util.concurrent.Executor, android.telephony.ims.ProvisioningManager.RcsProvisioningCallback): + Method 'registerRcsProvisioningCallback' documentation mentions permissions already declared by @RequiresPermission +RequiresPermission: android.telephony.ims.ProvisioningManager#setProvisioningStatusForCapability(int, int, boolean): + Method 'setProvisioningStatusForCapability' documentation mentions permissions already declared by @RequiresPermission +RequiresPermission: android.telephony.ims.ProvisioningManager#setRcsProvisioningStatusForCapability(int, boolean): + Method 'setRcsProvisioningStatusForCapability' documentation mentions permissions already declared by @RequiresPermission +RequiresPermission: android.telephony.ims.ProvisioningManager#setRcsProvisioningStatusForCapability(int, int, boolean): + Method 'setRcsProvisioningStatusForCapability' documentation mentions permissions already declared by @RequiresPermission +RequiresPermission: android.telephony.ims.ProvisioningManager#unregisterProvisioningChangedCallback(android.telephony.ims.ProvisioningManager.Callback): + Method 'unregisterProvisioningChangedCallback' documentation mentions permissions already declared by @RequiresPermission +RequiresPermission: android.telephony.ims.ProvisioningManager#unregisterRcsProvisioningCallback(android.telephony.ims.ProvisioningManager.RcsProvisioningCallback): + Method 'unregisterRcsProvisioningCallback' documentation mentions permissions already declared by @RequiresPermission +RequiresPermission: android.telephony.ims.SipDelegateManager#registerSipDialogStateCallback(java.util.concurrent.Executor, android.telephony.ims.SipDialogStateCallback): + Method 'registerSipDialogStateCallback' documentation mentions permissions already declared by @RequiresPermission +RequiresPermission: android.telephony.ims.SipDelegateManager#unregisterSipDialogStateCallback(android.telephony.ims.SipDialogStateCallback): + Method 'unregisterSipDialogStateCallback' documentation mentions permissions already declared by @RequiresPermission +RequiresPermission: android.view.WindowManager.LayoutParams#isSystemApplicationOverlay(): + Method 'isSystemApplicationOverlay' documentation mentions permissions without declaring @RequiresPermission +RequiresPermission: android.view.accessibility.AccessibilityManager#registerDisplayProxy(android.view.accessibility.AccessibilityDisplayProxy): + Method 'registerDisplayProxy' documentation mentions permissions already declared by @RequiresPermission +RequiresPermission: android.view.accessibility.AccessibilityManager#unregisterDisplayProxy(android.view.accessibility.AccessibilityDisplayProxy): + Method 'unregisterDisplayProxy' documentation mentions permissions already declared by @RequiresPermission +RequiresPermission: android.view.accessibility.CaptioningManager#setSystemAudioCaptioningEnabled(boolean): + Method 'setSystemAudioCaptioningEnabled' documentation mentions permissions already declared by @RequiresPermission +RequiresPermission: android.view.accessibility.CaptioningManager#setSystemAudioCaptioningUiEnabled(boolean): + Method 'setSystemAudioCaptioningUiEnabled' documentation mentions permissions already declared by @RequiresPermission +RequiresPermission: android.view.inputmethod.InputMethodManager#setCurrentInputMethodSubtype(android.view.inputmethod.InputMethodSubtype): + Method 'setCurrentInputMethodSubtype' documentation mentions permissions already declared by @RequiresPermission +RequiresPermission: android.webkit.WebSettings#setBlockNetworkLoads(boolean): + Method 'setBlockNetworkLoads' documentation mentions permissions without declaring @RequiresPermission +RequiresPermission: android.webkit.WebSettings#setGeolocationEnabled(boolean): + Method 'setGeolocationEnabled' documentation mentions permissions without declaring @RequiresPermission + + SamShouldBeLast: android.accounts.AccountManager#addAccount(String, String, String[], android.os.Bundle, android.app.Activity, android.accounts.AccountManagerCallback<android.os.Bundle>, android.os.Handler): SAM-compatible parameters (such as parameter 6, "callback", in android.accounts.AccountManager.addAccount) should be last to improve Kotlin interoperability; see https://kotlinlang.org/docs/reference/java-interop.html#sam-conversions SamShouldBeLast: android.accounts.AccountManager#addOnAccountsUpdatedListener(android.accounts.OnAccountsUpdateListener, android.os.Handler, boolean): @@ -201,6 +1901,80 @@ SamShouldBeLast: android.webkit.WebChromeClient#onShowFileChooser(android.webkit SAM-compatible parameters (such as parameter 2, "filePathCallback", in android.webkit.WebChromeClient.onShowFileChooser) should be last to improve Kotlin interoperability; see https://kotlinlang.org/docs/reference/java-interop.html#sam-conversions +SdkConstant: android.content.Intent#ACTION_BATTERY_LEVEL_CHANGED: + Field 'ACTION_BATTERY_LEVEL_CHANGED' is missing @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION) +SdkConstant: android.content.Intent#ACTION_DEVICE_CUSTOMIZATION_READY: + Field 'ACTION_DEVICE_CUSTOMIZATION_READY' is missing @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION) +SdkConstant: android.content.Intent#ACTION_GLOBAL_BUTTON: + Field 'ACTION_GLOBAL_BUTTON' is missing @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION) +SdkConstant: android.content.Intent#ACTION_PRE_BOOT_COMPLETED: + Field 'ACTION_PRE_BOOT_COMPLETED' is missing @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION) +SdkConstant: android.content.Intent#ACTION_UNARCHIVE_PACKAGE: + Field 'ACTION_UNARCHIVE_PACKAGE' is missing @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION) +SdkConstant: android.content.pm.PackageInstaller#ACTION_CONFIRM_PRE_APPROVAL: + Field 'ACTION_CONFIRM_PRE_APPROVAL' is missing @SdkConstant(SdkConstantType.ACTIVITY_INTENT_ACTION) +SdkConstant: android.hardware.usb.UsbManager#ACTION_USB_PORT_CHANGED: + Field 'ACTION_USB_PORT_CHANGED' is missing @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION) +SdkConstant: android.hardware.usb.UsbManager#ACTION_USB_PORT_COMPLIANCE_CHANGED: + Field 'ACTION_USB_PORT_COMPLIANCE_CHANGED' is missing @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION) +SdkConstant: android.hardware.usb.UsbManager#ACTION_USB_STATE: + Field 'ACTION_USB_STATE' is missing @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION) +SdkConstant: android.nfc.NfcAdapter#ACTION_REQUIRE_UNLOCK_FOR_NFC: + Field 'ACTION_REQUIRE_UNLOCK_FOR_NFC' is missing @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION) +SdkConstant: android.service.euicc.EuiccService#ACTION_DELETE_SUBSCRIPTION_PRIVILEGED: + Field 'ACTION_DELETE_SUBSCRIPTION_PRIVILEGED' is missing @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION) +SdkConstant: android.service.euicc.EuiccService#ACTION_RENAME_SUBSCRIPTION_PRIVILEGED: + Field 'ACTION_RENAME_SUBSCRIPTION_PRIVILEGED' is missing @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION) +SdkConstant: android.service.euicc.EuiccService#ACTION_TOGGLE_SUBSCRIPTION_PRIVILEGED: + Field 'ACTION_TOGGLE_SUBSCRIPTION_PRIVILEGED' is missing @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION) +SdkConstant: android.telephony.TelephonyManager#ACTION_DEFAULT_DATA_SUBSCRIPTION_CHANGED: + Field 'ACTION_DEFAULT_DATA_SUBSCRIPTION_CHANGED' is missing @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION) +SdkConstant: android.telephony.TelephonyManager#ACTION_DEFAULT_VOICE_SUBSCRIPTION_CHANGED: + Field 'ACTION_DEFAULT_VOICE_SUBSCRIPTION_CHANGED' is missing @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION) +SdkConstant: android.telephony.TelephonyManager#ACTION_REQUEST_OMADM_CONFIGURATION_UPDATE: + Field 'ACTION_REQUEST_OMADM_CONFIGURATION_UPDATE' is missing @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION) +SdkConstant: android.telephony.TelephonyManager#ACTION_SHOW_NOTICE_ECM_BLOCK_OTHERS: + Field 'ACTION_SHOW_NOTICE_ECM_BLOCK_OTHERS' is missing @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION) + + +Todo: android.Manifest.permission#DOMAIN_VERIFICATION_AGENT: + Documentation mentions 'TODO' +Todo: android.Manifest.permission#INSTALL_EXISTING_PACKAGES: + Documentation mentions 'TODO' +Todo: android.Manifest.permission#READ_PEOPLE_DATA: + Documentation mentions 'TODO' +Todo: android.app.NotificationManager#isNotificationAssistantAccessGranted(android.content.ComponentName): + Documentation mentions 'TODO' +Todo: android.hardware.camera2.params.StreamConfigurationMap: + Documentation mentions 'TODO' +Todo: android.hardware.location.ContextHubManager#getNanoAppInstanceInfo(int): + Documentation mentions 'TODO' +Todo: android.hardware.location.ContextHubManager#loadNanoApp(int, android.hardware.location.NanoApp): + Documentation mentions 'TODO' +Todo: android.hardware.location.ContextHubManager#unloadNanoApp(int): + Documentation mentions 'TODO' +Todo: android.hardware.location.NanoAppInstanceInfo: + Documentation mentions 'TODO' +Todo: android.media.tv.TvContentRatingSystemInfo#getXmlUri(): + Documentation mentions 'TODO' +Todo: android.media.tv.TvInputInfo#isConnectedToHdmiSwitch(): + Documentation mentions 'TODO' +Todo: android.os.RecoverySystem#prepareForUnattendedUpdate(android.content.Context, String, android.content.IntentSender): + Documentation mentions 'TODO' +Todo: android.os.RecoverySystem#rebootAndApply(android.content.Context, String, String): + Documentation mentions 'TODO' +Todo: android.os.SystemConfigManager: + Documentation mentions 'TODO' +Todo: android.os.UpdateEngineCallback#onStatusUpdate(int, float): + Documentation mentions 'TODO' +Todo: android.provider.ContactsContract.RawContacts#newEntityIterator(android.database.Cursor): + Documentation mentions 'TODO' +Todo: android.service.voice.AlwaysOnHotwordDetector: + Documentation mentions 'TODO' +Todo: android.telephony.TelephonyManager#getCurrentPhoneType(): + Documentation mentions 'TODO' + + UnflaggedApi: android.Manifest.permission#ACCESS_SMARTSPACE: New API must be flagged with @FlaggedApi: field android.Manifest.permission.ACCESS_SMARTSPACE UnflaggedApi: android.Manifest.permission#ALWAYS_UPDATE_WALLPAPER: @@ -325,10 +2099,10 @@ UnflaggedApi: android.service.voice.HotwordTrainingData#TIMEOUT_STAGE_VERY_EARLY New API must be flagged with @FlaggedApi: field android.service.voice.HotwordTrainingData.TIMEOUT_STAGE_VERY_EARLY UnflaggedApi: android.service.voice.HotwordTrainingData#describeContents(): New API must be flagged with @FlaggedApi: method android.service.voice.HotwordTrainingData.describeContents() -UnflaggedApi: android.service.voice.HotwordTrainingData#getMaxTrainingDataSize(): - New API must be flagged with @FlaggedApi: method android.service.voice.HotwordTrainingData.getMaxTrainingDataSize() UnflaggedApi: android.service.voice.HotwordTrainingData#getMaxTrainingDataBytes(): New API must be flagged with @FlaggedApi: method android.service.voice.HotwordTrainingData.getMaxTrainingDataBytes() +UnflaggedApi: android.service.voice.HotwordTrainingData#getMaxTrainingDataSize(): + New API must be flagged with @FlaggedApi: method android.service.voice.HotwordTrainingData.getMaxTrainingDataSize() UnflaggedApi: android.service.voice.HotwordTrainingData#getTimeoutStage(): New API must be flagged with @FlaggedApi: method android.service.voice.HotwordTrainingData.getTimeoutStage() UnflaggedApi: android.service.voice.HotwordTrainingData#getTrainingAudioList(): diff --git a/core/api/system-removed.txt b/core/api/system-removed.txt index aa17df3471d7..402a7184c7c2 100644 --- a/core/api/system-removed.txt +++ b/core/api/system-removed.txt @@ -15,7 +15,7 @@ package android.app { method public static Class<? extends android.app.Notification.Style> getNotificationStyleClass(String); } - public static final class Notification.TvExtender implements android.app.Notification.Extender { + @FlaggedApi("android.app.api_tvextender") public static final class Notification.TvExtender implements android.app.Notification.Extender { method @Deprecated public String getChannel(); } diff --git a/core/api/test-lint-baseline.txt b/core/api/test-lint-baseline.txt index 105e7645ac4b..559db514dabf 100644 --- a/core/api/test-lint-baseline.txt +++ b/core/api/test-lint-baseline.txt @@ -1,4 +1,512 @@ // Baseline format: 1.0 +BroadcastBehavior: android.app.AlarmManager#ACTION_NEXT_ALARM_CLOCK_CHANGED: + Field 'ACTION_NEXT_ALARM_CLOCK_CHANGED' is missing @BroadcastBehavior +BroadcastBehavior: android.app.AlarmManager#ACTION_SCHEDULE_EXACT_ALARM_PERMISSION_STATE_CHANGED: + Field 'ACTION_SCHEDULE_EXACT_ALARM_PERMISSION_STATE_CHANGED' is missing @BroadcastBehavior +BroadcastBehavior: android.app.NotificationManager#ACTION_CLOSE_NOTIFICATION_HANDLER_PANEL: + Field 'ACTION_CLOSE_NOTIFICATION_HANDLER_PANEL' is missing @BroadcastBehavior +BroadcastBehavior: android.app.admin.DevicePolicyManager#ACTION_APPLICATION_DELEGATION_SCOPES_CHANGED: + Field 'ACTION_APPLICATION_DELEGATION_SCOPES_CHANGED' is missing @BroadcastBehavior +BroadcastBehavior: android.app.admin.DevicePolicyManager#ACTION_MANAGED_PROFILE_PROVISIONED: + Field 'ACTION_MANAGED_PROFILE_PROVISIONED' is missing @BroadcastBehavior +BroadcastBehavior: android.content.Intent#ACTION_AIRPLANE_MODE_CHANGED: + Field 'ACTION_AIRPLANE_MODE_CHANGED' is missing @BroadcastBehavior +BroadcastBehavior: android.content.Intent#ACTION_APPLICATION_LOCALE_CHANGED: + Field 'ACTION_APPLICATION_LOCALE_CHANGED' is missing @BroadcastBehavior +BroadcastBehavior: android.content.Intent#ACTION_APPLICATION_RESTRICTIONS_CHANGED: + Field 'ACTION_APPLICATION_RESTRICTIONS_CHANGED' is missing @BroadcastBehavior +BroadcastBehavior: android.content.Intent#ACTION_BATTERY_CHANGED: + Field 'ACTION_BATTERY_CHANGED' is missing @BroadcastBehavior +BroadcastBehavior: android.content.Intent#ACTION_BATTERY_LEVEL_CHANGED: + Field 'ACTION_BATTERY_LEVEL_CHANGED' is missing @BroadcastBehavior +BroadcastBehavior: android.content.Intent#ACTION_BATTERY_LOW: + Field 'ACTION_BATTERY_LOW' is missing @BroadcastBehavior +BroadcastBehavior: android.content.Intent#ACTION_BATTERY_OKAY: + Field 'ACTION_BATTERY_OKAY' is missing @BroadcastBehavior +BroadcastBehavior: android.content.Intent#ACTION_CAMERA_BUTTON: + Field 'ACTION_CAMERA_BUTTON' is missing @BroadcastBehavior +BroadcastBehavior: android.content.Intent#ACTION_CLOSE_SYSTEM_DIALOGS: + Field 'ACTION_CLOSE_SYSTEM_DIALOGS' is missing @BroadcastBehavior +BroadcastBehavior: android.content.Intent#ACTION_CONFIGURATION_CHANGED: + Field 'ACTION_CONFIGURATION_CHANGED' is missing @BroadcastBehavior +BroadcastBehavior: android.content.Intent#ACTION_DATE_CHANGED: + Field 'ACTION_DATE_CHANGED' is missing @BroadcastBehavior +BroadcastBehavior: android.content.Intent#ACTION_DEVICE_CUSTOMIZATION_READY: + Field 'ACTION_DEVICE_CUSTOMIZATION_READY' is missing @BroadcastBehavior +BroadcastBehavior: android.content.Intent#ACTION_DEVICE_STORAGE_LOW: + Field 'ACTION_DEVICE_STORAGE_LOW' is missing @BroadcastBehavior +BroadcastBehavior: android.content.Intent#ACTION_DEVICE_STORAGE_OK: + Field 'ACTION_DEVICE_STORAGE_OK' is missing @BroadcastBehavior +BroadcastBehavior: android.content.Intent#ACTION_DOCK_EVENT: + Field 'ACTION_DOCK_EVENT' is missing @BroadcastBehavior +BroadcastBehavior: android.content.Intent#ACTION_DOMAINS_NEED_VERIFICATION: + Field 'ACTION_DOMAINS_NEED_VERIFICATION' is missing @BroadcastBehavior +BroadcastBehavior: android.content.Intent#ACTION_DREAMING_STARTED: + Field 'ACTION_DREAMING_STARTED' is missing @BroadcastBehavior +BroadcastBehavior: android.content.Intent#ACTION_DREAMING_STOPPED: + Field 'ACTION_DREAMING_STOPPED' is missing @BroadcastBehavior +BroadcastBehavior: android.content.Intent#ACTION_EXTERNAL_APPLICATIONS_AVAILABLE: + Field 'ACTION_EXTERNAL_APPLICATIONS_AVAILABLE' is missing @BroadcastBehavior +BroadcastBehavior: android.content.Intent#ACTION_EXTERNAL_APPLICATIONS_UNAVAILABLE: + Field 'ACTION_EXTERNAL_APPLICATIONS_UNAVAILABLE' is missing @BroadcastBehavior +BroadcastBehavior: android.content.Intent#ACTION_GLOBAL_BUTTON: + Field 'ACTION_GLOBAL_BUTTON' is missing @BroadcastBehavior +BroadcastBehavior: android.content.Intent#ACTION_GTALK_SERVICE_CONNECTED: + Field 'ACTION_GTALK_SERVICE_CONNECTED' is missing @BroadcastBehavior +BroadcastBehavior: android.content.Intent#ACTION_GTALK_SERVICE_DISCONNECTED: + Field 'ACTION_GTALK_SERVICE_DISCONNECTED' is missing @BroadcastBehavior +BroadcastBehavior: android.content.Intent#ACTION_HEADSET_PLUG: + Field 'ACTION_HEADSET_PLUG' is missing @BroadcastBehavior +BroadcastBehavior: android.content.Intent#ACTION_INPUT_METHOD_CHANGED: + Field 'ACTION_INPUT_METHOD_CHANGED' is missing @BroadcastBehavior +BroadcastBehavior: android.content.Intent#ACTION_INSTALL_INSTANT_APP_PACKAGE: + Field 'ACTION_INSTALL_INSTANT_APP_PACKAGE' is missing @BroadcastBehavior +BroadcastBehavior: android.content.Intent#ACTION_INSTANT_APP_RESOLVER_SETTINGS: + Field 'ACTION_INSTANT_APP_RESOLVER_SETTINGS' is missing @BroadcastBehavior +BroadcastBehavior: android.content.Intent#ACTION_INTENT_FILTER_NEEDS_VERIFICATION: + Field 'ACTION_INTENT_FILTER_NEEDS_VERIFICATION' is missing @BroadcastBehavior +BroadcastBehavior: android.content.Intent#ACTION_LOAD_DATA: + Field 'ACTION_LOAD_DATA' is missing @BroadcastBehavior +BroadcastBehavior: android.content.Intent#ACTION_LOCALE_CHANGED: + Field 'ACTION_LOCALE_CHANGED' is missing @BroadcastBehavior +BroadcastBehavior: android.content.Intent#ACTION_LOCKED_BOOT_COMPLETED: + Field 'ACTION_LOCKED_BOOT_COMPLETED' is missing @BroadcastBehavior +BroadcastBehavior: android.content.Intent#ACTION_MANAGE_PACKAGE_STORAGE: + Field 'ACTION_MANAGE_PACKAGE_STORAGE' is missing @BroadcastBehavior +BroadcastBehavior: android.content.Intent#ACTION_MEDIA_BAD_REMOVAL: + Field 'ACTION_MEDIA_BAD_REMOVAL' is missing @BroadcastBehavior +BroadcastBehavior: android.content.Intent#ACTION_MEDIA_BUTTON: + Field 'ACTION_MEDIA_BUTTON' is missing @BroadcastBehavior +BroadcastBehavior: android.content.Intent#ACTION_MEDIA_CHECKING: + Field 'ACTION_MEDIA_CHECKING' is missing @BroadcastBehavior +BroadcastBehavior: android.content.Intent#ACTION_MEDIA_EJECT: + Field 'ACTION_MEDIA_EJECT' is missing @BroadcastBehavior +BroadcastBehavior: android.content.Intent#ACTION_MEDIA_MOUNTED: + Field 'ACTION_MEDIA_MOUNTED' is missing @BroadcastBehavior +BroadcastBehavior: android.content.Intent#ACTION_MEDIA_NOFS: + Field 'ACTION_MEDIA_NOFS' is missing @BroadcastBehavior +BroadcastBehavior: android.content.Intent#ACTION_MEDIA_REMOVED: + Field 'ACTION_MEDIA_REMOVED' is missing @BroadcastBehavior +BroadcastBehavior: android.content.Intent#ACTION_MEDIA_SCANNER_FINISHED: + Field 'ACTION_MEDIA_SCANNER_FINISHED' is missing @BroadcastBehavior +BroadcastBehavior: android.content.Intent#ACTION_MEDIA_SCANNER_SCAN_FILE: + Field 'ACTION_MEDIA_SCANNER_SCAN_FILE' is missing @BroadcastBehavior +BroadcastBehavior: android.content.Intent#ACTION_MEDIA_SCANNER_STARTED: + Field 'ACTION_MEDIA_SCANNER_STARTED' is missing @BroadcastBehavior +BroadcastBehavior: android.content.Intent#ACTION_MEDIA_SHARED: + Field 'ACTION_MEDIA_SHARED' is missing @BroadcastBehavior +BroadcastBehavior: android.content.Intent#ACTION_MEDIA_UNMOUNTABLE: + Field 'ACTION_MEDIA_UNMOUNTABLE' is missing @BroadcastBehavior +BroadcastBehavior: android.content.Intent#ACTION_MEDIA_UNMOUNTED: + Field 'ACTION_MEDIA_UNMOUNTED' is missing @BroadcastBehavior +BroadcastBehavior: android.content.Intent#ACTION_MY_PACKAGE_REPLACED: + Field 'ACTION_MY_PACKAGE_REPLACED' is missing @BroadcastBehavior +BroadcastBehavior: android.content.Intent#ACTION_MY_PACKAGE_SUSPENDED: + Field 'ACTION_MY_PACKAGE_SUSPENDED' is missing @BroadcastBehavior +BroadcastBehavior: android.content.Intent#ACTION_MY_PACKAGE_UNSUSPENDED: + Field 'ACTION_MY_PACKAGE_UNSUSPENDED' is missing @BroadcastBehavior +BroadcastBehavior: android.content.Intent#ACTION_NEW_OUTGOING_CALL: + Field 'ACTION_NEW_OUTGOING_CALL' is missing @BroadcastBehavior +BroadcastBehavior: android.content.Intent#ACTION_PACKAGES_SUSPENDED: + Field 'ACTION_PACKAGES_SUSPENDED' is missing @BroadcastBehavior +BroadcastBehavior: android.content.Intent#ACTION_PACKAGES_UNSUSPENDED: + Field 'ACTION_PACKAGES_UNSUSPENDED' is missing @BroadcastBehavior +BroadcastBehavior: android.content.Intent#ACTION_PACKAGE_ADDED: + Field 'ACTION_PACKAGE_ADDED' is missing @BroadcastBehavior +BroadcastBehavior: android.content.Intent#ACTION_PACKAGE_CHANGED: + Field 'ACTION_PACKAGE_CHANGED' is missing @BroadcastBehavior +BroadcastBehavior: android.content.Intent#ACTION_PACKAGE_DATA_CLEARED: + Field 'ACTION_PACKAGE_DATA_CLEARED' is missing @BroadcastBehavior +BroadcastBehavior: android.content.Intent#ACTION_PACKAGE_FIRST_LAUNCH: + Field 'ACTION_PACKAGE_FIRST_LAUNCH' is missing @BroadcastBehavior +BroadcastBehavior: android.content.Intent#ACTION_PACKAGE_FULLY_REMOVED: + Field 'ACTION_PACKAGE_FULLY_REMOVED' is missing @BroadcastBehavior +BroadcastBehavior: android.content.Intent#ACTION_PACKAGE_INSTALL: + Field 'ACTION_PACKAGE_INSTALL' is missing @BroadcastBehavior +BroadcastBehavior: android.content.Intent#ACTION_PACKAGE_NEEDS_INTEGRITY_VERIFICATION: + Field 'ACTION_PACKAGE_NEEDS_INTEGRITY_VERIFICATION' is missing @BroadcastBehavior +BroadcastBehavior: android.content.Intent#ACTION_PACKAGE_NEEDS_VERIFICATION: + Field 'ACTION_PACKAGE_NEEDS_VERIFICATION' is missing @BroadcastBehavior +BroadcastBehavior: android.content.Intent#ACTION_PACKAGE_REMOVED: + Field 'ACTION_PACKAGE_REMOVED' is missing @BroadcastBehavior +BroadcastBehavior: android.content.Intent#ACTION_PACKAGE_REPLACED: + Field 'ACTION_PACKAGE_REPLACED' is missing @BroadcastBehavior +BroadcastBehavior: android.content.Intent#ACTION_PACKAGE_RESTARTED: + Field 'ACTION_PACKAGE_RESTARTED' is missing @BroadcastBehavior +BroadcastBehavior: android.content.Intent#ACTION_PACKAGE_UNSTOPPED: + Field 'ACTION_PACKAGE_UNSTOPPED' is missing @BroadcastBehavior +BroadcastBehavior: android.content.Intent#ACTION_PACKAGE_UNSUSPENDED_MANUALLY: + Field 'ACTION_PACKAGE_UNSUSPENDED_MANUALLY' is missing @BroadcastBehavior +BroadcastBehavior: android.content.Intent#ACTION_PACKAGE_VERIFIED: + Field 'ACTION_PACKAGE_VERIFIED' is missing @BroadcastBehavior +BroadcastBehavior: android.content.Intent#ACTION_POWER_CONNECTED: + Field 'ACTION_POWER_CONNECTED' is missing @BroadcastBehavior +BroadcastBehavior: android.content.Intent#ACTION_POWER_DISCONNECTED: + Field 'ACTION_POWER_DISCONNECTED' is missing @BroadcastBehavior +BroadcastBehavior: android.content.Intent#ACTION_PRE_BOOT_COMPLETED: + Field 'ACTION_PRE_BOOT_COMPLETED' is missing @BroadcastBehavior +BroadcastBehavior: android.content.Intent#ACTION_PROVIDER_CHANGED: + Field 'ACTION_PROVIDER_CHANGED' is missing @BroadcastBehavior +BroadcastBehavior: android.content.Intent#ACTION_QUERY_PACKAGE_RESTART: + Field 'ACTION_QUERY_PACKAGE_RESTART' is missing @BroadcastBehavior +BroadcastBehavior: android.content.Intent#ACTION_REBOOT: + Field 'ACTION_REBOOT' is missing @BroadcastBehavior +BroadcastBehavior: android.content.Intent#ACTION_RESOLVE_INSTANT_APP_PACKAGE: + Field 'ACTION_RESOLVE_INSTANT_APP_PACKAGE' is missing @BroadcastBehavior +BroadcastBehavior: android.content.Intent#ACTION_ROLLBACK_COMMITTED: + Field 'ACTION_ROLLBACK_COMMITTED' is missing @BroadcastBehavior +BroadcastBehavior: android.content.Intent#ACTION_SCREEN_OFF: + Field 'ACTION_SCREEN_OFF' is missing @BroadcastBehavior +BroadcastBehavior: android.content.Intent#ACTION_SCREEN_ON: + Field 'ACTION_SCREEN_ON' is missing @BroadcastBehavior +BroadcastBehavior: android.content.Intent#ACTION_SHOW_SUSPENDED_APP_DETAILS: + Field 'ACTION_SHOW_SUSPENDED_APP_DETAILS' is missing @BroadcastBehavior +BroadcastBehavior: android.content.Intent#ACTION_SHUTDOWN: + Field 'ACTION_SHUTDOWN' is missing @BroadcastBehavior +BroadcastBehavior: android.content.Intent#ACTION_SIM_STATE_CHANGED: + Field 'ACTION_SIM_STATE_CHANGED' is missing @BroadcastBehavior +BroadcastBehavior: android.content.Intent#ACTION_SPLIT_CONFIGURATION_CHANGED: + Field 'ACTION_SPLIT_CONFIGURATION_CHANGED' is missing @BroadcastBehavior +BroadcastBehavior: android.content.Intent#ACTION_TIMEZONE_CHANGED: + Field 'ACTION_TIMEZONE_CHANGED' is missing @BroadcastBehavior +BroadcastBehavior: android.content.Intent#ACTION_TIME_CHANGED: + Field 'ACTION_TIME_CHANGED' is missing @BroadcastBehavior +BroadcastBehavior: android.content.Intent#ACTION_TIME_TICK: + Field 'ACTION_TIME_TICK' is missing @BroadcastBehavior +BroadcastBehavior: android.content.Intent#ACTION_UID_REMOVED: + Field 'ACTION_UID_REMOVED' is missing @BroadcastBehavior +BroadcastBehavior: android.content.Intent#ACTION_UMS_CONNECTED: + Field 'ACTION_UMS_CONNECTED' is missing @BroadcastBehavior +BroadcastBehavior: android.content.Intent#ACTION_UMS_DISCONNECTED: + Field 'ACTION_UMS_DISCONNECTED' is missing @BroadcastBehavior +BroadcastBehavior: android.content.Intent#ACTION_UNARCHIVE_PACKAGE: + Field 'ACTION_UNARCHIVE_PACKAGE' is missing @BroadcastBehavior +BroadcastBehavior: android.content.Intent#ACTION_USER_PRESENT: + Field 'ACTION_USER_PRESENT' is missing @BroadcastBehavior +BroadcastBehavior: android.content.Intent#ACTION_USER_UNLOCKED: + Field 'ACTION_USER_UNLOCKED' is missing @BroadcastBehavior +BroadcastBehavior: android.content.Intent#ACTION_WALLPAPER_CHANGED: + Field 'ACTION_WALLPAPER_CHANGED' is missing @BroadcastBehavior +BroadcastBehavior: android.content.pm.PackageInstaller#ACTION_SESSION_COMMITTED: + Field 'ACTION_SESSION_COMMITTED' is missing @BroadcastBehavior +BroadcastBehavior: android.content.pm.PackageInstaller#ACTION_SESSION_UPDATED: + Field 'ACTION_SESSION_UPDATED' is missing @BroadcastBehavior +BroadcastBehavior: android.hardware.Camera#ACTION_NEW_PICTURE: + Field 'ACTION_NEW_PICTURE' is missing @BroadcastBehavior +BroadcastBehavior: android.hardware.Camera#ACTION_NEW_VIDEO: + Field 'ACTION_NEW_VIDEO' is missing @BroadcastBehavior +BroadcastBehavior: android.hardware.hdmi.HdmiControlManager#ACTION_OSD_MESSAGE: + Field 'ACTION_OSD_MESSAGE' is missing @BroadcastBehavior +BroadcastBehavior: android.hardware.input.InputManager#ACTION_QUERY_KEYBOARD_LAYOUTS: + Field 'ACTION_QUERY_KEYBOARD_LAYOUTS' is missing @BroadcastBehavior +BroadcastBehavior: android.hardware.usb.UsbManager#ACTION_USB_ACCESSORY_DETACHED: + Field 'ACTION_USB_ACCESSORY_DETACHED' is missing @BroadcastBehavior +BroadcastBehavior: android.hardware.usb.UsbManager#ACTION_USB_ACCESSORY_HANDSHAKE: + Field 'ACTION_USB_ACCESSORY_HANDSHAKE' is missing @BroadcastBehavior +BroadcastBehavior: android.hardware.usb.UsbManager#ACTION_USB_DEVICE_DETACHED: + Field 'ACTION_USB_DEVICE_DETACHED' is missing @BroadcastBehavior +BroadcastBehavior: android.hardware.usb.UsbManager#ACTION_USB_PORT_CHANGED: + Field 'ACTION_USB_PORT_CHANGED' is missing @BroadcastBehavior +BroadcastBehavior: android.hardware.usb.UsbManager#ACTION_USB_PORT_COMPLIANCE_CHANGED: + Field 'ACTION_USB_PORT_COMPLIANCE_CHANGED' is missing @BroadcastBehavior +BroadcastBehavior: android.hardware.usb.UsbManager#ACTION_USB_STATE: + Field 'ACTION_USB_STATE' is missing @BroadcastBehavior +BroadcastBehavior: android.media.AudioManager#ACTION_HDMI_AUDIO_PLUG: + Field 'ACTION_HDMI_AUDIO_PLUG' is missing @BroadcastBehavior +BroadcastBehavior: android.media.AudioManager#ACTION_HEADSET_PLUG: + Field 'ACTION_HEADSET_PLUG' is missing @BroadcastBehavior +BroadcastBehavior: android.media.AudioManager#ACTION_MICROPHONE_MUTE_CHANGED: + Field 'ACTION_MICROPHONE_MUTE_CHANGED' is missing @BroadcastBehavior +BroadcastBehavior: android.media.AudioManager#ACTION_SPEAKERPHONE_STATE_CHANGED: + Field 'ACTION_SPEAKERPHONE_STATE_CHANGED' is missing @BroadcastBehavior +BroadcastBehavior: android.media.tv.TvContract#ACTION_CHANNEL_BROWSABLE_REQUESTED: + Field 'ACTION_CHANNEL_BROWSABLE_REQUESTED' is missing @BroadcastBehavior +BroadcastBehavior: android.media.tv.TvContract#ACTION_INITIALIZE_PROGRAMS: + Field 'ACTION_INITIALIZE_PROGRAMS' is missing @BroadcastBehavior +BroadcastBehavior: android.media.tv.TvContract#ACTION_PREVIEW_PROGRAM_ADDED_TO_WATCH_NEXT: + Field 'ACTION_PREVIEW_PROGRAM_ADDED_TO_WATCH_NEXT' is missing @BroadcastBehavior +BroadcastBehavior: android.media.tv.TvContract#ACTION_PREVIEW_PROGRAM_BROWSABLE_DISABLED: + Field 'ACTION_PREVIEW_PROGRAM_BROWSABLE_DISABLED' is missing @BroadcastBehavior +BroadcastBehavior: android.media.tv.TvContract#ACTION_WATCH_NEXT_PROGRAM_BROWSABLE_DISABLED: + Field 'ACTION_WATCH_NEXT_PROGRAM_BROWSABLE_DISABLED' is missing @BroadcastBehavior +BroadcastBehavior: android.net.NetworkScoreManager#ACTION_SCORER_CHANGED: + Field 'ACTION_SCORER_CHANGED' is missing @BroadcastBehavior +BroadcastBehavior: android.net.NetworkScoreManager#ACTION_SCORE_NETWORKS: + Field 'ACTION_SCORE_NETWORKS' is missing @BroadcastBehavior +BroadcastBehavior: android.net.Proxy#PROXY_CHANGE_ACTION: + Field 'PROXY_CHANGE_ACTION' is missing @BroadcastBehavior +BroadcastBehavior: android.nfc.NfcAdapter#ACTION_ADAPTER_STATE_CHANGED: + Field 'ACTION_ADAPTER_STATE_CHANGED' is missing @BroadcastBehavior +BroadcastBehavior: android.nfc.NfcAdapter#ACTION_PREFERRED_PAYMENT_CHANGED: + Field 'ACTION_PREFERRED_PAYMENT_CHANGED' is missing @BroadcastBehavior +BroadcastBehavior: android.nfc.NfcAdapter#ACTION_REQUIRE_UNLOCK_FOR_NFC: + Field 'ACTION_REQUIRE_UNLOCK_FOR_NFC' is missing @BroadcastBehavior +BroadcastBehavior: android.nfc.NfcAdapter#ACTION_TRANSACTION_DETECTED: + Field 'ACTION_TRANSACTION_DETECTED' is missing @BroadcastBehavior +BroadcastBehavior: android.os.DropBoxManager#ACTION_DROPBOX_ENTRY_ADDED: + Field 'ACTION_DROPBOX_ENTRY_ADDED' is missing @BroadcastBehavior +BroadcastBehavior: android.provider.CalendarContract#ACTION_EVENT_REMINDER: + Field 'ACTION_EVENT_REMINDER' is missing @BroadcastBehavior +BroadcastBehavior: android.provider.ContactsContract.SimContacts#ACTION_SIM_ACCOUNTS_CHANGED: + Field 'ACTION_SIM_ACCOUNTS_CHANGED' is missing @BroadcastBehavior +BroadcastBehavior: android.provider.Telephony.Sms.Intents#ACTION_SMS_EMERGENCY_CB_RECEIVED: + Field 'ACTION_SMS_EMERGENCY_CB_RECEIVED' is missing @BroadcastBehavior +BroadcastBehavior: android.provider.Telephony.Sms.Intents#DATA_SMS_RECEIVED_ACTION: + Field 'DATA_SMS_RECEIVED_ACTION' is missing @BroadcastBehavior +BroadcastBehavior: android.provider.Telephony.Sms.Intents#SECRET_CODE_ACTION: + Field 'SECRET_CODE_ACTION' is missing @BroadcastBehavior +BroadcastBehavior: android.provider.Telephony.Sms.Intents#SIM_FULL_ACTION: + Field 'SIM_FULL_ACTION' is missing @BroadcastBehavior +BroadcastBehavior: android.provider.Telephony.Sms.Intents#SMS_CB_RECEIVED_ACTION: + Field 'SMS_CB_RECEIVED_ACTION' is missing @BroadcastBehavior +BroadcastBehavior: android.provider.Telephony.Sms.Intents#SMS_DELIVER_ACTION: + Field 'SMS_DELIVER_ACTION' is missing @BroadcastBehavior +BroadcastBehavior: android.provider.Telephony.Sms.Intents#SMS_RECEIVED_ACTION: + Field 'SMS_RECEIVED_ACTION' is missing @BroadcastBehavior +BroadcastBehavior: android.provider.Telephony.Sms.Intents#SMS_REJECTED_ACTION: + Field 'SMS_REJECTED_ACTION' is missing @BroadcastBehavior +BroadcastBehavior: android.provider.Telephony.Sms.Intents#SMS_SERVICE_CATEGORY_PROGRAM_DATA_RECEIVED_ACTION: + Field 'SMS_SERVICE_CATEGORY_PROGRAM_DATA_RECEIVED_ACTION' is missing @BroadcastBehavior +BroadcastBehavior: android.provider.Telephony.Sms.Intents#WAP_PUSH_DELIVER_ACTION: + Field 'WAP_PUSH_DELIVER_ACTION' is missing @BroadcastBehavior +BroadcastBehavior: android.provider.Telephony.Sms.Intents#WAP_PUSH_RECEIVED_ACTION: + Field 'WAP_PUSH_RECEIVED_ACTION' is missing @BroadcastBehavior +BroadcastBehavior: android.security.KeyChain#ACTION_KEYCHAIN_CHANGED: + Field 'ACTION_KEYCHAIN_CHANGED' is missing @BroadcastBehavior +BroadcastBehavior: android.security.KeyChain#ACTION_KEY_ACCESS_CHANGED: + Field 'ACTION_KEY_ACCESS_CHANGED' is missing @BroadcastBehavior +BroadcastBehavior: android.security.KeyChain#ACTION_STORAGE_CHANGED: + Field 'ACTION_STORAGE_CHANGED' is missing @BroadcastBehavior +BroadcastBehavior: android.security.KeyChain#ACTION_TRUST_STORE_CHANGED: + Field 'ACTION_TRUST_STORE_CHANGED' is missing @BroadcastBehavior +BroadcastBehavior: android.service.euicc.EuiccService#ACTION_DELETE_SUBSCRIPTION_PRIVILEGED: + Field 'ACTION_DELETE_SUBSCRIPTION_PRIVILEGED' is missing @BroadcastBehavior +BroadcastBehavior: android.service.euicc.EuiccService#ACTION_RENAME_SUBSCRIPTION_PRIVILEGED: + Field 'ACTION_RENAME_SUBSCRIPTION_PRIVILEGED' is missing @BroadcastBehavior +BroadcastBehavior: android.service.euicc.EuiccService#ACTION_START_EUICC_ACTIVATION: + Field 'ACTION_START_EUICC_ACTIVATION' is missing @BroadcastBehavior +BroadcastBehavior: android.service.euicc.EuiccService#ACTION_TOGGLE_SUBSCRIPTION_PRIVILEGED: + Field 'ACTION_TOGGLE_SUBSCRIPTION_PRIVILEGED' is missing @BroadcastBehavior +BroadcastBehavior: android.speech.tts.TextToSpeech#ACTION_TTS_QUEUE_PROCESSING_COMPLETED: + Field 'ACTION_TTS_QUEUE_PROCESSING_COMPLETED' is missing @BroadcastBehavior +BroadcastBehavior: android.speech.tts.TextToSpeech.Engine#ACTION_TTS_DATA_INSTALLED: + Field 'ACTION_TTS_DATA_INSTALLED' is missing @BroadcastBehavior +BroadcastBehavior: android.telephony.SubscriptionManager#ACTION_DEFAULT_SMS_SUBSCRIPTION_CHANGED: + Field 'ACTION_DEFAULT_SMS_SUBSCRIPTION_CHANGED' is missing @BroadcastBehavior +BroadcastBehavior: android.telephony.SubscriptionManager#ACTION_DEFAULT_SUBSCRIPTION_CHANGED: + Field 'ACTION_DEFAULT_SUBSCRIPTION_CHANGED' is missing @BroadcastBehavior +BroadcastBehavior: android.telephony.SubscriptionManager#ACTION_REFRESH_SUBSCRIPTION_PLANS: + Field 'ACTION_REFRESH_SUBSCRIPTION_PLANS' is missing @BroadcastBehavior +BroadcastBehavior: android.telephony.SubscriptionManager#ACTION_SUBSCRIPTION_PLANS_CHANGED: + Field 'ACTION_SUBSCRIPTION_PLANS_CHANGED' is missing @BroadcastBehavior +BroadcastBehavior: android.telephony.TelephonyManager#ACTION_CARRIER_SIGNAL_DEFAULT_NETWORK_AVAILABLE: + Field 'ACTION_CARRIER_SIGNAL_DEFAULT_NETWORK_AVAILABLE' is missing @BroadcastBehavior +BroadcastBehavior: android.telephony.TelephonyManager#ACTION_CARRIER_SIGNAL_PCO_VALUE: + Field 'ACTION_CARRIER_SIGNAL_PCO_VALUE' is missing @BroadcastBehavior +BroadcastBehavior: android.telephony.TelephonyManager#ACTION_CARRIER_SIGNAL_REDIRECTED: + Field 'ACTION_CARRIER_SIGNAL_REDIRECTED' is missing @BroadcastBehavior +BroadcastBehavior: android.telephony.TelephonyManager#ACTION_CARRIER_SIGNAL_REQUEST_NETWORK_FAILED: + Field 'ACTION_CARRIER_SIGNAL_REQUEST_NETWORK_FAILED' is missing @BroadcastBehavior +BroadcastBehavior: android.telephony.TelephonyManager#ACTION_CARRIER_SIGNAL_RESET: + Field 'ACTION_CARRIER_SIGNAL_RESET' is missing @BroadcastBehavior +BroadcastBehavior: android.telephony.TelephonyManager#ACTION_DEFAULT_DATA_SUBSCRIPTION_CHANGED: + Field 'ACTION_DEFAULT_DATA_SUBSCRIPTION_CHANGED' is missing @BroadcastBehavior +BroadcastBehavior: android.telephony.TelephonyManager#ACTION_DEFAULT_VOICE_SUBSCRIPTION_CHANGED: + Field 'ACTION_DEFAULT_VOICE_SUBSCRIPTION_CHANGED' is missing @BroadcastBehavior +BroadcastBehavior: android.telephony.TelephonyManager#ACTION_EMERGENCY_CALLBACK_MODE_CHANGED: + Field 'ACTION_EMERGENCY_CALLBACK_MODE_CHANGED' is missing @BroadcastBehavior +BroadcastBehavior: android.telephony.TelephonyManager#ACTION_EMERGENCY_CALL_STATE_CHANGED: + Field 'ACTION_EMERGENCY_CALL_STATE_CHANGED' is missing @BroadcastBehavior +BroadcastBehavior: android.telephony.TelephonyManager#ACTION_REQUEST_OMADM_CONFIGURATION_UPDATE: + Field 'ACTION_REQUEST_OMADM_CONFIGURATION_UPDATE' is missing @BroadcastBehavior +BroadcastBehavior: android.telephony.TelephonyManager#ACTION_SECRET_CODE: + Field 'ACTION_SECRET_CODE' is missing @BroadcastBehavior +BroadcastBehavior: android.telephony.TelephonyManager#ACTION_SHOW_NOTICE_ECM_BLOCK_OTHERS: + Field 'ACTION_SHOW_NOTICE_ECM_BLOCK_OTHERS' is missing @BroadcastBehavior +BroadcastBehavior: android.telephony.TelephonyManager#ACTION_SIM_APPLICATION_STATE_CHANGED: + Field 'ACTION_SIM_APPLICATION_STATE_CHANGED' is missing @BroadcastBehavior +BroadcastBehavior: android.telephony.TelephonyManager#ACTION_SIM_CARD_STATE_CHANGED: + Field 'ACTION_SIM_CARD_STATE_CHANGED' is missing @BroadcastBehavior +BroadcastBehavior: android.telephony.TelephonyManager#ACTION_SIM_SLOT_STATUS_CHANGED: + Field 'ACTION_SIM_SLOT_STATUS_CHANGED' is missing @BroadcastBehavior +BroadcastBehavior: android.telephony.TelephonyManager#ACTION_SUBSCRIPTION_CARRIER_IDENTITY_CHANGED: + Field 'ACTION_SUBSCRIPTION_CARRIER_IDENTITY_CHANGED' is missing @BroadcastBehavior +BroadcastBehavior: android.telephony.TelephonyManager#ACTION_SUBSCRIPTION_SPECIFIC_CARRIER_IDENTITY_CHANGED: + Field 'ACTION_SUBSCRIPTION_SPECIFIC_CARRIER_IDENTITY_CHANGED' is missing @BroadcastBehavior +BroadcastBehavior: android.telephony.euicc.EuiccManager#ACTION_NOTIFY_CARRIER_SETUP_INCOMPLETE: + Field 'ACTION_NOTIFY_CARRIER_SETUP_INCOMPLETE' is missing @BroadcastBehavior +BroadcastBehavior: android.telephony.euicc.EuiccManager#ACTION_OTA_STATUS_CHANGED: + Field 'ACTION_OTA_STATUS_CHANGED' is missing @BroadcastBehavior + + +DeprecationMismatch: android.accounts.AccountManager#newChooseAccountIntent(android.accounts.Account, java.util.ArrayList<android.accounts.Account>, String[], boolean, String, String, String[], android.os.Bundle): + Method android.accounts.AccountManager.newChooseAccountIntent(android.accounts.Account, java.util.ArrayList<android.accounts.Account>, String[], boolean, String, String, String[], android.os.Bundle): @Deprecated annotation (present) and @deprecated doc tag (not present) do not match +DeprecationMismatch: android.app.Activity#enterPictureInPictureMode(): + Method android.app.Activity.enterPictureInPictureMode(): @Deprecated annotation (present) and @deprecated doc tag (not present) do not match +DeprecationMismatch: android.app.Instrumentation#startAllocCounting(): + Method android.app.Instrumentation.startAllocCounting(): @Deprecated annotation (present) and @deprecated doc tag (not present) do not match +DeprecationMismatch: android.app.Instrumentation#stopAllocCounting(): + Method android.app.Instrumentation.stopAllocCounting(): @Deprecated annotation (present) and @deprecated doc tag (not present) do not match +DeprecationMismatch: android.app.Notification#bigContentView: + Field Notification.bigContentView: @Deprecated annotation (present) and @deprecated doc tag (not present) do not match +DeprecationMismatch: android.app.Notification#contentView: + Field Notification.contentView: @Deprecated annotation (present) and @deprecated doc tag (not present) do not match +DeprecationMismatch: android.app.Notification#headsUpContentView: + Field Notification.headsUpContentView: @Deprecated annotation (present) and @deprecated doc tag (not present) do not match +DeprecationMismatch: android.app.Notification#tickerView: + Field Notification.tickerView: @Deprecated annotation (present) and @deprecated doc tag (not present) do not match +DeprecationMismatch: android.app.Notification.Action.Builder#Builder(int, CharSequence, android.app.PendingIntent): + Constructor android.app.Notification.Action.Builder.Builder(int, CharSequence, android.app.PendingIntent): @Deprecated annotation (present) and @deprecated doc tag (not present) do not match +DeprecationMismatch: android.app.Notification.Action.WearableExtender#getCancelLabel(): + Method android.app.Notification.Action.WearableExtender.getCancelLabel(): @Deprecated annotation (present) and @deprecated doc tag (not present) do not match +DeprecationMismatch: android.app.Notification.Action.WearableExtender#getConfirmLabel(): + Method android.app.Notification.Action.WearableExtender.getConfirmLabel(): @Deprecated annotation (present) and @deprecated doc tag (not present) do not match +DeprecationMismatch: android.app.Notification.Action.WearableExtender#getInProgressLabel(): + Method android.app.Notification.Action.WearableExtender.getInProgressLabel(): @Deprecated annotation (present) and @deprecated doc tag (not present) do not match +DeprecationMismatch: android.app.Notification.Action.WearableExtender#setCancelLabel(CharSequence): + Method android.app.Notification.Action.WearableExtender.setCancelLabel(CharSequence): @Deprecated annotation (present) and @deprecated doc tag (not present) do not match +DeprecationMismatch: android.app.Notification.Action.WearableExtender#setConfirmLabel(CharSequence): + Method android.app.Notification.Action.WearableExtender.setConfirmLabel(CharSequence): @Deprecated annotation (present) and @deprecated doc tag (not present) do not match +DeprecationMismatch: android.app.Notification.Action.WearableExtender#setInProgressLabel(CharSequence): + Method android.app.Notification.Action.WearableExtender.setInProgressLabel(CharSequence): @Deprecated annotation (present) and @deprecated doc tag (not present) do not match +DeprecationMismatch: android.app.Notification.Builder#setContent(android.widget.RemoteViews): + Method android.app.Notification.Builder.setContent(android.widget.RemoteViews): @Deprecated annotation (present) and @deprecated doc tag (not present) do not match +DeprecationMismatch: android.app.Notification.Builder#setTicker(CharSequence, android.widget.RemoteViews): + Method android.app.Notification.Builder.setTicker(CharSequence, android.widget.RemoteViews): @Deprecated annotation (present) and @deprecated doc tag (not present) do not match +DeprecationMismatch: android.app.Notification.WearableExtender#getContentIcon(): + Method android.app.Notification.WearableExtender.getContentIcon(): @Deprecated annotation (present) and @deprecated doc tag (not present) do not match +DeprecationMismatch: android.app.Notification.WearableExtender#getContentIconGravity(): + Method android.app.Notification.WearableExtender.getContentIconGravity(): @Deprecated annotation (present) and @deprecated doc tag (not present) do not match +DeprecationMismatch: android.app.Notification.WearableExtender#getCustomContentHeight(): + Method android.app.Notification.WearableExtender.getCustomContentHeight(): @Deprecated annotation (present) and @deprecated doc tag (not present) do not match +DeprecationMismatch: android.app.Notification.WearableExtender#getCustomSizePreset(): + Method android.app.Notification.WearableExtender.getCustomSizePreset(): @Deprecated annotation (present) and @deprecated doc tag (not present) do not match +DeprecationMismatch: android.app.Notification.WearableExtender#getGravity(): + Method android.app.Notification.WearableExtender.getGravity(): @Deprecated annotation (present) and @deprecated doc tag (not present) do not match +DeprecationMismatch: android.app.Notification.WearableExtender#getHintAvoidBackgroundClipping(): + Method android.app.Notification.WearableExtender.getHintAvoidBackgroundClipping(): @Deprecated annotation (present) and @deprecated doc tag (not present) do not match +DeprecationMismatch: android.app.Notification.WearableExtender#getHintHideIcon(): + Method android.app.Notification.WearableExtender.getHintHideIcon(): @Deprecated annotation (present) and @deprecated doc tag (not present) do not match +DeprecationMismatch: android.app.Notification.WearableExtender#getHintScreenTimeout(): + Method android.app.Notification.WearableExtender.getHintScreenTimeout(): @Deprecated annotation (present) and @deprecated doc tag (not present) do not match +DeprecationMismatch: android.app.Notification.WearableExtender#getHintShowBackgroundOnly(): + Method android.app.Notification.WearableExtender.getHintShowBackgroundOnly(): @Deprecated annotation (present) and @deprecated doc tag (not present) do not match +DeprecationMismatch: android.app.Notification.WearableExtender#setContentIcon(int): + Method android.app.Notification.WearableExtender.setContentIcon(int): @Deprecated annotation (present) and @deprecated doc tag (not present) do not match +DeprecationMismatch: android.app.Notification.WearableExtender#setContentIconGravity(int): + Method android.app.Notification.WearableExtender.setContentIconGravity(int): @Deprecated annotation (present) and @deprecated doc tag (not present) do not match +DeprecationMismatch: android.app.Notification.WearableExtender#setCustomContentHeight(int): + Method android.app.Notification.WearableExtender.setCustomContentHeight(int): @Deprecated annotation (present) and @deprecated doc tag (not present) do not match +DeprecationMismatch: android.app.Notification.WearableExtender#setCustomSizePreset(int): + Method android.app.Notification.WearableExtender.setCustomSizePreset(int): @Deprecated annotation (present) and @deprecated doc tag (not present) do not match +DeprecationMismatch: android.app.Notification.WearableExtender#setGravity(int): + Method android.app.Notification.WearableExtender.setGravity(int): @Deprecated annotation (present) and @deprecated doc tag (not present) do not match +DeprecationMismatch: android.app.Notification.WearableExtender#setHintAvoidBackgroundClipping(boolean): + Method android.app.Notification.WearableExtender.setHintAvoidBackgroundClipping(boolean): @Deprecated annotation (present) and @deprecated doc tag (not present) do not match +DeprecationMismatch: android.app.Notification.WearableExtender#setHintHideIcon(boolean): + Method android.app.Notification.WearableExtender.setHintHideIcon(boolean): @Deprecated annotation (present) and @deprecated doc tag (not present) do not match +DeprecationMismatch: android.app.Notification.WearableExtender#setHintScreenTimeout(int): + Method android.app.Notification.WearableExtender.setHintScreenTimeout(int): @Deprecated annotation (present) and @deprecated doc tag (not present) do not match +DeprecationMismatch: android.app.Notification.WearableExtender#setHintShowBackgroundOnly(boolean): + Method android.app.Notification.WearableExtender.setHintShowBackgroundOnly(boolean): @Deprecated annotation (present) and @deprecated doc tag (not present) do not match +DeprecationMismatch: android.app.backup.BackupManager#selectBackupTransport(String): + Method android.app.backup.BackupManager.selectBackupTransport(String): @Deprecated annotation (present) and @deprecated doc tag (not present) do not match +DeprecationMismatch: android.content.Context#BIND_ALLOW_FOREGROUND_SERVICE_STARTS_FROM_BACKGROUND: + Field Context.BIND_ALLOW_FOREGROUND_SERVICE_STARTS_FROM_BACKGROUND: @Deprecated annotation (present) and @deprecated doc tag (not present) do not match +DeprecationMismatch: android.content.Context#POWER_WHITELIST_MANAGER: + Field Context.POWER_WHITELIST_MANAGER: @Deprecated annotation (present) and @deprecated doc tag (not present) do not match +DeprecationMismatch: android.content.Context#WIFI_RTT_SERVICE: + Field Context.WIFI_RTT_SERVICE: @Deprecated annotation (present) and @deprecated doc tag (not present) do not match +DeprecationMismatch: android.graphics.ComposeShader#ComposeShader(android.graphics.Shader, android.graphics.Shader, android.graphics.Xfermode): + Constructor android.graphics.ComposeShader.ComposeShader(android.graphics.Shader, android.graphics.Shader, android.graphics.Xfermode): @Deprecated annotation (present) and @deprecated doc tag (not present) do not match +DeprecationMismatch: android.graphics.PixelFormat#A_8: + Field PixelFormat.A_8: @Deprecated annotation (present) and @deprecated doc tag (not present) do not match +DeprecationMismatch: android.graphics.PixelFormat#LA_88: + Field PixelFormat.LA_88: @Deprecated annotation (present) and @deprecated doc tag (not present) do not match +DeprecationMismatch: android.graphics.PixelFormat#L_8: + Field PixelFormat.L_8: @Deprecated annotation (present) and @deprecated doc tag (not present) do not match +DeprecationMismatch: android.graphics.PixelFormat#RGBA_4444: + Field PixelFormat.RGBA_4444: @Deprecated annotation (present) and @deprecated doc tag (not present) do not match +DeprecationMismatch: android.graphics.PixelFormat#RGBA_5551: + Field PixelFormat.RGBA_5551: @Deprecated annotation (present) and @deprecated doc tag (not present) do not match +DeprecationMismatch: android.graphics.PixelFormat#RGB_332: + Field PixelFormat.RGB_332: @Deprecated annotation (present) and @deprecated doc tag (not present) do not match +DeprecationMismatch: android.hardware.hdmi.HdmiControlManager#RESULT_ALREADY_IN_PROGRESS: + Field HdmiControlManager.RESULT_ALREADY_IN_PROGRESS: @Deprecated annotation (present) and @deprecated doc tag (not present) do not match +DeprecationMismatch: android.media.tv.tuner.frontend.IsdbtFrontendSettings.Builder#setCodeRate(int): + Method android.media.tv.tuner.frontend.IsdbtFrontendSettings.Builder.setCodeRate(int): @Deprecated annotation (present) and @deprecated doc tag (not present) do not match +DeprecationMismatch: android.media.tv.tuner.frontend.IsdbtFrontendSettings.Builder#setModulation(int): + Method android.media.tv.tuner.frontend.IsdbtFrontendSettings.Builder.setModulation(int): @Deprecated annotation (present) and @deprecated doc tag (not present) do not match +DeprecationMismatch: android.opengl.EGL14#eglCreatePixmapSurface(android.opengl.EGLDisplay, android.opengl.EGLConfig, int, int[], int): + Method android.opengl.EGL14.eglCreatePixmapSurface(android.opengl.EGLDisplay, android.opengl.EGLConfig, int, int[], int): @Deprecated annotation (present) and @deprecated doc tag (not present) do not match +DeprecationMismatch: android.opengl.GLES20#GL_STENCIL_INDEX: + Field GLES20.GL_STENCIL_INDEX: @Deprecated annotation (present) and @deprecated doc tag (not present) do not match +DeprecationMismatch: android.opengl.GLSurfaceView#surfaceRedrawNeeded(android.view.SurfaceHolder): + Method android.opengl.GLSurfaceView.surfaceRedrawNeeded(android.view.SurfaceHolder): @Deprecated annotation (present) and @deprecated doc tag (not present) do not match +DeprecationMismatch: android.os.UserManager#setUserRestrictions(android.os.Bundle): + Method android.os.UserManager.setUserRestrictions(android.os.Bundle): @Deprecated annotation (present) and @deprecated doc tag (not present) do not match +DeprecationMismatch: android.os.UserManager#setUserRestrictions(android.os.Bundle, android.os.UserHandle): + Method android.os.UserManager.setUserRestrictions(android.os.Bundle, android.os.UserHandle): @Deprecated annotation (present) and @deprecated doc tag (not present) do not match +DeprecationMismatch: android.provider.Contacts.People#markAsContacted(android.content.ContentResolver, long): + Method android.provider.Contacts.People.markAsContacted(android.content.ContentResolver, long): @Deprecated annotation (present) and @deprecated doc tag (not present) do not match +DeprecationMismatch: android.renderscript.Type.CubemapFace#POSITVE_X: + Field Type.CubemapFace.POSITVE_X: @Deprecated annotation (present) and @deprecated doc tag (not present) do not match +DeprecationMismatch: android.renderscript.Type.CubemapFace#POSITVE_Y: + Field Type.CubemapFace.POSITVE_Y: @Deprecated annotation (present) and @deprecated doc tag (not present) do not match +DeprecationMismatch: android.renderscript.Type.CubemapFace#POSITVE_Z: + Field Type.CubemapFace.POSITVE_Z: @Deprecated annotation (present) and @deprecated doc tag (not present) do not match +DeprecationMismatch: android.speech.tts.TextToSpeech#areDefaultsEnforced(): + Method android.speech.tts.TextToSpeech.areDefaultsEnforced(): @Deprecated annotation (present) and @deprecated doc tag (not present) do not match +DeprecationMismatch: android.telecom.StatusHints#StatusHints(android.content.ComponentName, CharSequence, int, android.os.Bundle): + Constructor android.telecom.StatusHints.StatusHints(android.content.ComponentName, CharSequence, int, android.os.Bundle): @Deprecated annotation (present) and @deprecated doc tag (not present) do not match +DeprecationMismatch: android.telecom.StatusHints#getIcon(android.content.Context): + Method android.telecom.StatusHints.getIcon(android.content.Context): @Deprecated annotation (present) and @deprecated doc tag (not present) do not match +DeprecationMismatch: android.telecom.StatusHints#getIconResId(): + Method android.telecom.StatusHints.getIconResId(): @Deprecated annotation (present) and @deprecated doc tag (not present) do not match +DeprecationMismatch: android.telecom.StatusHints#getPackageName(): + Method android.telecom.StatusHints.getPackageName(): @Deprecated annotation (present) and @deprecated doc tag (not present) do not match +DeprecationMismatch: android.telephony.PhoneStateListener#PhoneStateListener(java.util.concurrent.Executor): + Constructor android.telephony.PhoneStateListener.PhoneStateListener(java.util.concurrent.Executor): @Deprecated annotation (present) and @deprecated doc tag (not present) do not match +DeprecationMismatch: android.telephony.SubscriptionManager#PROFILE_CLASS_DEFAULT: + Field SubscriptionManager.PROFILE_CLASS_DEFAULT: @Deprecated annotation (present) and @deprecated doc tag (not present) do not match +DeprecationMismatch: android.telephony.SubscriptionPlan.Builder#createRecurringDaily(java.time.ZonedDateTime): + Method android.telephony.SubscriptionPlan.Builder.createRecurringDaily(java.time.ZonedDateTime): @Deprecated annotation (present) and @deprecated doc tag (not present) do not match +DeprecationMismatch: android.telephony.SubscriptionPlan.Builder#createRecurringMonthly(java.time.ZonedDateTime): + Method android.telephony.SubscriptionPlan.Builder.createRecurringMonthly(java.time.ZonedDateTime): @Deprecated annotation (present) and @deprecated doc tag (not present) do not match +DeprecationMismatch: android.telephony.SubscriptionPlan.Builder#createRecurringWeekly(java.time.ZonedDateTime): + Method android.telephony.SubscriptionPlan.Builder.createRecurringWeekly(java.time.ZonedDateTime): @Deprecated annotation (present) and @deprecated doc tag (not present) do not match +DeprecationMismatch: android.text.format.DateUtils#FORMAT_12HOUR: + Field DateUtils.FORMAT_12HOUR: @Deprecated annotation (present) and @deprecated doc tag (not present) do not match +DeprecationMismatch: android.text.format.DateUtils#FORMAT_24HOUR: + Field DateUtils.FORMAT_24HOUR: @Deprecated annotation (present) and @deprecated doc tag (not present) do not match +DeprecationMismatch: android.text.format.DateUtils#FORMAT_CAP_AMPM: + Field DateUtils.FORMAT_CAP_AMPM: @Deprecated annotation (present) and @deprecated doc tag (not present) do not match +DeprecationMismatch: android.text.format.DateUtils#FORMAT_CAP_MIDNIGHT: + Field DateUtils.FORMAT_CAP_MIDNIGHT: @Deprecated annotation (present) and @deprecated doc tag (not present) do not match +DeprecationMismatch: android.text.format.DateUtils#FORMAT_CAP_NOON: + Field DateUtils.FORMAT_CAP_NOON: @Deprecated annotation (present) and @deprecated doc tag (not present) do not match +DeprecationMismatch: android.text.format.DateUtils#FORMAT_CAP_NOON_MIDNIGHT: + Field DateUtils.FORMAT_CAP_NOON_MIDNIGHT: @Deprecated annotation (present) and @deprecated doc tag (not present) do not match +DeprecationMismatch: android.text.format.DateUtils#FORMAT_NO_NOON_MIDNIGHT: + Field DateUtils.FORMAT_NO_NOON_MIDNIGHT: @Deprecated annotation (present) and @deprecated doc tag (not present) do not match +DeprecationMismatch: android.view.ViewGroup.LayoutParams#FILL_PARENT: + Field ViewGroup.LayoutParams.FILL_PARENT: @Deprecated annotation (present) and @deprecated doc tag (not present) do not match +DeprecationMismatch: android.view.Window#setTitleColor(int): + Method android.view.Window.setTitleColor(int): @Deprecated annotation (present) and @deprecated doc tag (not present) do not match +DeprecationMismatch: android.view.accessibility.AccessibilityEvent#MAX_TEXT_LENGTH: + Field AccessibilityEvent.MAX_TEXT_LENGTH: @Deprecated annotation (present) and @deprecated doc tag (not present) do not match +DeprecationMismatch: android.webkit.WebSettings#getSaveFormData(): + Method android.webkit.WebSettings.getSaveFormData(): @Deprecated annotation (present) and @deprecated doc tag (not present) do not match +DeprecationMismatch: android.webkit.WebView#shouldDelayChildPressedState(): + Method android.webkit.WebView.shouldDelayChildPressedState(): @Deprecated annotation (present) and @deprecated doc tag (not present) do not match +DeprecationMismatch: android.webkit.WebViewDatabase#clearFormData(): + Method android.webkit.WebViewDatabase.clearFormData(): @Deprecated annotation (present) and @deprecated doc tag (not present) do not match +DeprecationMismatch: android.webkit.WebViewDatabase#hasFormData(): + Method android.webkit.WebViewDatabase.hasFormData(): @Deprecated annotation (present) and @deprecated doc tag (not present) do not match +DeprecationMismatch: javax.microedition.khronos.egl.EGL10#eglCreatePixmapSurface(javax.microedition.khronos.egl.EGLDisplay, javax.microedition.khronos.egl.EGLConfig, Object, int[]): + Method javax.microedition.khronos.egl.EGL10.eglCreatePixmapSurface(javax.microedition.khronos.egl.EGLDisplay, javax.microedition.khronos.egl.EGLConfig, Object, int[]): @Deprecated annotation (present) and @deprecated doc tag (not present) do not match + + KotlinKeyword: android.app.Notification#when: Avoid field names that are Kotlin hard keywords ("when"); see https://android.github.io/kotlin-guides/interop.html#no-hard-keywords @@ -19,6 +527,1254 @@ ProtectedMember: android.view.ViewGroup#resetResolvedDrawables(): Protected methods not allowed; must be public: method android.view.ViewGroup.resetResolvedDrawables()} +RequiresPermission: android.accounts.AccountManager#getAccountsByTypeAndFeatures(String, String[], android.accounts.AccountManagerCallback<android.accounts.Account[]>, android.os.Handler): + Method 'getAccountsByTypeAndFeatures' documentation mentions permissions without declaring @RequiresPermission +RequiresPermission: android.accounts.AccountManager#hasFeatures(android.accounts.Account, String[], android.accounts.AccountManagerCallback<java.lang.Boolean>, android.os.Handler): + Method 'hasFeatures' documentation mentions permissions without declaring @RequiresPermission +RequiresPermission: android.app.ActivityManager#addOnUidImportanceListener(android.app.ActivityManager.OnUidImportanceListener, int): + Method 'addOnUidImportanceListener' documentation mentions permissions already declared by @RequiresPermission +RequiresPermission: android.app.ActivityManager#getHistoricalProcessExitReasons(String, int, int): + Method 'getHistoricalProcessExitReasons' documentation mentions permissions without declaring @RequiresPermission +RequiresPermission: android.app.ActivityManager#getProcessesInErrorState(): + Method 'getProcessesInErrorState' documentation mentions permissions without declaring @RequiresPermission +RequiresPermission: android.app.ActivityManager#getUidProcessCapabilities(int): + Method 'getUidProcessCapabilities' documentation mentions permissions already declared by @RequiresPermission +RequiresPermission: android.app.ActivityManager#getUidProcessState(int): + Method 'getUidProcessState' documentation mentions permissions already declared by @RequiresPermission +RequiresPermission: android.app.ActivityManager#killProcessesWhenImperceptible(int[], String): + Method 'killProcessesWhenImperceptible' documentation mentions permissions already declared by @RequiresPermission +RequiresPermission: android.app.ActivityManager#setDeviceLocales(android.os.LocaleList): + Method 'setDeviceLocales' documentation mentions permissions without declaring @RequiresPermission +RequiresPermission: android.app.AlarmManager#setAlarmClock(android.app.AlarmManager.AlarmClockInfo, android.app.PendingIntent): + Method 'setAlarmClock' documentation mentions permissions already declared by @RequiresPermission +RequiresPermission: android.app.AlarmManager#setExact(int, long, android.app.PendingIntent): + Method 'setExact' documentation mentions permissions already declared by @RequiresPermission +RequiresPermission: android.app.AlarmManager#setExactAndAllowWhileIdle(int, long, android.app.PendingIntent): + Method 'setExactAndAllowWhileIdle' documentation mentions permissions already declared by @RequiresPermission +RequiresPermission: android.app.AlarmManager#setTime(long): + Method 'setTime' documentation mentions permissions already declared by @RequiresPermission +RequiresPermission: android.app.AppOpsManager#isOpActive(String, int, String): + Method 'isOpActive' documentation mentions permissions without declaring @RequiresPermission +RequiresPermission: android.app.AppOpsManager#isOperationActive(int, int, String): + Method 'isOperationActive' documentation mentions permissions without declaring @RequiresPermission +RequiresPermission: android.app.AppOpsManager#startWatchingActive(String[], java.util.concurrent.Executor, android.app.AppOpsManager.OnOpActiveChangedListener): + Method 'startWatchingActive' documentation mentions permissions without declaring @RequiresPermission +RequiresPermission: android.app.AppOpsManager#startWatchingNoted(String[], java.util.concurrent.Executor, android.app.AppOpsManager.OnOpNotedListener): + Method 'startWatchingNoted' documentation mentions permissions already declared by @RequiresPermission +RequiresPermission: android.app.DownloadManager.Request#setDestinationInExternalPublicDir(String, String): + Method 'setDestinationInExternalPublicDir' documentation mentions permissions without declaring @RequiresPermission +RequiresPermission: android.app.DownloadManager.Request#setDestinationUri(android.net.Uri): + Method 'setDestinationUri' documentation mentions permissions without declaring @RequiresPermission +RequiresPermission: android.app.DownloadManager.Request#setNotificationVisibility(int): + Method 'setNotificationVisibility' documentation mentions permissions without declaring @RequiresPermission +RequiresPermission: android.app.DownloadManager.Request#setShowRunningNotification(boolean): + Method 'setShowRunningNotification' documentation mentions permissions without declaring @RequiresPermission +RequiresPermission: android.app.GameManager#getGameMode(String): + Method 'getGameMode' documentation mentions permissions already declared by @RequiresPermission +RequiresPermission: android.app.GameManager#isAngleEnabled(String): + Method 'isAngleEnabled' documentation mentions permissions already declared by @RequiresPermission +RequiresPermission: android.app.GameManager#setGameMode(String, int): + Method 'setGameMode' documentation mentions permissions already declared by @RequiresPermission +RequiresPermission: android.app.GameManager#updateCustomGameModeConfiguration(String, android.app.GameModeConfiguration): + Method 'updateCustomGameModeConfiguration' documentation mentions permissions already declared by @RequiresPermission +RequiresPermission: android.app.LocaleManager#getApplicationLocales(String): + Method 'getApplicationLocales' documentation mentions permissions already declared by @RequiresPermission +RequiresPermission: android.app.Notification.Builder#setFullScreenIntent(android.app.PendingIntent, boolean): + Method 'setFullScreenIntent' documentation mentions permissions without declaring @RequiresPermission +RequiresPermission: android.app.NotificationManager#canUseFullScreenIntent(): + Method 'canUseFullScreenIntent' documentation mentions permissions without declaring @RequiresPermission +RequiresPermission: android.app.Service#startForeground(int, android.app.Notification): + Method 'startForeground' documentation mentions permissions without declaring @RequiresPermission +RequiresPermission: android.app.StatusBarManager#canLaunchCaptureContentActivityForNote(android.app.Activity): + Method 'canLaunchCaptureContentActivityForNote' documentation mentions permissions already declared by @RequiresPermission +RequiresPermission: android.app.StatusBarManager#collapsePanels(): + Method 'collapsePanels' documentation mentions permissions already declared by @RequiresPermission +RequiresPermission: android.app.UiModeManager#releaseProjection(int): + Method 'releaseProjection' documentation mentions permissions already declared by @RequiresPermission +RequiresPermission: android.app.UiModeManager#requestProjection(int): + Method 'requestProjection' documentation mentions permissions already declared by @RequiresPermission +RequiresPermission: android.app.WallpaperInfo#getSettingsSliceUri(): + Method 'getSettingsSliceUri' documentation mentions permissions without declaring @RequiresPermission +RequiresPermission: android.app.WallpaperManager#clear(): + Method 'clear' documentation mentions permissions already declared by @RequiresPermission +RequiresPermission: android.app.WallpaperManager#clearWallpaper(int, int): + Method 'clearWallpaper' documentation mentions permissions already declared by @RequiresPermission +RequiresPermission: android.app.WallpaperManager#getDrawable(): + Method 'getDrawable' documentation mentions permissions already declared by @RequiresPermission +RequiresPermission: android.app.WallpaperManager#getDrawable(int): + Method 'getDrawable' documentation mentions permissions already declared by @RequiresPermission +RequiresPermission: android.app.WallpaperManager#getFastDrawable(): + Method 'getFastDrawable' documentation mentions permissions already declared by @RequiresPermission +RequiresPermission: android.app.WallpaperManager#getFastDrawable(int): + Method 'getFastDrawable' documentation mentions permissions already declared by @RequiresPermission +RequiresPermission: android.app.WallpaperManager#getWallpaperFile(int): + Method 'getWallpaperFile' documentation mentions permissions already declared by @RequiresPermission +RequiresPermission: android.app.WallpaperManager#getWallpaperInfo(int): + Method 'getWallpaperInfo' documentation mentions permissions without declaring @RequiresPermission +RequiresPermission: android.app.WallpaperManager#peekDrawable(): + Method 'peekDrawable' documentation mentions permissions already declared by @RequiresPermission +RequiresPermission: android.app.WallpaperManager#peekDrawable(int): + Method 'peekDrawable' documentation mentions permissions already declared by @RequiresPermission +RequiresPermission: android.app.WallpaperManager#peekFastDrawable(): + Method 'peekFastDrawable' documentation mentions permissions already declared by @RequiresPermission +RequiresPermission: android.app.WallpaperManager#peekFastDrawable(int): + Method 'peekFastDrawable' documentation mentions permissions already declared by @RequiresPermission +RequiresPermission: android.app.WallpaperManager#setBitmap(android.graphics.Bitmap): + Method 'setBitmap' documentation mentions permissions already declared by @RequiresPermission +RequiresPermission: android.app.WallpaperManager#setBitmap(android.graphics.Bitmap, android.graphics.Rect, boolean): + Method 'setBitmap' documentation mentions permissions already declared by @RequiresPermission +RequiresPermission: android.app.WallpaperManager#setDisplayPadding(android.graphics.Rect): + Method 'setDisplayPadding' documentation mentions permissions already declared by @RequiresPermission +RequiresPermission: android.app.WallpaperManager#setResource(int): + Method 'setResource' documentation mentions permissions already declared by @RequiresPermission +RequiresPermission: android.app.WallpaperManager#setStream(java.io.InputStream): + Method 'setStream' documentation mentions permissions already declared by @RequiresPermission +RequiresPermission: android.app.WallpaperManager#setStream(java.io.InputStream, android.graphics.Rect, boolean): + Method 'setStream' documentation mentions permissions already declared by @RequiresPermission +RequiresPermission: android.app.WallpaperManager#setWallpaperComponentWithFlags(android.content.ComponentName, int): + Method 'setWallpaperComponentWithFlags' documentation mentions permissions already declared by @RequiresPermission +RequiresPermission: android.app.WallpaperManager#suggestDesiredDimensions(int, int): + Method 'suggestDesiredDimensions' documentation mentions permissions without declaring @RequiresPermission +RequiresPermission: android.app.admin.DevicePolicyManager#addCrossProfileWidgetProvider(android.content.ComponentName, String): + Method 'addCrossProfileWidgetProvider' documentation mentions permissions already declared by @RequiresPermission +RequiresPermission: android.app.admin.DevicePolicyManager#addPersistentPreferredActivity(android.content.ComponentName, android.content.IntentFilter, android.content.ComponentName): + Method 'addPersistentPreferredActivity' documentation mentions permissions already declared by @RequiresPermission +RequiresPermission: android.app.admin.DevicePolicyManager#bindDeviceAdminServiceAsUser(android.content.ComponentName, android.content.Intent, android.content.ServiceConnection, int, android.os.UserHandle): + Method 'bindDeviceAdminServiceAsUser' documentation mentions permissions without declaring @RequiresPermission +RequiresPermission: android.app.admin.DevicePolicyManager#clearPackagePersistentPreferredActivities(android.content.ComponentName, String): + Method 'clearPackagePersistentPreferredActivities' documentation mentions permissions already declared by @RequiresPermission +RequiresPermission: android.app.admin.DevicePolicyManager#clearResetPasswordToken(android.content.ComponentName): + Method 'clearResetPasswordToken' documentation mentions permissions already declared by @RequiresPermission +RequiresPermission: android.app.admin.DevicePolicyManager#createAndProvisionManagedProfile(android.app.admin.ManagedProfileProvisioningParams): + Method 'createAndProvisionManagedProfile' documentation mentions permissions already declared by @RequiresPermission +RequiresPermission: android.app.admin.DevicePolicyManager#finalizeWorkProfileProvisioning(android.os.UserHandle, android.accounts.Account): + Method 'finalizeWorkProfileProvisioning' documentation mentions permissions already declared by @RequiresPermission +RequiresPermission: android.app.admin.DevicePolicyManager#forceUpdateUserSetupComplete(int): + Method 'forceUpdateUserSetupComplete' documentation mentions permissions without declaring @RequiresPermission +RequiresPermission: android.app.admin.DevicePolicyManager#generateKeyPair(android.content.ComponentName, String, android.security.keystore.KeyGenParameterSpec, int): + Method 'generateKeyPair' documentation mentions permissions already declared by @RequiresPermission +RequiresPermission: android.app.admin.DevicePolicyManager#getApplicationExemptions(String): + Method 'getApplicationExemptions' documentation mentions permissions already declared by @RequiresPermission +RequiresPermission: android.app.admin.DevicePolicyManager#getCrossProfileWidgetProviders(android.content.ComponentName): + Method 'getCrossProfileWidgetProviders' documentation mentions permissions already declared by @RequiresPermission +RequiresPermission: android.app.admin.DevicePolicyManager#getLockTaskFeatures(android.content.ComponentName): + Method 'getLockTaskFeatures' documentation mentions permissions already declared by @RequiresPermission +RequiresPermission: android.app.admin.DevicePolicyManager#getLockTaskPackages(android.content.ComponentName): + Method 'getLockTaskPackages' documentation mentions permissions already declared by @RequiresPermission +RequiresPermission: android.app.admin.DevicePolicyManager#getNearbyAppStreamingPolicy(): + Method 'getNearbyAppStreamingPolicy' documentation mentions permissions already declared by @RequiresPermission +RequiresPermission: android.app.admin.DevicePolicyManager#getNearbyNotificationStreamingPolicy(): + Method 'getNearbyNotificationStreamingPolicy' documentation mentions permissions already declared by @RequiresPermission +RequiresPermission: android.app.admin.DevicePolicyManager#getOrganizationName(android.content.ComponentName): + Method 'getOrganizationName' documentation mentions permissions already declared by @RequiresPermission +RequiresPermission: android.app.admin.DevicePolicyManager#getOwnerInstalledCaCerts(android.os.UserHandle): + Method 'getOwnerInstalledCaCerts' documentation mentions permissions without declaring @RequiresPermission +RequiresPermission: android.app.admin.DevicePolicyManager#getPasswordComplexity(): + Method 'getPasswordComplexity' documentation mentions permissions already declared by @RequiresPermission +RequiresPermission: android.app.admin.DevicePolicyManager#getShortSupportMessage(android.content.ComponentName): + Method 'getShortSupportMessage' documentation mentions permissions already declared by @RequiresPermission +RequiresPermission: android.app.admin.DevicePolicyManager#getUserControlDisabledPackages(android.content.ComponentName): + Method 'getUserControlDisabledPackages' documentation mentions permissions already declared by @RequiresPermission +RequiresPermission: android.app.admin.DevicePolicyManager#hasKeyPair(String): + Method 'hasKeyPair' documentation mentions permissions already declared by @RequiresPermission +RequiresPermission: android.app.admin.DevicePolicyManager#installKeyPair(android.content.ComponentName, java.security.PrivateKey, java.security.cert.Certificate, String): + Method 'installKeyPair' documentation mentions permissions already declared by @RequiresPermission +RequiresPermission: android.app.admin.DevicePolicyManager#installKeyPair(android.content.ComponentName, java.security.PrivateKey, java.security.cert.Certificate[], String, boolean): + Method 'installKeyPair' documentation mentions permissions already declared by @RequiresPermission +RequiresPermission: android.app.admin.DevicePolicyManager#installKeyPair(android.content.ComponentName, java.security.PrivateKey, java.security.cert.Certificate[], String, int): + Method 'installKeyPair' documentation mentions permissions already declared by @RequiresPermission +RequiresPermission: android.app.admin.DevicePolicyManager#isDeviceProvisioningConfigApplied(): + Method 'isDeviceProvisioningConfigApplied' documentation mentions permissions already declared by @RequiresPermission +RequiresPermission: android.app.admin.DevicePolicyManager#isPackageSuspended(android.content.ComponentName, String): + Method 'isPackageSuspended' documentation mentions permissions already declared by @RequiresPermission +RequiresPermission: android.app.admin.DevicePolicyManager#isResetPasswordTokenActive(android.content.ComponentName): + Method 'isResetPasswordTokenActive' documentation mentions permissions already declared by @RequiresPermission +RequiresPermission: android.app.admin.DevicePolicyManager#lockNow(int): + Method 'lockNow' documentation mentions permissions already declared by @RequiresPermission +RequiresPermission: android.app.admin.DevicePolicyManager#provisionFullyManagedDevice(android.app.admin.FullyManagedDeviceProvisioningParams): + Method 'provisionFullyManagedDevice' documentation mentions permissions already declared by @RequiresPermission +RequiresPermission: android.app.admin.DevicePolicyManager#removeCrossProfileWidgetProvider(android.content.ComponentName, String): + Method 'removeCrossProfileWidgetProvider' documentation mentions permissions already declared by @RequiresPermission +RequiresPermission: android.app.admin.DevicePolicyManager#sendLostModeLocationUpdate(java.util.concurrent.Executor, java.util.function.Consumer<java.lang.Boolean>): + Method 'sendLostModeLocationUpdate' documentation mentions permissions already declared by @RequiresPermission +RequiresPermission: android.app.admin.DevicePolicyManager#setActiveProfileOwner(android.content.ComponentName, String): + Method 'setActiveProfileOwner' documentation mentions permissions already declared by @RequiresPermission +RequiresPermission: android.app.admin.DevicePolicyManager#setAlwaysOnVpnPackage(android.content.ComponentName, String, boolean): + Method 'setAlwaysOnVpnPackage' documentation mentions permissions without declaring @RequiresPermission +RequiresPermission: android.app.admin.DevicePolicyManager#setApplicationExemptions(String, java.util.Set<java.lang.Integer>): + Method 'setApplicationExemptions' documentation mentions permissions already declared by @RequiresPermission +RequiresPermission: android.app.admin.DevicePolicyManager#setDeviceOwner(android.content.ComponentName, int): + Method 'setDeviceOwner' documentation mentions permissions already declared by @RequiresPermission +RequiresPermission: android.app.admin.DevicePolicyManager#setDeviceProvisioningConfigApplied(): + Method 'setDeviceProvisioningConfigApplied' documentation mentions permissions already declared by @RequiresPermission +RequiresPermission: android.app.admin.DevicePolicyManager#setLockTaskFeatures(android.content.ComponentName, int): + Method 'setLockTaskFeatures' documentation mentions permissions already declared by @RequiresPermission +RequiresPermission: android.app.admin.DevicePolicyManager#setLockTaskPackages(android.content.ComponentName, String[]): + Method 'setLockTaskPackages' documentation mentions permissions already declared by @RequiresPermission +RequiresPermission: android.app.admin.DevicePolicyManager#setPermittedInputMethods(android.content.ComponentName, java.util.List<java.lang.String>): + Method 'setPermittedInputMethods' documentation mentions permissions already declared by @RequiresPermission +RequiresPermission: android.app.admin.DevicePolicyManager#setUninstallBlocked(android.content.ComponentName, String, boolean): + Method 'setUninstallBlocked' documentation mentions permissions already declared by @RequiresPermission +RequiresPermission: android.app.admin.DevicePolicyManager#setUserControlDisabledPackages(android.content.ComponentName, java.util.List<java.lang.String>): + Method 'setUserControlDisabledPackages' documentation mentions permissions already declared by @RequiresPermission +RequiresPermission: android.app.admin.DevicePolicyManager#wipeData(int): + Method 'wipeData' documentation mentions permissions already declared by @RequiresPermission +RequiresPermission: android.app.admin.DevicePolicyManager#wipeData(int, CharSequence): + Method 'wipeData' documentation mentions permissions already declared by @RequiresPermission +RequiresPermission: android.app.admin.DevicePolicyManager#wipeDevice(int): + Method 'wipeDevice' documentation mentions permissions already declared by @RequiresPermission +RequiresPermission: android.app.admin.PolicyUpdateReceiver#onPolicyChanged(android.content.Context, String, android.os.Bundle, android.app.admin.TargetUser, android.app.admin.PolicyUpdateResult): + Method 'onPolicyChanged' documentation mentions permissions without declaring @RequiresPermission +RequiresPermission: android.app.admin.PolicyUpdateReceiver#onPolicySetResult(android.content.Context, String, android.os.Bundle, android.app.admin.TargetUser, android.app.admin.PolicyUpdateResult): + Method 'onPolicySetResult' documentation mentions permissions without declaring @RequiresPermission +RequiresPermission: android.app.backup.BackupManager#dataChanged(String): + Method 'dataChanged' documentation mentions permissions without declaring @RequiresPermission +RequiresPermission: android.app.backup.BackupManager#requestBackup(String[], android.app.backup.BackupObserver, android.app.backup.BackupManagerMonitor, int): + Method 'requestBackup' documentation mentions permissions already declared by @RequiresPermission +RequiresPermission: android.app.backup.BackupManager#setFrameworkSchedulingEnabled(boolean): + Method 'setFrameworkSchedulingEnabled' documentation mentions permissions already declared by @RequiresPermission +RequiresPermission: android.app.backup.BackupManager#updateTransportAttributes(android.content.ComponentName, String, android.content.Intent, String, android.content.Intent, CharSequence): + Method 'updateTransportAttributes' documentation mentions permissions already declared by @RequiresPermission +RequiresPermission: android.app.backup.BackupManager#updateTransportAttributes(android.content.ComponentName, String, android.content.Intent, String, android.content.Intent, String): + Method 'updateTransportAttributes' documentation mentions permissions already declared by @RequiresPermission +RequiresPermission: android.app.backup.RestoreSession#restoreAll(long, android.app.backup.RestoreObserver): + Method 'restoreAll' documentation mentions permissions without declaring @RequiresPermission +RequiresPermission: android.app.backup.RestoreSession#restoreAll(long, android.app.backup.RestoreObserver, android.app.backup.BackupManagerMonitor): + Method 'restoreAll' documentation mentions permissions without declaring @RequiresPermission +RequiresPermission: android.app.backup.RestoreSession#restorePackage(String, android.app.backup.RestoreObserver): + Method 'restorePackage' documentation mentions permissions without declaring @RequiresPermission +RequiresPermission: android.app.backup.RestoreSession#restorePackage(String, android.app.backup.RestoreObserver, android.app.backup.BackupManagerMonitor): + Method 'restorePackage' documentation mentions permissions without declaring @RequiresPermission +RequiresPermission: android.app.backup.RestoreSession#restorePackages(long, android.app.backup.RestoreObserver, java.util.Set<java.lang.String>): + Method 'restorePackages' documentation mentions permissions without declaring @RequiresPermission +RequiresPermission: android.app.backup.RestoreSession#restorePackages(long, android.app.backup.RestoreObserver, java.util.Set<java.lang.String>, android.app.backup.BackupManagerMonitor): + Method 'restorePackages' documentation mentions permissions without declaring @RequiresPermission +RequiresPermission: android.app.job.JobInfo.Builder#setRequiredNetwork(android.net.NetworkRequest): + Method 'setRequiredNetwork' documentation mentions permissions without declaring @RequiresPermission +RequiresPermission: android.app.job.JobInfo.Builder#setRequiredNetworkType(int): + Method 'setRequiredNetworkType' documentation mentions permissions without declaring @RequiresPermission +RequiresPermission: android.app.job.JobInfo.Builder#setUserInitiated(boolean): + Method 'setUserInitiated' documentation mentions permissions already declared by @RequiresPermission +RequiresPermission: android.app.job.JobParameters#isUserInitiatedJob(): + Method 'isUserInitiatedJob' documentation mentions permissions without declaring @RequiresPermission +RequiresPermission: android.app.job.JobScheduler#canRunUserInitiatedJobs(): + Method 'canRunUserInitiatedJobs' documentation mentions permissions without declaring @RequiresPermission +RequiresPermission: android.app.people.PeopleManager#isConversation(String, String): + Method 'isConversation' documentation mentions permissions already declared by @RequiresPermission +RequiresPermission: android.app.usage.StorageStatsManager#queryExternalStatsForUser(java.util.UUID, android.os.UserHandle): + Method 'queryExternalStatsForUser' documentation mentions permissions without declaring @RequiresPermission +RequiresPermission: android.app.usage.StorageStatsManager#queryStatsForPackage(java.util.UUID, String, android.os.UserHandle): + Method 'queryStatsForPackage' documentation mentions permissions without declaring @RequiresPermission +RequiresPermission: android.app.usage.StorageStatsManager#queryStatsForUid(java.util.UUID, int): + Method 'queryStatsForUid' documentation mentions permissions without declaring @RequiresPermission +RequiresPermission: android.app.usage.StorageStatsManager#queryStatsForUser(java.util.UUID, android.os.UserHandle): + Method 'queryStatsForUser' documentation mentions permissions without declaring @RequiresPermission +RequiresPermission: android.app.usage.UsageEvents.Event#getTaskRootClassName(): + Method 'getTaskRootClassName' documentation mentions permissions without declaring @RequiresPermission +RequiresPermission: android.app.usage.UsageEvents.Event#getTaskRootPackageName(): + Method 'getTaskRootPackageName' documentation mentions permissions without declaring @RequiresPermission +RequiresPermission: android.app.usage.UsageStatsManager#getAppStandbyBucket(String): + Method 'getAppStandbyBucket' documentation mentions permissions already declared by @RequiresPermission +RequiresPermission: android.app.usage.UsageStatsManager#getAppStandbyBuckets(): + Method 'getAppStandbyBuckets' documentation mentions permissions already declared by @RequiresPermission +RequiresPermission: android.app.usage.UsageStatsManager#isAppInactive(String): + Method 'isAppInactive' documentation mentions permissions without declaring @RequiresPermission +RequiresPermission: android.app.usage.UsageStatsManager#onCarrierPrivilegedAppsChanged(): + Method 'onCarrierPrivilegedAppsChanged' documentation mentions permissions already declared by @RequiresPermission +RequiresPermission: android.app.usage.UsageStatsManager#queryAndAggregateUsageStats(long, long): + Method 'queryAndAggregateUsageStats' documentation mentions permissions without declaring @RequiresPermission +RequiresPermission: android.app.usage.UsageStatsManager#queryConfigurations(int, long, long): + Method 'queryConfigurations' documentation mentions permissions without declaring @RequiresPermission +RequiresPermission: android.app.usage.UsageStatsManager#queryEventStats(int, long, long): + Method 'queryEventStats' documentation mentions permissions without declaring @RequiresPermission +RequiresPermission: android.app.usage.UsageStatsManager#queryEvents(long, long): + Method 'queryEvents' documentation mentions permissions without declaring @RequiresPermission +RequiresPermission: android.app.usage.UsageStatsManager#queryUsageStats(int, long, long): + Method 'queryUsageStats' documentation mentions permissions without declaring @RequiresPermission +RequiresPermission: android.app.usage.UsageStatsManager#registerAppUsageLimitObserver(int, String[], java.time.Duration, java.time.Duration, android.app.PendingIntent): + Method 'registerAppUsageLimitObserver' documentation mentions permissions already declared by @RequiresPermission +RequiresPermission: android.app.usage.UsageStatsManager#registerAppUsageObserver(int, String[], long, java.util.concurrent.TimeUnit, android.app.PendingIntent): + Method 'registerAppUsageObserver' documentation mentions permissions already declared by @RequiresPermission +RequiresPermission: android.app.usage.UsageStatsManager#registerUsageSessionObserver(int, String[], java.time.Duration, java.time.Duration, android.app.PendingIntent, android.app.PendingIntent): + Method 'registerUsageSessionObserver' documentation mentions permissions already declared by @RequiresPermission +RequiresPermission: android.app.usage.UsageStatsManager#reportUsageStart(android.app.Activity, String): + Method 'reportUsageStart' documentation mentions permissions without declaring @RequiresPermission +RequiresPermission: android.app.usage.UsageStatsManager#reportUsageStart(android.app.Activity, String, long): + Method 'reportUsageStart' documentation mentions permissions without declaring @RequiresPermission +RequiresPermission: android.app.usage.UsageStatsManager#unregisterAppUsageLimitObserver(int): + Method 'unregisterAppUsageLimitObserver' documentation mentions permissions already declared by @RequiresPermission +RequiresPermission: android.app.usage.UsageStatsManager#unregisterAppUsageObserver(int): + Method 'unregisterAppUsageObserver' documentation mentions permissions already declared by @RequiresPermission +RequiresPermission: android.app.usage.UsageStatsManager#unregisterUsageSessionObserver(int): + Method 'unregisterUsageSessionObserver' documentation mentions permissions already declared by @RequiresPermission +RequiresPermission: android.appwidget.AppWidgetManager#bindAppWidgetIdIfAllowed(int, android.os.UserHandle, android.content.ComponentName, android.os.Bundle): + Method 'bindAppWidgetIdIfAllowed' documentation mentions permissions without declaring @RequiresPermission +RequiresPermission: android.companion.CompanionDeviceManager#isDeviceAssociatedForWifiConnection(String, android.net.MacAddress, android.os.UserHandle): + Method 'isDeviceAssociatedForWifiConnection' documentation mentions permissions already declared by @RequiresPermission +RequiresPermission: android.companion.CompanionDeviceManager#startObservingDevicePresence(String): + Method 'startObservingDevicePresence' documentation mentions permissions already declared by @RequiresPermission +RequiresPermission: android.companion.CompanionDeviceManager#stopObservingDevicePresence(String): + Method 'stopObservingDevicePresence' documentation mentions permissions already declared by @RequiresPermission +RequiresPermission: android.companion.virtual.VirtualDeviceManager#createVirtualDevice(int, android.companion.virtual.VirtualDeviceParams): + Method 'createVirtualDevice' documentation mentions permissions already declared by @RequiresPermission +RequiresPermission: android.companion.virtual.VirtualDeviceParams.Builder#setLockState(int): + Method 'setLockState' documentation mentions permissions already declared by @RequiresPermission +RequiresPermission: android.content.ContentResolver#addPeriodicSync(android.accounts.Account, String, android.os.Bundle, long): + Method 'addPeriodicSync' documentation mentions permissions without declaring @RequiresPermission +RequiresPermission: android.content.ContentResolver#cancelSync(android.content.SyncRequest): + Method 'cancelSync' documentation mentions permissions without declaring @RequiresPermission +RequiresPermission: android.content.ContentResolver#getCurrentSync(): + Method 'getCurrentSync' documentation mentions permissions without declaring @RequiresPermission +RequiresPermission: android.content.ContentResolver#getCurrentSyncs(): + Method 'getCurrentSyncs' documentation mentions permissions without declaring @RequiresPermission +RequiresPermission: android.content.ContentResolver#getIsSyncable(android.accounts.Account, String): + Method 'getIsSyncable' documentation mentions permissions without declaring @RequiresPermission +RequiresPermission: android.content.ContentResolver#getMasterSyncAutomatically(): + Method 'getMasterSyncAutomatically' documentation mentions permissions without declaring @RequiresPermission +RequiresPermission: android.content.ContentResolver#getPeriodicSyncs(android.accounts.Account, String): + Method 'getPeriodicSyncs' documentation mentions permissions without declaring @RequiresPermission +RequiresPermission: android.content.ContentResolver#getSyncAutomatically(android.accounts.Account, String): + Method 'getSyncAutomatically' documentation mentions permissions without declaring @RequiresPermission +RequiresPermission: android.content.ContentResolver#isSyncActive(android.accounts.Account, String): + Method 'isSyncActive' documentation mentions permissions without declaring @RequiresPermission +RequiresPermission: android.content.ContentResolver#isSyncPending(android.accounts.Account, String): + Method 'isSyncPending' documentation mentions permissions without declaring @RequiresPermission +RequiresPermission: android.content.ContentResolver#removePeriodicSync(android.accounts.Account, String, android.os.Bundle): + Method 'removePeriodicSync' documentation mentions permissions without declaring @RequiresPermission +RequiresPermission: android.content.ContentResolver#setIsSyncable(android.accounts.Account, String, int): + Method 'setIsSyncable' documentation mentions permissions without declaring @RequiresPermission +RequiresPermission: android.content.ContentResolver#setMasterSyncAutomatically(boolean): + Method 'setMasterSyncAutomatically' documentation mentions permissions without declaring @RequiresPermission +RequiresPermission: android.content.ContentResolver#setSyncAutomatically(android.accounts.Account, String, boolean): + Method 'setSyncAutomatically' documentation mentions permissions without declaring @RequiresPermission +RequiresPermission: android.content.Context#bindServiceAsUser(android.content.Intent, android.content.ServiceConnection, int, android.os.UserHandle): + Method 'bindServiceAsUser' documentation mentions permissions already declared by @RequiresPermission +RequiresPermission: android.content.Context#clearWallpaper(): + Method 'clearWallpaper' documentation mentions permissions without declaring @RequiresPermission +RequiresPermission: android.content.Context#getExternalCacheDir(): + Method 'getExternalCacheDir' documentation mentions permissions without declaring @RequiresPermission +RequiresPermission: android.content.Context#getExternalCacheDirs(): + Method 'getExternalCacheDirs' documentation mentions permissions without declaring @RequiresPermission +RequiresPermission: android.content.Context#getExternalFilesDir(String): + Method 'getExternalFilesDir' documentation mentions permissions without declaring @RequiresPermission +RequiresPermission: android.content.Context#getExternalFilesDirs(String): + Method 'getExternalFilesDirs' documentation mentions permissions without declaring @RequiresPermission +RequiresPermission: android.content.Context#getExternalMediaDirs(): + Method 'getExternalMediaDirs' documentation mentions permissions without declaring @RequiresPermission +RequiresPermission: android.content.Context#getObbDir(): + Method 'getObbDir' documentation mentions permissions without declaring @RequiresPermission +RequiresPermission: android.content.Context#getObbDirs(): + Method 'getObbDirs' documentation mentions permissions without declaring @RequiresPermission +RequiresPermission: android.content.Context#removeStickyBroadcastAsUser(android.content.Intent, android.os.UserHandle): + Method 'removeStickyBroadcastAsUser' documentation mentions permissions already declared by @RequiresPermission +RequiresPermission: android.content.Context#setWallpaper(android.graphics.Bitmap): + Method 'setWallpaper' documentation mentions permissions without declaring @RequiresPermission +RequiresPermission: android.content.Context#setWallpaper(java.io.InputStream): + Method 'setWallpaper' documentation mentions permissions without declaring @RequiresPermission +RequiresPermission: android.content.pm.CrossProfileApps#canRequestInteractAcrossProfiles(): + Method 'canRequestInteractAcrossProfiles' documentation mentions permissions without declaring @RequiresPermission +RequiresPermission: android.content.pm.CrossProfileApps#startActivity(android.content.ComponentName, android.os.UserHandle): + Method 'startActivity' documentation mentions permissions already declared by @RequiresPermission +RequiresPermission: android.content.pm.CrossProfileApps#startActivity(android.content.ComponentName, android.os.UserHandle, android.app.Activity, android.os.Bundle): + Method 'startActivity' documentation mentions permissions already declared by @RequiresPermission +RequiresPermission: android.content.pm.CrossProfileApps#startActivity(android.content.Intent, android.os.UserHandle, android.app.Activity): + Method 'startActivity' documentation mentions permissions already declared by @RequiresPermission +RequiresPermission: android.content.pm.CrossProfileApps#startActivity(android.content.Intent, android.os.UserHandle, android.app.Activity, android.os.Bundle): + Method 'startActivity' documentation mentions permissions already declared by @RequiresPermission +RequiresPermission: android.content.pm.LauncherApps#getAllPackageInstallerSessions(): + Method 'getAllPackageInstallerSessions' documentation mentions permissions without declaring @RequiresPermission +RequiresPermission: android.content.pm.LauncherApps#registerPackageInstallerSessionCallback(java.util.concurrent.Executor, android.content.pm.PackageInstaller.SessionCallback): + Method 'registerPackageInstallerSessionCallback' documentation mentions permissions without declaring @RequiresPermission +RequiresPermission: android.content.pm.LauncherApps.Callback#onPackagesSuspended(String[], android.os.UserHandle, android.os.Bundle): + Method 'onPackagesSuspended' documentation mentions permissions without declaring @RequiresPermission +RequiresPermission: android.content.pm.PackageInstaller#getAllSessions(): + Method 'getAllSessions' documentation mentions permissions without declaring @RequiresPermission +RequiresPermission: android.content.pm.PackageInstaller#getSessionInfo(int): + Method 'getSessionInfo' documentation mentions permissions without declaring @RequiresPermission +RequiresPermission: android.content.pm.PackageInstaller#getStagedSessions(): + Method 'getStagedSessions' documentation mentions permissions without declaring @RequiresPermission +RequiresPermission: android.content.pm.PackageInstaller#registerSessionCallback(android.content.pm.PackageInstaller.SessionCallback): + Method 'registerSessionCallback' documentation mentions permissions without declaring @RequiresPermission +RequiresPermission: android.content.pm.PackageInstaller.Session#requestUserPreapproval(android.content.pm.PackageInstaller.PreapprovalDetails, android.content.IntentSender): + Method 'requestUserPreapproval' documentation mentions permissions without declaring @RequiresPermission +RequiresPermission: android.content.pm.PackageInstaller.SessionParams#setInstallerPackageName(String): + Method 'setInstallerPackageName' documentation mentions permissions without declaring @RequiresPermission +RequiresPermission: android.content.pm.PackageInstaller.SessionParams#setPermissionState(String, int): + Method 'setPermissionState' documentation mentions permissions already declared by @RequiresPermission +RequiresPermission: android.content.pm.PackageInstaller.SessionParams#setRequestUpdateOwnership(boolean): + Method 'setRequestUpdateOwnership' documentation mentions permissions already declared by @RequiresPermission +RequiresPermission: android.content.pm.PackageInstaller.SessionParams#setRequireUserAction(int): + Method 'setRequireUserAction' documentation mentions permissions without declaring @RequiresPermission +RequiresPermission: android.content.pm.PackageManager#canRequestPackageInstalls(): + Method 'canRequestPackageInstalls' documentation mentions permissions without declaring @RequiresPermission +RequiresPermission: android.content.pm.PackageManager#getSuspendedPackageAppExtras(): + Method 'getSuspendedPackageAppExtras' documentation mentions permissions without declaring @RequiresPermission +RequiresPermission: android.content.pm.PackageManager#getUnsuspendablePackages(String[]): + Method 'getUnsuspendablePackages' documentation mentions permissions already declared by @RequiresPermission +RequiresPermission: android.content.pm.PackageManager#grantRuntimePermission(String, String, android.os.UserHandle): + Method 'grantRuntimePermission' documentation mentions permissions already declared by @RequiresPermission +RequiresPermission: android.content.pm.PackageManager#isAutoRevokeWhitelisted(String): + Method 'isAutoRevokeWhitelisted' documentation mentions permissions already declared by @RequiresPermission +RequiresPermission: android.content.pm.PackageManager#isPackageSuspended(): + Method 'isPackageSuspended' documentation mentions permissions without declaring @RequiresPermission +RequiresPermission: android.content.pm.PackageManager#revokeRuntimePermission(String, String, android.os.UserHandle): + Method 'revokeRuntimePermission' documentation mentions permissions already declared by @RequiresPermission +RequiresPermission: android.content.pm.PackageManager#revokeRuntimePermission(String, String, android.os.UserHandle, String): + Method 'revokeRuntimePermission' documentation mentions permissions already declared by @RequiresPermission +RequiresPermission: android.content.pm.PackageManager#setDistractingPackageRestrictions(String[], int): + Method 'setDistractingPackageRestrictions' documentation mentions permissions already declared by @RequiresPermission +RequiresPermission: android.content.pm.PackageManager#setPackagesSuspended(String[], boolean, android.os.PersistableBundle, android.os.PersistableBundle, String): + Method 'setPackagesSuspended' documentation mentions permissions already declared by @RequiresPermission +RequiresPermission: android.content.pm.PackageManager#setPackagesSuspended(String[], boolean, android.os.PersistableBundle, android.os.PersistableBundle, android.content.pm.SuspendDialogInfo): + Method 'setPackagesSuspended' documentation mentions permissions already declared by @RequiresPermission +RequiresPermission: android.content.pm.PackageManager#setPackagesSuspended(String[], boolean, android.os.PersistableBundle, android.os.PersistableBundle, android.content.pm.SuspendDialogInfo, int): + Method 'setPackagesSuspended' documentation mentions permissions already declared by @RequiresPermission +RequiresPermission: android.content.pm.PackageManager#verifyIntentFilter(int, int, java.util.List<java.lang.String>): + Method 'verifyIntentFilter' documentation mentions permissions already declared by @RequiresPermission +RequiresPermission: android.hardware.Sensor#getHighestDirectReportRateLevel(): + Method 'getHighestDirectReportRateLevel' documentation mentions permissions without declaring @RequiresPermission +RequiresPermission: android.hardware.Sensor#getMinDelay(): + Method 'getMinDelay' documentation mentions permissions without declaring @RequiresPermission +RequiresPermission: android.hardware.camera2.CameraCharacteristics#getKeysNeedingPermission(): + Method 'getKeysNeedingPermission' documentation mentions permissions without declaring @RequiresPermission +RequiresPermission: android.hardware.camera2.CameraManager.AvailabilityCallback#onCameraClosed(String): + Method 'onCameraClosed' documentation mentions permissions already declared by @RequiresPermission +RequiresPermission: android.hardware.camera2.CameraManager.AvailabilityCallback#onCameraOpened(String, String): + Method 'onCameraOpened' documentation mentions permissions already declared by @RequiresPermission +RequiresPermission: android.hardware.devicestate.DeviceStateManager#cancelBaseStateOverride(): + Method 'cancelBaseStateOverride' documentation mentions permissions already declared by @RequiresPermission +RequiresPermission: android.hardware.devicestate.DeviceStateManager#cancelStateRequest(): + Method 'cancelStateRequest' documentation mentions permissions already declared by @RequiresPermission +RequiresPermission: android.hardware.devicestate.DeviceStateManager#requestBaseStateOverride(android.hardware.devicestate.DeviceStateRequest, java.util.concurrent.Executor, android.hardware.devicestate.DeviceStateRequest.Callback): + Method 'requestBaseStateOverride' documentation mentions permissions already declared by @RequiresPermission +RequiresPermission: android.hardware.devicestate.DeviceStateManager#requestState(android.hardware.devicestate.DeviceStateRequest, java.util.concurrent.Executor, android.hardware.devicestate.DeviceStateRequest.Callback): + Method 'requestState' documentation mentions permissions already declared by @RequiresPermission +RequiresPermission: android.hardware.hdmi.HdmiControlManager#getHdmiCecVersion(): + Method 'getHdmiCecVersion' documentation mentions permissions already declared by @RequiresPermission +RequiresPermission: android.hardware.hdmi.HdmiControlManager#setHdmiCecVersion(int): + Method 'setHdmiCecVersion' documentation mentions permissions already declared by @RequiresPermission +RequiresPermission: android.hardware.input.InputManager#addUniqueIdAssociation(String, String): + Method 'addUniqueIdAssociation' documentation mentions permissions without declaring @RequiresPermission +RequiresPermission: android.hardware.input.InputManager#removeUniqueIdAssociation(String): + Method 'removeUniqueIdAssociation' documentation mentions permissions without declaring @RequiresPermission +RequiresPermission: android.hardware.location.GeofenceHardware#addGeofence(int, int, android.hardware.location.GeofenceHardwareRequest, android.hardware.location.GeofenceHardwareCallback): + Method 'addGeofence' documentation mentions permissions without declaring @RequiresPermission +RequiresPermission: android.hardware.location.GeofenceHardware#getMonitoringTypes(): + Method 'getMonitoringTypes' documentation mentions permissions without declaring @RequiresPermission +RequiresPermission: android.hardware.location.GeofenceHardware#pauseGeofence(int, int): + Method 'pauseGeofence' documentation mentions permissions without declaring @RequiresPermission +RequiresPermission: android.hardware.location.GeofenceHardware#registerForMonitorStateChangeCallback(int, android.hardware.location.GeofenceHardwareMonitorCallback): + Method 'registerForMonitorStateChangeCallback' documentation mentions permissions without declaring @RequiresPermission +RequiresPermission: android.hardware.location.GeofenceHardware#removeGeofence(int, int): + Method 'removeGeofence' documentation mentions permissions without declaring @RequiresPermission +RequiresPermission: android.hardware.location.GeofenceHardware#resumeGeofence(int, int, int): + Method 'resumeGeofence' documentation mentions permissions without declaring @RequiresPermission +RequiresPermission: android.hardware.location.GeofenceHardware#unregisterForMonitorStateChangeCallback(int, android.hardware.location.GeofenceHardwareMonitorCallback): + Method 'unregisterForMonitorStateChangeCallback' documentation mentions permissions without declaring @RequiresPermission +RequiresPermission: android.hardware.usb.UsbManager#grantPermission(android.hardware.usb.UsbDevice, String): + Method 'grantPermission' documentation mentions permissions already declared by @RequiresPermission +RequiresPermission: android.hardware.usb.UsbManager#hasPermission(android.hardware.usb.UsbDevice): + Method 'hasPermission' documentation mentions permissions without declaring @RequiresPermission +RequiresPermission: android.hardware.usb.UsbManager#requestPermission(android.hardware.usb.UsbDevice, android.app.PendingIntent): + Method 'requestPermission' documentation mentions permissions without declaring @RequiresPermission +RequiresPermission: android.media.AudioAttributes.Builder#setHapticChannelsMuted(boolean): + Method 'setHapticChannelsMuted' documentation mentions permissions without declaring @RequiresPermission +RequiresPermission: android.media.AudioManager#getCallDownlinkExtractionAudioRecord(android.media.AudioFormat): + Method 'getCallDownlinkExtractionAudioRecord' documentation mentions permissions already declared by @RequiresPermission +RequiresPermission: android.media.AudioManager#getCallUplinkInjectionAudioTrack(android.media.AudioFormat): + Method 'getCallUplinkInjectionAudioTrack' documentation mentions permissions already declared by @RequiresPermission +RequiresPermission: android.media.AudioManager#registerAudioPolicy(android.media.audiopolicy.AudioPolicy): + Method 'registerAudioPolicy' documentation mentions permissions already declared by @RequiresPermission +RequiresPermission: android.media.AudioRecord#shareAudioHistory(String, long): + Method 'shareAudioHistory' documentation mentions permissions already declared by @RequiresPermission +RequiresPermission: android.media.AudioRecordingConfiguration#getClientUid(): + Method 'getClientUid' documentation mentions permissions already declared by @RequiresPermission +RequiresPermission: android.media.MediaCodec#createByCodecNameForClient(String, int, int): + Method 'createByCodecNameForClient' documentation mentions permissions already declared by @RequiresPermission +RequiresPermission: android.media.MediaExtractor#setDataSource(String): + Method 'setDataSource' documentation mentions permissions without declaring @RequiresPermission +RequiresPermission: android.media.MediaExtractor#setDataSource(String, java.util.Map<java.lang.String,java.lang.String>): + Method 'setDataSource' documentation mentions permissions without declaring @RequiresPermission +RequiresPermission: android.media.MediaExtractor#setDataSource(android.content.Context, android.net.Uri, java.util.Map<java.lang.String,java.lang.String>): + Method 'setDataSource' documentation mentions permissions without declaring @RequiresPermission +RequiresPermission: android.media.MediaPlayer#setWakeMode(android.content.Context, int): + Method 'setWakeMode' documentation mentions permissions without declaring @RequiresPermission +RequiresPermission: android.media.MediaRouter2#getInstance(android.content.Context, String): + Method 'getInstance' documentation mentions permissions already declared by @RequiresPermission +RequiresPermission: android.media.RingtoneManager#getCursor(): + Method 'getCursor' documentation mentions permissions without declaring @RequiresPermission +RequiresPermission: android.media.RingtoneManager#getValidRingtoneUri(android.content.Context): + Method 'getValidRingtoneUri' documentation mentions permissions without declaring @RequiresPermission +RequiresPermission: android.media.audiofx.HapticGenerator#setEnabled(boolean): + Method 'setEnabled' documentation mentions permissions without declaring @RequiresPermission +RequiresPermission: android.media.projection.MediaProjection#createVirtualDisplay(String, int, int, int, int, android.view.Surface, android.hardware.display.VirtualDisplay.Callback, android.os.Handler): + Method 'createVirtualDisplay' documentation mentions permissions without declaring @RequiresPermission +RequiresPermission: android.media.projection.MediaProjectionManager#getMediaProjection(int, android.content.Intent): + Method 'getMediaProjection' documentation mentions permissions without declaring @RequiresPermission +RequiresPermission: android.media.session.MediaSessionManager#addOnActiveSessionsChangedListener(android.media.session.MediaSessionManager.OnActiveSessionsChangedListener, android.content.ComponentName): + Method 'addOnActiveSessionsChangedListener' documentation mentions permissions without declaring @RequiresPermission +RequiresPermission: android.media.session.MediaSessionManager#addOnActiveSessionsChangedListener(android.media.session.MediaSessionManager.OnActiveSessionsChangedListener, android.content.ComponentName, android.os.Handler): + Method 'addOnActiveSessionsChangedListener' documentation mentions permissions without declaring @RequiresPermission +RequiresPermission: android.media.session.MediaSessionManager#addOnMediaKeyEventSessionChangedListener(java.util.concurrent.Executor, android.media.session.MediaSessionManager.OnMediaKeyEventSessionChangedListener): + Method 'addOnMediaKeyEventSessionChangedListener' documentation mentions permissions without declaring @RequiresPermission +RequiresPermission: android.media.session.MediaSessionManager#getActiveSessions(android.content.ComponentName): + Method 'getActiveSessions' documentation mentions permissions without declaring @RequiresPermission +RequiresPermission: android.media.session.MediaSessionManager#getMediaKeyEventSession(): + Method 'getMediaKeyEventSession' documentation mentions permissions without declaring @RequiresPermission +RequiresPermission: android.media.session.MediaSessionManager#getMediaKeyEventSessionPackageName(): + Method 'getMediaKeyEventSessionPackageName' documentation mentions permissions without declaring @RequiresPermission +RequiresPermission: android.media.session.MediaSessionManager#isTrustedForMediaControl(android.media.session.MediaSessionManager.RemoteUserInfo): + Method 'isTrustedForMediaControl' documentation mentions permissions without declaring @RequiresPermission +RequiresPermission: android.media.voice.KeyphraseModelManager#deleteKeyphraseSoundModel(int, java.util.Locale): + Method 'deleteKeyphraseSoundModel' documentation mentions permissions already declared by @RequiresPermission +RequiresPermission: android.media.voice.KeyphraseModelManager#getKeyphraseSoundModel(int, java.util.Locale): + Method 'getKeyphraseSoundModel' documentation mentions permissions already declared by @RequiresPermission +RequiresPermission: android.media.voice.KeyphraseModelManager#updateKeyphraseSoundModel(android.hardware.soundtrigger.SoundTrigger.KeyphraseSoundModel): + Method 'updateKeyphraseSoundModel' documentation mentions permissions already declared by @RequiresPermission +RequiresPermission: android.net.NetworkScoreManager#clearScores(): + Method 'clearScores' documentation mentions permissions already declared by @RequiresPermission +RequiresPermission: android.net.NetworkScoreManager#disableScoring(): + Method 'disableScoring' documentation mentions permissions already declared by @RequiresPermission +RequiresPermission: android.net.NetworkScoreManager#getActiveScorerPackage(): + Method 'getActiveScorerPackage' documentation mentions permissions already declared by @RequiresPermission +RequiresPermission: android.net.NetworkScoreManager#registerNetworkScoreCallback(int, int, java.util.concurrent.Executor, android.net.NetworkScoreManager.NetworkScoreCallback): + Method 'registerNetworkScoreCallback' documentation mentions permissions already declared by @RequiresPermission +RequiresPermission: android.net.NetworkScoreManager#requestScores(java.util.Collection<android.net.NetworkKey>): + Method 'requestScores' documentation mentions permissions already declared by @RequiresPermission +RequiresPermission: android.net.NetworkScoreManager#setActiveScorer(String): + Method 'setActiveScorer' documentation mentions permissions already declared by @RequiresPermission +RequiresPermission: android.net.VpnService#prepareAndAuthorize(android.content.Context): + Method 'prepareAndAuthorize' documentation mentions permissions already declared by @RequiresPermission +RequiresPermission: android.net.sip.SipAudioCall#setSpeakerMode(boolean): + Method 'setSpeakerMode' documentation mentions permissions without declaring @RequiresPermission +RequiresPermission: android.net.sip.SipAudioCall#startAudio(): + Method 'startAudio' documentation mentions permissions without declaring @RequiresPermission +RequiresPermission: android.net.vcn.VcnManager#addVcnNetworkPolicyChangeListener(java.util.concurrent.Executor, android.net.vcn.VcnManager.VcnNetworkPolicyChangeListener): + Method 'addVcnNetworkPolicyChangeListener' documentation mentions permissions already declared by @RequiresPermission +RequiresPermission: android.net.vcn.VcnManager#applyVcnNetworkPolicy(android.net.NetworkCapabilities, android.net.LinkProperties): + Method 'applyVcnNetworkPolicy' documentation mentions permissions already declared by @RequiresPermission +RequiresPermission: android.net.vcn.VcnManager#removeVcnNetworkPolicyChangeListener(android.net.vcn.VcnManager.VcnNetworkPolicyChangeListener): + Method 'removeVcnNetworkPolicyChangeListener' documentation mentions permissions already declared by @RequiresPermission +RequiresPermission: android.nfc.NfcAdapter#disableForegroundDispatch(android.app.Activity): + Method 'disableForegroundDispatch' documentation mentions permissions without declaring @RequiresPermission +RequiresPermission: android.nfc.NfcAdapter#enableForegroundDispatch(android.app.Activity, android.app.PendingIntent, android.content.IntentFilter[], String[][]): + Method 'enableForegroundDispatch' documentation mentions permissions without declaring @RequiresPermission +RequiresPermission: android.nfc.cardemulation.CardEmulation#isDefaultServiceForAid(android.content.ComponentName, String): + Method 'isDefaultServiceForAid' documentation mentions permissions without declaring @RequiresPermission +RequiresPermission: android.nfc.cardemulation.CardEmulation#isDefaultServiceForCategory(android.content.ComponentName, String): + Method 'isDefaultServiceForCategory' documentation mentions permissions without declaring @RequiresPermission +RequiresPermission: android.nfc.cardemulation.CardEmulation#setOffHostForService(android.content.ComponentName, String): + Method 'setOffHostForService' documentation mentions permissions already declared by @RequiresPermission +RequiresPermission: android.nfc.tech.IsoDep#getTimeout(): + Method 'getTimeout' documentation mentions permissions without declaring @RequiresPermission +RequiresPermission: android.nfc.tech.IsoDep#setTimeout(int): + Method 'setTimeout' documentation mentions permissions without declaring @RequiresPermission +RequiresPermission: android.nfc.tech.IsoDep#transceive(byte[]): + Method 'transceive' documentation mentions permissions without declaring @RequiresPermission +RequiresPermission: android.nfc.tech.MifareClassic#authenticateSectorWithKeyA(int, byte[]): + Method 'authenticateSectorWithKeyA' documentation mentions permissions without declaring @RequiresPermission +RequiresPermission: android.nfc.tech.MifareClassic#authenticateSectorWithKeyB(int, byte[]): + Method 'authenticateSectorWithKeyB' documentation mentions permissions without declaring @RequiresPermission +RequiresPermission: android.nfc.tech.MifareClassic#decrement(int, int): + Method 'decrement' documentation mentions permissions without declaring @RequiresPermission +RequiresPermission: android.nfc.tech.MifareClassic#getTimeout(): + Method 'getTimeout' documentation mentions permissions without declaring @RequiresPermission +RequiresPermission: android.nfc.tech.MifareClassic#increment(int, int): + Method 'increment' documentation mentions permissions without declaring @RequiresPermission +RequiresPermission: android.nfc.tech.MifareClassic#readBlock(int): + Method 'readBlock' documentation mentions permissions without declaring @RequiresPermission +RequiresPermission: android.nfc.tech.MifareClassic#restore(int): + Method 'restore' documentation mentions permissions without declaring @RequiresPermission +RequiresPermission: android.nfc.tech.MifareClassic#setTimeout(int): + Method 'setTimeout' documentation mentions permissions without declaring @RequiresPermission +RequiresPermission: android.nfc.tech.MifareClassic#transceive(byte[]): + Method 'transceive' documentation mentions permissions without declaring @RequiresPermission +RequiresPermission: android.nfc.tech.MifareClassic#transfer(int): + Method 'transfer' documentation mentions permissions without declaring @RequiresPermission +RequiresPermission: android.nfc.tech.MifareClassic#writeBlock(int, byte[]): + Method 'writeBlock' documentation mentions permissions without declaring @RequiresPermission +RequiresPermission: android.nfc.tech.MifareUltralight#getTimeout(): + Method 'getTimeout' documentation mentions permissions without declaring @RequiresPermission +RequiresPermission: android.nfc.tech.MifareUltralight#readPages(int): + Method 'readPages' documentation mentions permissions without declaring @RequiresPermission +RequiresPermission: android.nfc.tech.MifareUltralight#setTimeout(int): + Method 'setTimeout' documentation mentions permissions without declaring @RequiresPermission +RequiresPermission: android.nfc.tech.MifareUltralight#transceive(byte[]): + Method 'transceive' documentation mentions permissions without declaring @RequiresPermission +RequiresPermission: android.nfc.tech.MifareUltralight#writePage(int, byte[]): + Method 'writePage' documentation mentions permissions without declaring @RequiresPermission +RequiresPermission: android.nfc.tech.Ndef#getNdefMessage(): + Method 'getNdefMessage' documentation mentions permissions without declaring @RequiresPermission +RequiresPermission: android.nfc.tech.Ndef#isWritable(): + Method 'isWritable' documentation mentions permissions without declaring @RequiresPermission +RequiresPermission: android.nfc.tech.Ndef#makeReadOnly(): + Method 'makeReadOnly' documentation mentions permissions without declaring @RequiresPermission +RequiresPermission: android.nfc.tech.Ndef#writeNdefMessage(android.nfc.NdefMessage): + Method 'writeNdefMessage' documentation mentions permissions without declaring @RequiresPermission +RequiresPermission: android.nfc.tech.NdefFormatable#format(android.nfc.NdefMessage): + Method 'format' documentation mentions permissions without declaring @RequiresPermission +RequiresPermission: android.nfc.tech.NdefFormatable#formatReadOnly(android.nfc.NdefMessage): + Method 'formatReadOnly' documentation mentions permissions without declaring @RequiresPermission +RequiresPermission: android.nfc.tech.NfcA#getTimeout(): + Method 'getTimeout' documentation mentions permissions without declaring @RequiresPermission +RequiresPermission: android.nfc.tech.NfcA#setTimeout(int): + Method 'setTimeout' documentation mentions permissions without declaring @RequiresPermission +RequiresPermission: android.nfc.tech.NfcA#transceive(byte[]): + Method 'transceive' documentation mentions permissions without declaring @RequiresPermission +RequiresPermission: android.nfc.tech.NfcB#transceive(byte[]): + Method 'transceive' documentation mentions permissions without declaring @RequiresPermission +RequiresPermission: android.nfc.tech.NfcF#getTimeout(): + Method 'getTimeout' documentation mentions permissions without declaring @RequiresPermission +RequiresPermission: android.nfc.tech.NfcF#setTimeout(int): + Method 'setTimeout' documentation mentions permissions without declaring @RequiresPermission +RequiresPermission: android.nfc.tech.NfcF#transceive(byte[]): + Method 'transceive' documentation mentions permissions without declaring @RequiresPermission +RequiresPermission: android.nfc.tech.NfcV#transceive(byte[]): + Method 'transceive' documentation mentions permissions without declaring @RequiresPermission +RequiresPermission: android.nfc.tech.TagTechnology#close(): + Method 'close' documentation mentions permissions without declaring @RequiresPermission +RequiresPermission: android.nfc.tech.TagTechnology#connect(): + Method 'connect' documentation mentions permissions without declaring @RequiresPermission +RequiresPermission: android.os.BugreportManager#cancelBugreport(): + Method 'cancelBugreport' documentation mentions permissions without declaring @RequiresPermission +RequiresPermission: android.os.BugreportManager#preDumpUiData(): + Method 'preDumpUiData' documentation mentions permissions already declared by @RequiresPermission +RequiresPermission: android.os.Build#getSerial(): + Method 'getSerial' documentation mentions permissions already declared by @RequiresPermission +RequiresPermission: android.os.Debug#dumpService(String, java.io.FileDescriptor, String[]): + Method 'dumpService' documentation mentions permissions without declaring @RequiresPermission +RequiresPermission: android.os.DropBoxManager#getNextEntry(String, long): + Method 'getNextEntry' documentation mentions permissions already declared by @RequiresPermission +RequiresPermission: android.os.Environment#getExternalStorageDirectory(): + Method 'getExternalStorageDirectory' documentation mentions permissions without declaring @RequiresPermission +RequiresPermission: android.os.Environment#isExternalStorageManager(): + Method 'isExternalStorageManager' documentation mentions permissions without declaring @RequiresPermission +RequiresPermission: android.os.Environment#isExternalStorageManager(java.io.File): + Method 'isExternalStorageManager' documentation mentions permissions without declaring @RequiresPermission +RequiresPermission: android.os.PowerManager#dream(long): + Method 'dream' documentation mentions permissions already declared by @RequiresPermission +RequiresPermission: android.os.PowerManager#forceSuspend(): + Method 'forceSuspend' documentation mentions permissions already declared by @RequiresPermission +RequiresPermission: android.os.PowerManager#getPowerSaveModeTrigger(): + Method 'getPowerSaveModeTrigger' documentation mentions permissions without declaring @RequiresPermission +RequiresPermission: android.os.PowerManager#newWakeLock(int, String): + Method 'newWakeLock' documentation mentions permissions without declaring @RequiresPermission +RequiresPermission: android.os.PowerManager#reboot(String): + Method 'reboot' documentation mentions permissions already declared by @RequiresPermission +RequiresPermission: android.os.PowerManager#setBatteryDischargePrediction(java.time.Duration, boolean): + Method 'setBatteryDischargePrediction' documentation mentions permissions already declared by @RequiresPermission +RequiresPermission: android.os.PowerManager#setDynamicPowerSaveHint(boolean, int): + Method 'setDynamicPowerSaveHint' documentation mentions permissions already declared by @RequiresPermission +RequiresPermission: android.os.PowerManager#userActivity(long, int, int): + Method 'userActivity' documentation mentions permissions already declared by @RequiresPermission +RequiresPermission: android.os.RecoverySystem#rebootWipeUserData(android.content.Context): + Method 'rebootWipeUserData' documentation mentions permissions without declaring @RequiresPermission +RequiresPermission: android.os.StrictMode.VmPolicy.Builder#detectFileUriExposure(): + Method 'detectFileUriExposure' documentation mentions permissions without declaring @RequiresPermission +RequiresPermission: android.os.SystemUpdateManager#retrieveSystemUpdateInfo(): + Method 'retrieveSystemUpdateInfo' documentation mentions permissions already declared by @RequiresPermission +RequiresPermission: android.os.SystemUpdateManager#updateSystemUpdateInfo(android.os.PersistableBundle): + Method 'updateSystemUpdateInfo' documentation mentions permissions already declared by @RequiresPermission +RequiresPermission: android.os.UserManager#createUser(String, String, int): + Method 'createUser' documentation mentions permissions already declared by @RequiresPermission +RequiresPermission: android.os.UserManager#getUserProperties(android.os.UserHandle): + Method 'getUserProperties' documentation mentions permissions already declared by @RequiresPermission +RequiresPermission: android.os.UserManager#getUserRestrictions(android.os.UserHandle): + Method 'getUserRestrictions' documentation mentions permissions already declared by @RequiresPermission +RequiresPermission: android.os.UserManager#hasUserRestrictionForUser(String, android.os.UserHandle): + Method 'hasUserRestrictionForUser' documentation mentions permissions already declared by @RequiresPermission +RequiresPermission: android.os.UserManager#isManagedProfile(int): + Method 'isManagedProfile' documentation mentions permissions already declared by @RequiresPermission +RequiresPermission: android.os.UserManager#isRestrictedProfile(): + Method 'isRestrictedProfile' documentation mentions permissions without declaring @RequiresPermission +RequiresPermission: android.os.UserManager#isRestrictedProfile(android.os.UserHandle): + Method 'isRestrictedProfile' documentation mentions permissions already declared by @RequiresPermission +RequiresPermission: android.os.UserManager#isUserUnlocked(android.os.UserHandle): + Method 'isUserUnlocked' documentation mentions permissions already declared by @RequiresPermission +RequiresPermission: android.os.UserManager#isUserUnlockingOrUnlocked(android.os.UserHandle): + Method 'isUserUnlockingOrUnlocked' documentation mentions permissions already declared by @RequiresPermission +RequiresPermission: android.os.UserManager#preCreateUser(String): + Method 'preCreateUser' documentation mentions permissions already declared by @RequiresPermission +RequiresPermission: android.os.UserManager#requestQuietModeEnabled(boolean, android.os.UserHandle): + Method 'requestQuietModeEnabled' documentation mentions permissions already declared by @RequiresPermission +RequiresPermission: android.os.UserManager#setUserRestriction(String, boolean): + Method 'setUserRestriction' documentation mentions permissions already declared by @RequiresPermission +RequiresPermission: android.os.health.SystemHealthManager#takeUidSnapshot(int): + Method 'takeUidSnapshot' documentation mentions permissions without declaring @RequiresPermission +RequiresPermission: android.os.health.SystemHealthManager#takeUidSnapshots(int[]): + Method 'takeUidSnapshots' documentation mentions permissions without declaring @RequiresPermission +RequiresPermission: android.os.storage.StorageManager#getCloudMediaProvider(): + Method 'getCloudMediaProvider' documentation mentions permissions without declaring @RequiresPermission +RequiresPermission: android.os.storage.StorageManager#getManageSpaceActivityIntent(String, int): + Method 'getManageSpaceActivityIntent' documentation mentions permissions already declared by @RequiresPermission +RequiresPermission: android.os.storage.StorageManager#isAppIoBlocked(java.util.UUID, int, int, int): + Method 'isAppIoBlocked' documentation mentions permissions without declaring @RequiresPermission +RequiresPermission: android.os.storage.StorageVolume#createAccessIntent(String): + Method 'createAccessIntent' documentation mentions permissions without declaring @RequiresPermission +RequiresPermission: android.permission.PermissionManager#checkPermissionForDataDelivery(String, android.content.AttributionSource, String): + Method 'checkPermissionForDataDelivery' documentation mentions permissions already declared by @RequiresPermission +RequiresPermission: android.permission.PermissionManager#checkPermissionForDataDeliveryFromDataSource(String, android.content.AttributionSource, String): + Method 'checkPermissionForDataDeliveryFromDataSource' documentation mentions permissions already declared by @RequiresPermission +RequiresPermission: android.permission.PermissionManager#checkPermissionForStartDataDelivery(String, android.content.AttributionSource, String): + Method 'checkPermissionForStartDataDelivery' documentation mentions permissions already declared by @RequiresPermission +RequiresPermission: android.provider.Settings#canDrawOverlays(android.content.Context): + Method 'canDrawOverlays' documentation mentions permissions without declaring @RequiresPermission +RequiresPermission: android.provider.Settings.System#canWrite(android.content.Context): + Method 'canWrite' documentation mentions permissions without declaring @RequiresPermission +RequiresPermission: android.security.KeyChain#removeCredentialManagementApp(android.content.Context): + Method 'removeCredentialManagementApp' documentation mentions permissions already declared by @RequiresPermission +RequiresPermission: android.service.credentials.BeginCreateCredentialResponse.Builder#setRemoteCreateEntry(android.service.credentials.RemoteEntry): + Method 'setRemoteCreateEntry' documentation mentions permissions already declared by @RequiresPermission +RequiresPermission: android.service.credentials.BeginGetCredentialResponse.Builder#setRemoteCredentialEntry(android.service.credentials.RemoteEntry): + Method 'setRemoteCredentialEntry' documentation mentions permissions already declared by @RequiresPermission +RequiresPermission: android.service.credentials.CallingAppInfo#getOrigin(): + Method 'getOrigin' documentation mentions permissions without declaring @RequiresPermission +RequiresPermission: android.telecom.Call.Details#getContactDisplayName(): + Method 'getContactDisplayName' documentation mentions permissions without declaring @RequiresPermission +RequiresPermission: android.telecom.Call.Details#getContactPhotoUri(): + Method 'getContactPhotoUri' documentation mentions permissions without declaring @RequiresPermission +RequiresPermission: android.telecom.TelecomManager#acceptHandover(android.net.Uri, int, android.telecom.PhoneAccountHandle): + Method 'acceptHandover' documentation mentions permissions without declaring @RequiresPermission +RequiresPermission: android.telecom.TelecomManager#addNewIncomingCall(android.telecom.PhoneAccountHandle, android.os.Bundle): + Method 'addNewIncomingCall' documentation mentions permissions without declaring @RequiresPermission +RequiresPermission: android.telecom.TelecomManager#addNewIncomingConference(android.telecom.PhoneAccountHandle, android.os.Bundle): + Method 'addNewIncomingConference' documentation mentions permissions without declaring @RequiresPermission +RequiresPermission: android.telecom.TelecomManager#getCallState(): + Method 'getCallState' documentation mentions permissions already declared by @RequiresPermission +RequiresPermission: android.telecom.TelecomManager#getLine1Number(android.telecom.PhoneAccountHandle): + Method 'getLine1Number' documentation mentions permissions already declared by @RequiresPermission +RequiresPermission: android.telecom.TelecomManager#getOwnSelfManagedPhoneAccounts(): + Method 'getOwnSelfManagedPhoneAccounts' documentation mentions permissions already declared by @RequiresPermission +RequiresPermission: android.telecom.TelecomManager#getPhoneAccount(android.telecom.PhoneAccountHandle): + Method 'getPhoneAccount' documentation mentions permissions without declaring @RequiresPermission +RequiresPermission: android.telecom.TelecomManager#getSelfManagedPhoneAccounts(): + Method 'getSelfManagedPhoneAccounts' documentation mentions permissions already declared by @RequiresPermission +RequiresPermission: android.telecom.TelecomManager#hasManageOngoingCallsPermission(): + Method 'hasManageOngoingCallsPermission' documentation mentions permissions without declaring @RequiresPermission +RequiresPermission: android.telecom.TelecomManager#placeCall(android.net.Uri, android.os.Bundle): + Method 'placeCall' documentation mentions permissions already declared by @RequiresPermission +RequiresPermission: android.telecom.TelecomManager#showInCallScreen(boolean): + Method 'showInCallScreen' documentation mentions permissions already declared by @RequiresPermission +RequiresPermission: android.telecom.TelecomManager#silenceRinger(): + Method 'silenceRinger' documentation mentions permissions already declared by @RequiresPermission +RequiresPermission: android.telephony.CarrierConfigManager#getConfig(): + Method 'getConfig' documentation mentions permissions already declared by @RequiresPermission +RequiresPermission: android.telephony.CarrierConfigManager#getConfig(java.lang.String...): + Method 'getConfig' documentation mentions permissions already declared by @RequiresPermission +RequiresPermission: android.telephony.CarrierConfigManager#getConfigByComponentForSubId(String, int): + Method 'getConfigByComponentForSubId' documentation mentions permissions already declared by @RequiresPermission +RequiresPermission: android.telephony.CarrierConfigManager#getConfigForSubId(int): + Method 'getConfigForSubId' documentation mentions permissions already declared by @RequiresPermission +RequiresPermission: android.telephony.CarrierConfigManager#getConfigForSubId(int, java.lang.String...): + Method 'getConfigForSubId' documentation mentions permissions already declared by @RequiresPermission +RequiresPermission: android.telephony.CarrierConfigManager#notifyConfigChangedForSubId(int): + Method 'notifyConfigChangedForSubId' documentation mentions permissions already declared by @RequiresPermission +RequiresPermission: android.telephony.CellLocation#requestLocationUpdate(): + Method 'requestLocationUpdate' documentation mentions permissions without declaring @RequiresPermission +RequiresPermission: android.telephony.NetworkRegistrationInfo#getCellIdentity(): + Method 'getCellIdentity' documentation mentions permissions without declaring @RequiresPermission +RequiresPermission: android.telephony.PhoneStateListener#onActiveDataSubscriptionIdChanged(int): + Method 'onActiveDataSubscriptionIdChanged' documentation mentions permissions already declared by @RequiresPermission +RequiresPermission: android.telephony.PhoneStateListener#onCallAttributesChanged(android.telephony.CallAttributes): + Method 'onCallAttributesChanged' documentation mentions permissions already declared by @RequiresPermission +RequiresPermission: android.telephony.PhoneStateListener#onCallStateChanged(int, String): + Method 'onCallStateChanged' documentation mentions permissions already declared by @RequiresPermission +RequiresPermission: android.telephony.PhoneStateListener#onDisplayInfoChanged(android.telephony.TelephonyDisplayInfo): + Method 'onDisplayInfoChanged' documentation mentions permissions already declared by @RequiresPermission +RequiresPermission: android.telephony.PhoneStateListener#onPreciseDataConnectionStateChanged(android.telephony.PreciseDataConnectionState): + Method 'onPreciseDataConnectionStateChanged' documentation mentions permissions already declared by @RequiresPermission +RequiresPermission: android.telephony.PhoneStateListener#onRadioPowerStateChanged(int): + Method 'onRadioPowerStateChanged' documentation mentions permissions already declared by @RequiresPermission +RequiresPermission: android.telephony.PhoneStateListener#onServiceStateChanged(android.telephony.ServiceState): + Method 'onServiceStateChanged' documentation mentions permissions without declaring @RequiresPermission +RequiresPermission: android.telephony.ServiceState#getCdmaNetworkId(): + Method 'getCdmaNetworkId' documentation mentions permissions already declared by @RequiresPermission +RequiresPermission: android.telephony.ServiceState#getCdmaSystemId(): + Method 'getCdmaSystemId' documentation mentions permissions already declared by @RequiresPermission +RequiresPermission: android.telephony.ServiceState#getOperatorAlphaLong(): + Method 'getOperatorAlphaLong' documentation mentions permissions already declared by @RequiresPermission +RequiresPermission: android.telephony.ServiceState#getOperatorAlphaShort(): + Method 'getOperatorAlphaShort' documentation mentions permissions already declared by @RequiresPermission +RequiresPermission: android.telephony.ServiceState#getOperatorNumeric(): + Method 'getOperatorNumeric' documentation mentions permissions already declared by @RequiresPermission +RequiresPermission: android.telephony.SignalStrengthUpdateRequest.Builder#setSystemThresholdReportingRequestedWhileIdle(boolean): + Method 'setSystemThresholdReportingRequestedWhileIdle' documentation mentions permissions already declared by @RequiresPermission +RequiresPermission: android.telephony.SmsManager#disableCellBroadcastRange(int, int, int): + Method 'disableCellBroadcastRange' documentation mentions permissions without declaring @RequiresPermission +RequiresPermission: android.telephony.SmsManager#enableCellBroadcastRange(int, int, int): + Method 'enableCellBroadcastRange' documentation mentions permissions without declaring @RequiresPermission +RequiresPermission: android.telephony.SmsManager#getSmscAddress(): + Method 'getSmscAddress' documentation mentions permissions already declared by @RequiresPermission +RequiresPermission: android.telephony.SmsManager#injectSmsPdu(byte[], String, android.app.PendingIntent): + Method 'injectSmsPdu' documentation mentions permissions without declaring @RequiresPermission +RequiresPermission: android.telephony.SmsManager#sendDataMessage(String, String, short, byte[], android.app.PendingIntent, android.app.PendingIntent): + Method 'sendDataMessage' documentation mentions permissions without declaring @RequiresPermission +RequiresPermission: android.telephony.SmsManager#sendMultipartTextMessage(String, String, java.util.ArrayList<java.lang.String>, java.util.ArrayList<android.app.PendingIntent>, java.util.ArrayList<android.app.PendingIntent>): + Method 'sendMultipartTextMessage' documentation mentions permissions without declaring @RequiresPermission +RequiresPermission: android.telephony.SmsManager#sendMultipartTextMessageWithoutPersisting(String, String, java.util.List<java.lang.String>, java.util.List<android.app.PendingIntent>, java.util.List<android.app.PendingIntent>): + Method 'sendMultipartTextMessageWithoutPersisting' documentation mentions permissions already declared by @RequiresPermission +RequiresPermission: android.telephony.SmsManager#sendTextMessage(String, String, String, android.app.PendingIntent, android.app.PendingIntent): + Method 'sendTextMessage' documentation mentions permissions without declaring @RequiresPermission +RequiresPermission: android.telephony.SmsManager#sendTextMessageWithoutPersisting(String, String, String, android.app.PendingIntent, android.app.PendingIntent): + Method 'sendTextMessageWithoutPersisting' documentation mentions permissions already declared by @RequiresPermission +RequiresPermission: android.telephony.SmsManager#setSmscAddress(String): + Method 'setSmscAddress' documentation mentions permissions already declared by @RequiresPermission +RequiresPermission: android.telephony.SubscriptionManager#addSubscriptionsIntoGroup(java.util.List<java.lang.Integer>, android.os.ParcelUuid): + Method 'addSubscriptionsIntoGroup' documentation mentions permissions already declared by @RequiresPermission +RequiresPermission: android.telephony.SubscriptionManager#createSubscriptionGroup(java.util.List<java.lang.Integer>): + Method 'createSubscriptionGroup' documentation mentions permissions already declared by @RequiresPermission +RequiresPermission: android.telephony.SubscriptionManager#getActiveSubscriptionInfo(int): + Method 'getActiveSubscriptionInfo' documentation mentions permissions already declared by @RequiresPermission +RequiresPermission: android.telephony.SubscriptionManager#getActiveSubscriptionInfoForSimSlotIndex(int): + Method 'getActiveSubscriptionInfoForSimSlotIndex' documentation mentions permissions already declared by @RequiresPermission +RequiresPermission: android.telephony.SubscriptionManager#getActiveSubscriptionInfoList(): + Method 'getActiveSubscriptionInfoList' documentation mentions permissions already declared by @RequiresPermission +RequiresPermission: android.telephony.SubscriptionManager#getAvailableSubscriptionInfoList(): + Method 'getAvailableSubscriptionInfoList' documentation mentions permissions without declaring @RequiresPermission +RequiresPermission: android.telephony.SubscriptionManager#getCompleteActiveSubscriptionInfoList(): + Method 'getCompleteActiveSubscriptionInfoList' documentation mentions permissions without declaring @RequiresPermission +RequiresPermission: android.telephony.SubscriptionManager#getOpportunisticSubscriptions(): + Method 'getOpportunisticSubscriptions' documentation mentions permissions already declared by @RequiresPermission +RequiresPermission: android.telephony.SubscriptionManager#getResourcesForSubId(android.content.Context, int): + Method 'getResourcesForSubId' documentation mentions permissions without declaring @RequiresPermission +RequiresPermission: android.telephony.SubscriptionManager#getSubscriptionsInGroup(android.os.ParcelUuid): + Method 'getSubscriptionsInGroup' documentation mentions permissions already declared by @RequiresPermission +RequiresPermission: android.telephony.SubscriptionManager#removeSubscriptionsFromGroup(java.util.List<java.lang.Integer>, android.os.ParcelUuid): + Method 'removeSubscriptionsFromGroup' documentation mentions permissions already declared by @RequiresPermission +RequiresPermission: android.telephony.SubscriptionManager#requestEmbeddedSubscriptionInfoListRefresh(): + Method 'requestEmbeddedSubscriptionInfoListRefresh' documentation mentions permissions without declaring @RequiresPermission +RequiresPermission: android.telephony.SubscriptionManager#requestEmbeddedSubscriptionInfoListRefresh(int): + Method 'requestEmbeddedSubscriptionInfoListRefresh' documentation mentions permissions without declaring @RequiresPermission +RequiresPermission: android.telephony.SubscriptionManager#setOpportunistic(boolean, int): + Method 'setOpportunistic' documentation mentions permissions already declared by @RequiresPermission +RequiresPermission: android.telephony.SubscriptionManager#setPreferredDataSubscriptionId(int, boolean, java.util.concurrent.Executor, java.util.function.Consumer<java.lang.Integer>): + Method 'setPreferredDataSubscriptionId' documentation mentions permissions already declared by @RequiresPermission +RequiresPermission: android.telephony.TelephonyCallback.ActiveDataSubscriptionIdListener#onActiveDataSubscriptionIdChanged(int): + Method 'onActiveDataSubscriptionIdChanged' documentation mentions permissions already declared by @RequiresPermission +RequiresPermission: android.telephony.TelephonyCallback.BarringInfoListener#onBarringInfoChanged(android.telephony.BarringInfo): + Method 'onBarringInfoChanged' documentation mentions permissions already declared by @RequiresPermission +RequiresPermission: android.telephony.TelephonyCallback.CallAttributesListener#onCallAttributesChanged(android.telephony.CallAttributes): + Method 'onCallAttributesChanged' documentation mentions permissions already declared by @RequiresPermission +RequiresPermission: android.telephony.TelephonyCallback.CallAttributesListener#onCallStatesChanged(java.util.List<android.telephony.CallState>): + Method 'onCallStatesChanged' documentation mentions permissions already declared by @RequiresPermission +RequiresPermission: android.telephony.TelephonyCallback.CallForwardingIndicatorListener#onCallForwardingIndicatorChanged(boolean): + Method 'onCallForwardingIndicatorChanged' documentation mentions permissions already declared by @RequiresPermission +RequiresPermission: android.telephony.TelephonyCallback.DataEnabledListener#onDataEnabledChanged(boolean, int): + Method 'onDataEnabledChanged' documentation mentions permissions already declared by @RequiresPermission +RequiresPermission: android.telephony.TelephonyCallback.EmergencyNumberListListener#onEmergencyNumberListChanged(java.util.Map<java.lang.Integer,java.util.List<android.telephony.emergency.EmergencyNumber>>): + Method 'onEmergencyNumberListChanged' documentation mentions permissions already declared by @RequiresPermission +RequiresPermission: android.telephony.TelephonyCallback.ImsCallDisconnectCauseListener#onImsCallDisconnectCauseChanged(android.telephony.ims.ImsReasonInfo): + Method 'onImsCallDisconnectCauseChanged' documentation mentions permissions already declared by @RequiresPermission +RequiresPermission: android.telephony.TelephonyCallback.MessageWaitingIndicatorListener#onMessageWaitingIndicatorChanged(boolean): + Method 'onMessageWaitingIndicatorChanged' documentation mentions permissions already declared by @RequiresPermission +RequiresPermission: android.telephony.TelephonyCallback.PhysicalChannelConfigListener#onPhysicalChannelConfigChanged(java.util.List<android.telephony.PhysicalChannelConfig>): + Method 'onPhysicalChannelConfigChanged' documentation mentions permissions already declared by @RequiresPermission +RequiresPermission: android.telephony.TelephonyCallback.PreciseCallStateListener#onPreciseCallStateChanged(android.telephony.PreciseCallState): + Method 'onPreciseCallStateChanged' documentation mentions permissions already declared by @RequiresPermission +RequiresPermission: android.telephony.TelephonyCallback.PreciseDataConnectionStateListener#onPreciseDataConnectionStateChanged(android.telephony.PreciseDataConnectionState): + Method 'onPreciseDataConnectionStateChanged' documentation mentions permissions already declared by @RequiresPermission +RequiresPermission: android.telephony.TelephonyCallback.RegistrationFailedListener#onRegistrationFailed(android.telephony.CellIdentity, String, int, int, int): + Method 'onRegistrationFailed' documentation mentions permissions already declared by @RequiresPermission +RequiresPermission: android.telephony.TelephonyCallback.ServiceStateListener#onServiceStateChanged(android.telephony.ServiceState): + Method 'onServiceStateChanged' documentation mentions permissions without declaring @RequiresPermission +RequiresPermission: android.telephony.TelephonyManager#bootstrapAuthenticationRequest(int, android.net.Uri, android.telephony.gba.UaSecurityProtocolIdentifier, boolean, java.util.concurrent.Executor, android.telephony.TelephonyManager.BootstrapAuthenticationCallback): + Method 'bootstrapAuthenticationRequest' documentation mentions permissions already declared by @RequiresPermission +RequiresPermission: android.telephony.TelephonyManager#changeIccLockPin(String, String): + Method 'changeIccLockPin' documentation mentions permissions already declared by @RequiresPermission +RequiresPermission: android.telephony.TelephonyManager#clearRadioPowerOffForReason(int): + Method 'clearRadioPowerOffForReason' documentation mentions permissions already declared by @RequiresPermission +RequiresPermission: android.telephony.TelephonyManager#clearSignalStrengthUpdateRequest(android.telephony.SignalStrengthUpdateRequest): + Method 'clearSignalStrengthUpdateRequest' documentation mentions permissions already declared by @RequiresPermission +RequiresPermission: android.telephony.TelephonyManager#doesSwitchMultiSimConfigTriggerReboot(): + Method 'doesSwitchMultiSimConfigTriggerReboot' documentation mentions permissions already declared by @RequiresPermission +RequiresPermission: android.telephony.TelephonyManager#enableModemForSlot(int, boolean): + Method 'enableModemForSlot' documentation mentions permissions already declared by @RequiresPermission +RequiresPermission: android.telephony.TelephonyManager#getAidForAppType(int): + Method 'getAidForAppType' documentation mentions permissions already declared by @RequiresPermission +RequiresPermission: android.telephony.TelephonyManager#getAllowedNetworkTypes(): + Method 'getAllowedNetworkTypes' documentation mentions permissions already declared by @RequiresPermission +RequiresPermission: android.telephony.TelephonyManager#getAllowedNetworkTypesBitmask(): + Method 'getAllowedNetworkTypesBitmask' documentation mentions permissions already declared by @RequiresPermission +RequiresPermission: android.telephony.TelephonyManager#getAllowedNetworkTypesForReason(int): + Method 'getAllowedNetworkTypesForReason' documentation mentions permissions already declared by @RequiresPermission +RequiresPermission: android.telephony.TelephonyManager#getCallState(): + Method 'getCallState' documentation mentions permissions already declared by @RequiresPermission +RequiresPermission: android.telephony.TelephonyManager#getCallStateForSubscription(): + Method 'getCallStateForSubscription' documentation mentions permissions already declared by @RequiresPermission +RequiresPermission: android.telephony.TelephonyManager#getCarrierConfig(): + Method 'getCarrierConfig' documentation mentions permissions already declared by @RequiresPermission +RequiresPermission: android.telephony.TelephonyManager#getCarrierIdListVersion(): + Method 'getCarrierIdListVersion' documentation mentions permissions without declaring @RequiresPermission +RequiresPermission: android.telephony.TelephonyManager#getCarrierInfoForImsiEncryption(int): + Method 'getCarrierInfoForImsiEncryption' documentation mentions permissions already declared by @RequiresPermission +RequiresPermission: android.telephony.TelephonyManager#getCarrierRestrictionStatus(java.util.concurrent.Executor, java.util.function.Consumer<java.lang.Integer>): + Method 'getCarrierRestrictionStatus' documentation mentions permissions already declared by @RequiresPermission +RequiresPermission: android.telephony.TelephonyManager#getCdmaRoamingMode(): + Method 'getCdmaRoamingMode' documentation mentions permissions already declared by @RequiresPermission +RequiresPermission: android.telephony.TelephonyManager#getCdmaSubscriptionMode(): + Method 'getCdmaSubscriptionMode' documentation mentions permissions already declared by @RequiresPermission +RequiresPermission: android.telephony.TelephonyManager#getDataActivationState(): + Method 'getDataActivationState' documentation mentions permissions already declared by @RequiresPermission +RequiresPermission: android.telephony.TelephonyManager#getDataNetworkType(): + Method 'getDataNetworkType' documentation mentions permissions already declared by @RequiresPermission +RequiresPermission: android.telephony.TelephonyManager#getDeviceId(): + Method 'getDeviceId' documentation mentions permissions already declared by @RequiresPermission +RequiresPermission: android.telephony.TelephonyManager#getDeviceId(int): + Method 'getDeviceId' documentation mentions permissions already declared by @RequiresPermission +RequiresPermission: android.telephony.TelephonyManager#getDeviceSoftwareVersion(int): + Method 'getDeviceSoftwareVersion' documentation mentions permissions already declared by @RequiresPermission +RequiresPermission: android.telephony.TelephonyManager#getEmergencyNumberDbVersion(): + Method 'getEmergencyNumberDbVersion' documentation mentions permissions already declared by @RequiresPermission +RequiresPermission: android.telephony.TelephonyManager#getEmergencyNumberList(): + Method 'getEmergencyNumberList' documentation mentions permissions already declared by @RequiresPermission +RequiresPermission: android.telephony.TelephonyManager#getEmergencyNumberList(int): + Method 'getEmergencyNumberList' documentation mentions permissions already declared by @RequiresPermission +RequiresPermission: android.telephony.TelephonyManager#getEquivalentHomePlmns(): + Method 'getEquivalentHomePlmns' documentation mentions permissions already declared by @RequiresPermission +RequiresPermission: android.telephony.TelephonyManager#getForbiddenPlmns(): + Method 'getForbiddenPlmns' documentation mentions permissions already declared by @RequiresPermission +RequiresPermission: android.telephony.TelephonyManager#getGroupIdLevel1(): + Method 'getGroupIdLevel1' documentation mentions permissions already declared by @RequiresPermission +RequiresPermission: android.telephony.TelephonyManager#getImei(int): + Method 'getImei' documentation mentions permissions already declared by @RequiresPermission +RequiresPermission: android.telephony.TelephonyManager#getIsimDomain(): + Method 'getIsimDomain' documentation mentions permissions already declared by @RequiresPermission +RequiresPermission: android.telephony.TelephonyManager#getLine1Number(): + Method 'getLine1Number' documentation mentions permissions already declared by @RequiresPermission +RequiresPermission: android.telephony.TelephonyManager#getManualNetworkSelectionPlmn(): + Method 'getManualNetworkSelectionPlmn' documentation mentions permissions already declared by @RequiresPermission +RequiresPermission: android.telephony.TelephonyManager#getMeid(): + Method 'getMeid' documentation mentions permissions already declared by @RequiresPermission +RequiresPermission: android.telephony.TelephonyManager#getMeid(int): + Method 'getMeid' documentation mentions permissions already declared by @RequiresPermission +RequiresPermission: android.telephony.TelephonyManager#getNai(): + Method 'getNai' documentation mentions permissions already declared by @RequiresPermission +RequiresPermission: android.telephony.TelephonyManager#getNetworkSelectionMode(): + Method 'getNetworkSelectionMode' documentation mentions permissions already declared by @RequiresPermission +RequiresPermission: android.telephony.TelephonyManager#getNetworkSlicingConfiguration(java.util.concurrent.Executor, android.os.OutcomeReceiver<android.telephony.data.NetworkSlicingConfig,android.telephony.TelephonyManager.NetworkSlicingException>): + Method 'getNetworkSlicingConfiguration' documentation mentions permissions already declared by @RequiresPermission +RequiresPermission: android.telephony.TelephonyManager#getPhoneAccountHandle(): + Method 'getPhoneAccountHandle' documentation mentions permissions already declared by @RequiresPermission +RequiresPermission: android.telephony.TelephonyManager#getPreferredNetworkTypeBitmask(): + Method 'getPreferredNetworkTypeBitmask' documentation mentions permissions already declared by @RequiresPermission +RequiresPermission: android.telephony.TelephonyManager#getPreferredOpportunisticDataSubscription(): + Method 'getPreferredOpportunisticDataSubscription' documentation mentions permissions already declared by @RequiresPermission +RequiresPermission: android.telephony.TelephonyManager#getRadioPowerOffReasons(): + Method 'getRadioPowerOffReasons' documentation mentions permissions already declared by @RequiresPermission +RequiresPermission: android.telephony.TelephonyManager#getRadioPowerState(): + Method 'getRadioPowerState' documentation mentions permissions already declared by @RequiresPermission +RequiresPermission: android.telephony.TelephonyManager#getServiceState(): + Method 'getServiceState' documentation mentions permissions already declared by @RequiresPermission +RequiresPermission: android.telephony.TelephonyManager#getServiceState(int): + Method 'getServiceState' documentation mentions permissions already declared by @RequiresPermission +RequiresPermission: android.telephony.TelephonyManager#getSimLocale(): + Method 'getSimLocale' documentation mentions permissions already declared by @RequiresPermission +RequiresPermission: android.telephony.TelephonyManager#getSimSerialNumber(): + Method 'getSimSerialNumber' documentation mentions permissions already declared by @RequiresPermission +RequiresPermission: android.telephony.TelephonyManager#getSubscriberId(): + Method 'getSubscriberId' documentation mentions permissions already declared by @RequiresPermission +RequiresPermission: android.telephony.TelephonyManager#getSupportedRadioAccessFamily(): + Method 'getSupportedRadioAccessFamily' documentation mentions permissions already declared by @RequiresPermission +RequiresPermission: android.telephony.TelephonyManager#getSystemSelectionChannels(): + Method 'getSystemSelectionChannels' documentation mentions permissions already declared by @RequiresPermission +RequiresPermission: android.telephony.TelephonyManager#getTelephonyHistograms(): + Method 'getTelephonyHistograms' documentation mentions permissions already declared by @RequiresPermission +RequiresPermission: android.telephony.TelephonyManager#getVisualVoicemailPackageName(): + Method 'getVisualVoicemailPackageName' documentation mentions permissions already declared by @RequiresPermission +RequiresPermission: android.telephony.TelephonyManager#getVoiceActivationState(): + Method 'getVoiceActivationState' documentation mentions permissions already declared by @RequiresPermission +RequiresPermission: android.telephony.TelephonyManager#getVoiceMailAlphaTag(): + Method 'getVoiceMailAlphaTag' documentation mentions permissions already declared by @RequiresPermission +RequiresPermission: android.telephony.TelephonyManager#getVoiceMailNumber(): + Method 'getVoiceMailNumber' documentation mentions permissions already declared by @RequiresPermission +RequiresPermission: android.telephony.TelephonyManager#getVoiceNetworkType(): + Method 'getVoiceNetworkType' documentation mentions permissions already declared by @RequiresPermission +RequiresPermission: android.telephony.TelephonyManager#iccCloseLogicalChannel(int): + Method 'iccCloseLogicalChannel' documentation mentions permissions without declaring @RequiresPermission +RequiresPermission: android.telephony.TelephonyManager#iccCloseLogicalChannelBySlot(int, int): + Method 'iccCloseLogicalChannelBySlot' documentation mentions permissions already declared by @RequiresPermission +RequiresPermission: android.telephony.TelephonyManager#iccExchangeSimIO(int, int, int, int, int, String): + Method 'iccExchangeSimIO' documentation mentions permissions without declaring @RequiresPermission +RequiresPermission: android.telephony.TelephonyManager#iccOpenLogicalChannel(String): + Method 'iccOpenLogicalChannel' documentation mentions permissions without declaring @RequiresPermission +RequiresPermission: android.telephony.TelephonyManager#iccOpenLogicalChannel(String, int): + Method 'iccOpenLogicalChannel' documentation mentions permissions without declaring @RequiresPermission +RequiresPermission: android.telephony.TelephonyManager#iccOpenLogicalChannelBySlot(int, String, int): + Method 'iccOpenLogicalChannelBySlot' documentation mentions permissions already declared by @RequiresPermission +RequiresPermission: android.telephony.TelephonyManager#iccTransmitApduBasicChannel(int, int, int, int, int, String): + Method 'iccTransmitApduBasicChannel' documentation mentions permissions without declaring @RequiresPermission +RequiresPermission: android.telephony.TelephonyManager#iccTransmitApduBasicChannelBySlot(int, int, int, int, int, int, String): + Method 'iccTransmitApduBasicChannelBySlot' documentation mentions permissions already declared by @RequiresPermission +RequiresPermission: android.telephony.TelephonyManager#iccTransmitApduLogicalChannel(int, int, int, int, int, int, String): + Method 'iccTransmitApduLogicalChannel' documentation mentions permissions without declaring @RequiresPermission +RequiresPermission: android.telephony.TelephonyManager#iccTransmitApduLogicalChannelBySlot(int, int, int, int, int, int, int, String): + Method 'iccTransmitApduLogicalChannelBySlot' documentation mentions permissions already declared by @RequiresPermission +RequiresPermission: android.telephony.TelephonyManager#isApplicationOnUicc(int): + Method 'isApplicationOnUicc' documentation mentions permissions already declared by @RequiresPermission +RequiresPermission: android.telephony.TelephonyManager#isDataEnabled(): + Method 'isDataEnabled' documentation mentions permissions already declared by @RequiresPermission +RequiresPermission: android.telephony.TelephonyManager#isDataEnabledForReason(int): + Method 'isDataEnabledForReason' documentation mentions permissions already declared by @RequiresPermission +RequiresPermission: android.telephony.TelephonyManager#isDataRoamingEnabled(): + Method 'isDataRoamingEnabled' documentation mentions permissions already declared by @RequiresPermission +RequiresPermission: android.telephony.TelephonyManager#isDomainSelectionSupported(): + Method 'isDomainSelectionSupported' documentation mentions permissions already declared by @RequiresPermission +RequiresPermission: android.telephony.TelephonyManager#isEmergencyAssistanceEnabled(): + Method 'isEmergencyAssistanceEnabled' documentation mentions permissions already declared by @RequiresPermission +RequiresPermission: android.telephony.TelephonyManager#isIccLockEnabled(): + Method 'isIccLockEnabled' documentation mentions permissions already declared by @RequiresPermission +RequiresPermission: android.telephony.TelephonyManager#isManualNetworkSelectionAllowed(): + Method 'isManualNetworkSelectionAllowed' documentation mentions permissions already declared by @RequiresPermission +RequiresPermission: android.telephony.TelephonyManager#isModemEnabledForSlot(int): + Method 'isModemEnabledForSlot' documentation mentions permissions already declared by @RequiresPermission +RequiresPermission: android.telephony.TelephonyManager#isMultiSimSupported(): + Method 'isMultiSimSupported' documentation mentions permissions already declared by @RequiresPermission +RequiresPermission: android.telephony.TelephonyManager#isOpportunisticNetworkEnabled(): + Method 'isOpportunisticNetworkEnabled' documentation mentions permissions already declared by @RequiresPermission +RequiresPermission: android.telephony.TelephonyManager#isPotentialEmergencyNumber(String): + Method 'isPotentialEmergencyNumber' documentation mentions permissions already declared by @RequiresPermission +RequiresPermission: android.telephony.TelephonyManager#isPremiumCapabilityAvailableForPurchase(int): + Method 'isPremiumCapabilityAvailableForPurchase' documentation mentions permissions already declared by @RequiresPermission +RequiresPermission: android.telephony.TelephonyManager#isTetheringApnRequired(): + Method 'isTetheringApnRequired' documentation mentions permissions already declared by @RequiresPermission +RequiresPermission: android.telephony.TelephonyManager#notifyOtaEmergencyNumberDbInstalled(): + Method 'notifyOtaEmergencyNumberDbInstalled' documentation mentions permissions already declared by @RequiresPermission +RequiresPermission: android.telephony.TelephonyManager#prepareForUnattendedReboot(): + Method 'prepareForUnattendedReboot' documentation mentions permissions already declared by @RequiresPermission +RequiresPermission: android.telephony.TelephonyManager#purchasePremiumCapability(int, java.util.concurrent.Executor, java.util.function.Consumer<java.lang.Integer>): + Method 'purchasePremiumCapability' documentation mentions permissions already declared by @RequiresPermission +RequiresPermission: android.telephony.TelephonyManager#rebootModem(): + Method 'rebootModem' documentation mentions permissions already declared by @RequiresPermission +RequiresPermission: android.telephony.TelephonyManager#rebootRadio(): + Method 'rebootRadio' documentation mentions permissions already declared by @RequiresPermission +RequiresPermission: android.telephony.TelephonyManager#reportDefaultNetworkStatus(boolean): + Method 'reportDefaultNetworkStatus' documentation mentions permissions already declared by @RequiresPermission +RequiresPermission: android.telephony.TelephonyManager#requestNetworkScan(android.telephony.NetworkScanRequest, java.util.concurrent.Executor, android.telephony.TelephonyScanManager.NetworkScanCallback): + Method 'requestNetworkScan' documentation mentions permissions already declared by @RequiresPermission +RequiresPermission: android.telephony.TelephonyManager#requestNetworkScan(int, android.telephony.NetworkScanRequest, java.util.concurrent.Executor, android.telephony.TelephonyScanManager.NetworkScanCallback): + Method 'requestNetworkScan' documentation mentions permissions already declared by @RequiresPermission +RequiresPermission: android.telephony.TelephonyManager#requestNumberVerification(android.telephony.PhoneNumberRange, long, java.util.concurrent.Executor, android.telephony.NumberVerificationCallback): + Method 'requestNumberVerification' documentation mentions permissions already declared by @RequiresPermission +RequiresPermission: android.telephony.TelephonyManager#requestRadioPowerOffForReason(int): + Method 'requestRadioPowerOffForReason' documentation mentions permissions already declared by @RequiresPermission +RequiresPermission: android.telephony.TelephonyManager#resetAllCarrierActions(): + Method 'resetAllCarrierActions' documentation mentions permissions already declared by @RequiresPermission +RequiresPermission: android.telephony.TelephonyManager#resetCarrierKeysForImsiEncryption(): + Method 'resetCarrierKeysForImsiEncryption' documentation mentions permissions already declared by @RequiresPermission +RequiresPermission: android.telephony.TelephonyManager#resetOtaEmergencyNumberDbFilePath(): + Method 'resetOtaEmergencyNumberDbFilePath' documentation mentions permissions already declared by @RequiresPermission +RequiresPermission: android.telephony.TelephonyManager#resetRadioConfig(): + Method 'resetRadioConfig' documentation mentions permissions already declared by @RequiresPermission +RequiresPermission: android.telephony.TelephonyManager#sendEnvelopeWithStatus(String): + Method 'sendEnvelopeWithStatus' documentation mentions permissions without declaring @RequiresPermission +RequiresPermission: android.telephony.TelephonyManager#sendThermalMitigationRequest(android.telephony.ThermalMitigationRequest): + Method 'sendThermalMitigationRequest' documentation mentions permissions already declared by @RequiresPermission +RequiresPermission: android.telephony.TelephonyManager#sendUssdRequest(String, android.telephony.TelephonyManager.UssdResponseCallback, android.os.Handler): + Method 'sendUssdRequest' documentation mentions permissions already declared by @RequiresPermission +RequiresPermission: android.telephony.TelephonyManager#sendVisualVoicemailSms(String, int, String, android.app.PendingIntent): + Method 'sendVisualVoicemailSms' documentation mentions permissions without declaring @RequiresPermission +RequiresPermission: android.telephony.TelephonyManager#setAllowedCarriers(int, java.util.List<android.service.carrier.CarrierIdentifier>): + Method 'setAllowedCarriers' documentation mentions permissions already declared by @RequiresPermission +RequiresPermission: android.telephony.TelephonyManager#setAllowedNetworkTypesForReason(int, long): + Method 'setAllowedNetworkTypesForReason' documentation mentions permissions already declared by @RequiresPermission +RequiresPermission: android.telephony.TelephonyManager#setCarrierDataEnabled(boolean): + Method 'setCarrierDataEnabled' documentation mentions permissions already declared by @RequiresPermission +RequiresPermission: android.telephony.TelephonyManager#setCarrierRestrictionRules(android.telephony.CarrierRestrictionRules): + Method 'setCarrierRestrictionRules' documentation mentions permissions already declared by @RequiresPermission +RequiresPermission: android.telephony.TelephonyManager#setCarrierTestOverride(String, String, String, String, String, String, String): + Method 'setCarrierTestOverride' documentation mentions permissions without declaring @RequiresPermission +RequiresPermission: android.telephony.TelephonyManager#setCarrierTestOverride(String, String, String, String, String, String, String, String, String): + Method 'setCarrierTestOverride' documentation mentions permissions without declaring @RequiresPermission +RequiresPermission: android.telephony.TelephonyManager#setCdmaRoamingMode(int): + Method 'setCdmaRoamingMode' documentation mentions permissions already declared by @RequiresPermission +RequiresPermission: android.telephony.TelephonyManager#setCdmaSubscriptionMode(int): + Method 'setCdmaSubscriptionMode' documentation mentions permissions already declared by @RequiresPermission +RequiresPermission: android.telephony.TelephonyManager#setDataActivationState(int): + Method 'setDataActivationState' documentation mentions permissions already declared by @RequiresPermission +RequiresPermission: android.telephony.TelephonyManager#setDataEnabled(boolean): + Method 'setDataEnabled' documentation mentions permissions already declared by @RequiresPermission +RequiresPermission: android.telephony.TelephonyManager#setDataEnabledForReason(int, boolean): + Method 'setDataEnabledForReason' documentation mentions permissions already declared by @RequiresPermission +RequiresPermission: android.telephony.TelephonyManager#setDataRoamingEnabled(boolean): + Method 'setDataRoamingEnabled' documentation mentions permissions already declared by @RequiresPermission +RequiresPermission: android.telephony.TelephonyManager#setForbiddenPlmns(java.util.List<java.lang.String>): + Method 'setForbiddenPlmns' documentation mentions permissions already declared by @RequiresPermission +RequiresPermission: android.telephony.TelephonyManager#setIccLockEnabled(boolean, String): + Method 'setIccLockEnabled' documentation mentions permissions already declared by @RequiresPermission +RequiresPermission: android.telephony.TelephonyManager#setNetworkSelectionModeAutomatic(): + Method 'setNetworkSelectionModeAutomatic' documentation mentions permissions already declared by @RequiresPermission +RequiresPermission: android.telephony.TelephonyManager#setNetworkSelectionModeManual(String, boolean): + Method 'setNetworkSelectionModeManual' documentation mentions permissions already declared by @RequiresPermission +RequiresPermission: android.telephony.TelephonyManager#setNetworkSelectionModeManual(String, boolean, int): + Method 'setNetworkSelectionModeManual' documentation mentions permissions already declared by @RequiresPermission +RequiresPermission: android.telephony.TelephonyManager#setOpportunisticNetworkState(boolean): + Method 'setOpportunisticNetworkState' documentation mentions permissions already declared by @RequiresPermission +RequiresPermission: android.telephony.TelephonyManager#setPreferredNetworkTypeBitmask(long): + Method 'setPreferredNetworkTypeBitmask' documentation mentions permissions already declared by @RequiresPermission +RequiresPermission: android.telephony.TelephonyManager#setPreferredOpportunisticDataSubscription(int, boolean, java.util.concurrent.Executor, java.util.function.Consumer<java.lang.Integer>): + Method 'setPreferredOpportunisticDataSubscription' documentation mentions permissions without declaring @RequiresPermission +RequiresPermission: android.telephony.TelephonyManager#setRadioEnabled(boolean): + Method 'setRadioEnabled' documentation mentions permissions already declared by @RequiresPermission +RequiresPermission: android.telephony.TelephonyManager#setSignalStrengthUpdateRequest(android.telephony.SignalStrengthUpdateRequest): + Method 'setSignalStrengthUpdateRequest' documentation mentions permissions already declared by @RequiresPermission +RequiresPermission: android.telephony.TelephonyManager#setSimPowerState(int): + Method 'setSimPowerState' documentation mentions permissions already declared by @RequiresPermission +RequiresPermission: android.telephony.TelephonyManager#setSimPowerState(int, java.util.concurrent.Executor, java.util.function.Consumer<java.lang.Integer>): + Method 'setSimPowerState' documentation mentions permissions already declared by @RequiresPermission +RequiresPermission: android.telephony.TelephonyManager#setSimPowerStateForSlot(int, int): + Method 'setSimPowerStateForSlot' documentation mentions permissions already declared by @RequiresPermission +RequiresPermission: android.telephony.TelephonyManager#setSimPowerStateForSlot(int, int, java.util.concurrent.Executor, java.util.function.Consumer<java.lang.Integer>): + Method 'setSimPowerStateForSlot' documentation mentions permissions already declared by @RequiresPermission +RequiresPermission: android.telephony.TelephonyManager#setVoiceActivationState(int): + Method 'setVoiceActivationState' documentation mentions permissions already declared by @RequiresPermission +RequiresPermission: android.telephony.TelephonyManager#setVoicemailRingtoneUri(android.telecom.PhoneAccountHandle, android.net.Uri): + Method 'setVoicemailRingtoneUri' documentation mentions permissions without declaring @RequiresPermission +RequiresPermission: android.telephony.TelephonyManager#setVoicemailVibrationEnabled(android.telecom.PhoneAccountHandle, boolean): + Method 'setVoicemailVibrationEnabled' documentation mentions permissions without declaring @RequiresPermission +RequiresPermission: android.telephony.TelephonyManager#supplyIccLockPin(String): + Method 'supplyIccLockPin' documentation mentions permissions already declared by @RequiresPermission +RequiresPermission: android.telephony.TelephonyManager#supplyIccLockPuk(String, String): + Method 'supplyIccLockPuk' documentation mentions permissions already declared by @RequiresPermission +RequiresPermission: android.telephony.TelephonyManager#switchMultiSimConfig(int): + Method 'switchMultiSimConfig' documentation mentions permissions already declared by @RequiresPermission +RequiresPermission: android.telephony.TelephonyManager#updateAvailableNetworks(java.util.List<android.telephony.AvailableNetworkInfo>, java.util.concurrent.Executor, java.util.function.Consumer<java.lang.Integer>): + Method 'updateAvailableNetworks' documentation mentions permissions without declaring @RequiresPermission +RequiresPermission: android.telephony.TelephonyManager#updateOtaEmergencyNumberDbFilePath(android.os.ParcelFileDescriptor): + Method 'updateOtaEmergencyNumberDbFilePath' documentation mentions permissions already declared by @RequiresPermission +RequiresPermission: android.telephony.VisualVoicemailService#sendVisualVoicemailSms(android.content.Context, android.telecom.PhoneAccountHandle, String, short, String, android.app.PendingIntent): + Method 'sendVisualVoicemailSms' documentation mentions permissions without declaring @RequiresPermission +RequiresPermission: android.telephony.VisualVoicemailService#setSmsFilterSettings(android.content.Context, android.telecom.PhoneAccountHandle, android.telephony.VisualVoicemailSmsFilterSettings): + Method 'setSmsFilterSettings' documentation mentions permissions without declaring @RequiresPermission +RequiresPermission: android.telephony.euicc.EuiccManager#continueOperation(android.content.Intent, android.os.Bundle): + Method 'continueOperation' documentation mentions permissions already declared by @RequiresPermission +RequiresPermission: android.telephony.euicc.EuiccManager#deleteSubscription(int, android.app.PendingIntent): + Method 'deleteSubscription' documentation mentions permissions already declared by @RequiresPermission +RequiresPermission: android.telephony.euicc.EuiccManager#downloadSubscription(android.telephony.euicc.DownloadableSubscription, boolean, android.app.PendingIntent): + Method 'downloadSubscription' documentation mentions permissions already declared by @RequiresPermission +RequiresPermission: android.telephony.euicc.EuiccManager#eraseSubscriptions(android.app.PendingIntent): + Method 'eraseSubscriptions' documentation mentions permissions already declared by @RequiresPermission +RequiresPermission: android.telephony.euicc.EuiccManager#eraseSubscriptions(int, android.app.PendingIntent): + Method 'eraseSubscriptions' documentation mentions permissions already declared by @RequiresPermission +RequiresPermission: android.telephony.euicc.EuiccManager#getDefaultDownloadableSubscriptionList(android.app.PendingIntent): + Method 'getDefaultDownloadableSubscriptionList' documentation mentions permissions already declared by @RequiresPermission +RequiresPermission: android.telephony.euicc.EuiccManager#getDownloadableSubscriptionMetadata(android.telephony.euicc.DownloadableSubscription, android.app.PendingIntent): + Method 'getDownloadableSubscriptionMetadata' documentation mentions permissions already declared by @RequiresPermission +RequiresPermission: android.telephony.euicc.EuiccManager#getOtaStatus(): + Method 'getOtaStatus' documentation mentions permissions already declared by @RequiresPermission +RequiresPermission: android.telephony.euicc.EuiccManager#getSupportedCountries(): + Method 'getSupportedCountries' documentation mentions permissions already declared by @RequiresPermission +RequiresPermission: android.telephony.euicc.EuiccManager#getUnsupportedCountries(): + Method 'getUnsupportedCountries' documentation mentions permissions already declared by @RequiresPermission +RequiresPermission: android.telephony.euicc.EuiccManager#setSupportedCountries(java.util.List<java.lang.String>): + Method 'setSupportedCountries' documentation mentions permissions already declared by @RequiresPermission +RequiresPermission: android.telephony.euicc.EuiccManager#setUnsupportedCountries(java.util.List<java.lang.String>): + Method 'setUnsupportedCountries' documentation mentions permissions already declared by @RequiresPermission +RequiresPermission: android.telephony.euicc.EuiccManager#switchToSubscription(int, android.app.PendingIntent): + Method 'switchToSubscription' documentation mentions permissions already declared by @RequiresPermission +RequiresPermission: android.telephony.euicc.EuiccManager#switchToSubscription(int, int, android.app.PendingIntent): + Method 'switchToSubscription' documentation mentions permissions already declared by @RequiresPermission +RequiresPermission: android.telephony.euicc.EuiccManager#updateSubscriptionNickname(int, String, android.app.PendingIntent): + Method 'updateSubscriptionNickname' documentation mentions permissions already declared by @RequiresPermission +RequiresPermission: android.telephony.ims.ImsMmTelManager#createForSubscriptionId(int): + Method 'createForSubscriptionId' documentation mentions permissions already declared by @RequiresPermission +RequiresPermission: android.telephony.ims.ImsMmTelManager#getRegistrationTransportType(java.util.concurrent.Executor, java.util.function.Consumer<java.lang.Integer>): + Method 'getRegistrationTransportType' documentation mentions permissions already declared by @RequiresPermission +RequiresPermission: android.telephony.ims.ImsMmTelManager#getVoWiFiModeSetting(): + Method 'getVoWiFiModeSetting' documentation mentions permissions already declared by @RequiresPermission +RequiresPermission: android.telephony.ims.ImsMmTelManager#isAdvancedCallingSettingEnabled(): + Method 'isAdvancedCallingSettingEnabled' documentation mentions permissions already declared by @RequiresPermission +RequiresPermission: android.telephony.ims.ImsMmTelManager#isCrossSimCallingEnabled(): + Method 'isCrossSimCallingEnabled' documentation mentions permissions already declared by @RequiresPermission +RequiresPermission: android.telephony.ims.ImsMmTelManager#isTtyOverVolteEnabled(): + Method 'isTtyOverVolteEnabled' documentation mentions permissions already declared by @RequiresPermission +RequiresPermission: android.telephony.ims.ImsMmTelManager#isVoWiFiRoamingSettingEnabled(): + Method 'isVoWiFiRoamingSettingEnabled' documentation mentions permissions already declared by @RequiresPermission +RequiresPermission: android.telephony.ims.ImsMmTelManager#isVoWiFiSettingEnabled(): + Method 'isVoWiFiSettingEnabled' documentation mentions permissions already declared by @RequiresPermission +RequiresPermission: android.telephony.ims.ImsMmTelManager#isVtSettingEnabled(): + Method 'isVtSettingEnabled' documentation mentions permissions already declared by @RequiresPermission +RequiresPermission: android.telephony.ims.ImsMmTelManager#registerImsRegistrationCallback(java.util.concurrent.Executor, android.telephony.ims.RegistrationManager.RegistrationCallback): + Method 'registerImsRegistrationCallback' documentation mentions permissions already declared by @RequiresPermission +RequiresPermission: android.telephony.ims.ImsMmTelManager#registerImsStateCallback(java.util.concurrent.Executor, android.telephony.ims.ImsStateCallback): + Method 'registerImsStateCallback' documentation mentions permissions already declared by @RequiresPermission +RequiresPermission: android.telephony.ims.ImsMmTelManager#registerMmTelCapabilityCallback(java.util.concurrent.Executor, android.telephony.ims.ImsMmTelManager.CapabilityCallback): + Method 'registerMmTelCapabilityCallback' documentation mentions permissions already declared by @RequiresPermission +RequiresPermission: android.telephony.ims.ImsMmTelManager#unregisterImsRegistrationCallback(android.telephony.ims.RegistrationManager.RegistrationCallback): + Method 'unregisterImsRegistrationCallback' documentation mentions permissions already declared by @RequiresPermission +RequiresPermission: android.telephony.ims.ImsMmTelManager#unregisterMmTelCapabilityCallback(android.telephony.ims.ImsMmTelManager.CapabilityCallback): + Method 'unregisterMmTelCapabilityCallback' documentation mentions permissions already declared by @RequiresPermission +RequiresPermission: android.telephony.ims.ImsRcsManager#getRegistrationState(java.util.concurrent.Executor, java.util.function.Consumer<java.lang.Integer>): + Method 'getRegistrationState' documentation mentions permissions already declared by @RequiresPermission +RequiresPermission: android.telephony.ims.ImsRcsManager#getRegistrationTransportType(java.util.concurrent.Executor, java.util.function.Consumer<java.lang.Integer>): + Method 'getRegistrationTransportType' documentation mentions permissions already declared by @RequiresPermission +RequiresPermission: android.telephony.ims.ImsRcsManager#registerImsRegistrationCallback(java.util.concurrent.Executor, android.telephony.ims.RegistrationManager.RegistrationCallback): + Method 'registerImsRegistrationCallback' documentation mentions permissions already declared by @RequiresPermission +RequiresPermission: android.telephony.ims.ImsRcsManager#registerImsStateCallback(java.util.concurrent.Executor, android.telephony.ims.ImsStateCallback): + Method 'registerImsStateCallback' documentation mentions permissions already declared by @RequiresPermission +RequiresPermission: android.telephony.ims.ImsRcsManager#unregisterImsRegistrationCallback(android.telephony.ims.RegistrationManager.RegistrationCallback): + Method 'unregisterImsRegistrationCallback' documentation mentions permissions already declared by @RequiresPermission +RequiresPermission: android.telephony.ims.ProvisioningManager#getProvisioningStatusForCapability(int, int): + Method 'getProvisioningStatusForCapability' documentation mentions permissions already declared by @RequiresPermission +RequiresPermission: android.telephony.ims.ProvisioningManager#getRcsProvisioningStatusForCapability(int, int): + Method 'getRcsProvisioningStatusForCapability' documentation mentions permissions already declared by @RequiresPermission +RequiresPermission: android.telephony.ims.ProvisioningManager#isProvisioningRequiredForCapability(int, int): + Method 'isProvisioningRequiredForCapability' documentation mentions permissions already declared by @RequiresPermission +RequiresPermission: android.telephony.ims.ProvisioningManager#isRcsProvisioningRequiredForCapability(int, int): + Method 'isRcsProvisioningRequiredForCapability' documentation mentions permissions already declared by @RequiresPermission +RequiresPermission: android.telephony.ims.ProvisioningManager#isRcsVolteSingleRegistrationCapable(): + Method 'isRcsVolteSingleRegistrationCapable' documentation mentions permissions already declared by @RequiresPermission +RequiresPermission: android.telephony.ims.ProvisioningManager#notifyRcsAutoConfigurationReceived(byte[], boolean): + Method 'notifyRcsAutoConfigurationReceived' documentation mentions permissions already declared by @RequiresPermission +RequiresPermission: android.telephony.ims.ProvisioningManager#registerFeatureProvisioningChangedCallback(java.util.concurrent.Executor, android.telephony.ims.ProvisioningManager.FeatureProvisioningCallback): + Method 'registerFeatureProvisioningChangedCallback' documentation mentions permissions already declared by @RequiresPermission +RequiresPermission: android.telephony.ims.ProvisioningManager#registerProvisioningChangedCallback(java.util.concurrent.Executor, android.telephony.ims.ProvisioningManager.Callback): + Method 'registerProvisioningChangedCallback' documentation mentions permissions already declared by @RequiresPermission +RequiresPermission: android.telephony.ims.ProvisioningManager#registerRcsProvisioningCallback(java.util.concurrent.Executor, android.telephony.ims.ProvisioningManager.RcsProvisioningCallback): + Method 'registerRcsProvisioningCallback' documentation mentions permissions already declared by @RequiresPermission +RequiresPermission: android.telephony.ims.ProvisioningManager#setProvisioningStatusForCapability(int, int, boolean): + Method 'setProvisioningStatusForCapability' documentation mentions permissions already declared by @RequiresPermission +RequiresPermission: android.telephony.ims.ProvisioningManager#setRcsProvisioningStatusForCapability(int, boolean): + Method 'setRcsProvisioningStatusForCapability' documentation mentions permissions already declared by @RequiresPermission +RequiresPermission: android.telephony.ims.ProvisioningManager#setRcsProvisioningStatusForCapability(int, int, boolean): + Method 'setRcsProvisioningStatusForCapability' documentation mentions permissions already declared by @RequiresPermission +RequiresPermission: android.telephony.ims.ProvisioningManager#unregisterProvisioningChangedCallback(android.telephony.ims.ProvisioningManager.Callback): + Method 'unregisterProvisioningChangedCallback' documentation mentions permissions already declared by @RequiresPermission +RequiresPermission: android.telephony.ims.ProvisioningManager#unregisterRcsProvisioningCallback(android.telephony.ims.ProvisioningManager.RcsProvisioningCallback): + Method 'unregisterRcsProvisioningCallback' documentation mentions permissions already declared by @RequiresPermission +RequiresPermission: android.telephony.ims.SipDelegateManager#registerSipDialogStateCallback(java.util.concurrent.Executor, android.telephony.ims.SipDialogStateCallback): + Method 'registerSipDialogStateCallback' documentation mentions permissions already declared by @RequiresPermission +RequiresPermission: android.telephony.ims.SipDelegateManager#unregisterSipDialogStateCallback(android.telephony.ims.SipDialogStateCallback): + Method 'unregisterSipDialogStateCallback' documentation mentions permissions already declared by @RequiresPermission +RequiresPermission: android.view.WindowManager.LayoutParams#isSystemApplicationOverlay(): + Method 'isSystemApplicationOverlay' documentation mentions permissions without declaring @RequiresPermission +RequiresPermission: android.view.accessibility.AccessibilityManager#registerDisplayProxy(android.view.accessibility.AccessibilityDisplayProxy): + Method 'registerDisplayProxy' documentation mentions permissions already declared by @RequiresPermission +RequiresPermission: android.view.accessibility.AccessibilityManager#unregisterDisplayProxy(android.view.accessibility.AccessibilityDisplayProxy): + Method 'unregisterDisplayProxy' documentation mentions permissions already declared by @RequiresPermission +RequiresPermission: android.view.accessibility.CaptioningManager#setSystemAudioCaptioningEnabled(boolean): + Method 'setSystemAudioCaptioningEnabled' documentation mentions permissions already declared by @RequiresPermission +RequiresPermission: android.view.accessibility.CaptioningManager#setSystemAudioCaptioningUiEnabled(boolean): + Method 'setSystemAudioCaptioningUiEnabled' documentation mentions permissions already declared by @RequiresPermission +RequiresPermission: android.view.inputmethod.InputMethodManager#getEnabledInputMethodListAsUser(android.os.UserHandle): + Method 'getEnabledInputMethodListAsUser' documentation mentions permissions already declared by @RequiresPermission +RequiresPermission: android.view.inputmethod.InputMethodManager#getEnabledInputMethodSubtypeListAsUser(String, boolean, android.os.UserHandle): + Method 'getEnabledInputMethodSubtypeListAsUser' documentation mentions permissions already declared by @RequiresPermission +RequiresPermission: android.view.inputmethod.InputMethodManager#getInputMethodListAsUser(int): + Method 'getInputMethodListAsUser' documentation mentions permissions already declared by @RequiresPermission +RequiresPermission: android.view.inputmethod.InputMethodManager#isStylusHandwritingAvailableAsUser(android.os.UserHandle): + Method 'isStylusHandwritingAvailableAsUser' documentation mentions permissions already declared by @RequiresPermission +RequiresPermission: android.view.inputmethod.InputMethodManager#setCurrentInputMethodSubtype(android.view.inputmethod.InputMethodSubtype): + Method 'setCurrentInputMethodSubtype' documentation mentions permissions already declared by @RequiresPermission +RequiresPermission: android.webkit.WebSettings#setBlockNetworkLoads(boolean): + Method 'setBlockNetworkLoads' documentation mentions permissions without declaring @RequiresPermission +RequiresPermission: android.webkit.WebSettings#setGeolocationEnabled(boolean): + Method 'setGeolocationEnabled' documentation mentions permissions without declaring @RequiresPermission +RequiresPermission: android.window.WindowOrganizer#applySyncTransaction(android.window.WindowContainerTransaction, android.window.WindowContainerTransactionCallback): + Method 'applySyncTransaction' documentation mentions permissions already declared by @RequiresPermission +RequiresPermission: android.window.WindowOrganizer#applyTransaction(android.window.WindowContainerTransaction): + Method 'applyTransaction' documentation mentions permissions already declared by @RequiresPermission + + SamShouldBeLast: android.animation.ValueAnimator#ofObject(android.animation.TypeEvaluator, java.lang.Object...): SAM-compatible parameters (such as parameter 1, "evaluator", in android.animation.ValueAnimator.ofObject) should be last to improve Kotlin interoperability; see https://kotlinlang.org/docs/reference/java-interop.html#sam-conversions SamShouldBeLast: android.app.Activity#convertToTranslucent(android.app.Activity.TranslucentConversionListener, android.app.ActivityOptions): @@ -109,6 +1865,84 @@ SamShouldBeLast: android.view.inputmethod.InputMethodInfo#dump(android.util.Prin SAM-compatible parameters (such as parameter 1, "pw", in android.view.inputmethod.InputMethodInfo.dump) should be last to improve Kotlin interoperability; see https://kotlinlang.org/docs/reference/java-interop.html#sam-conversions +SdkConstant: android.content.Intent#ACTION_BATTERY_LEVEL_CHANGED: + Field 'ACTION_BATTERY_LEVEL_CHANGED' is missing @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION) +SdkConstant: android.content.Intent#ACTION_DEVICE_CUSTOMIZATION_READY: + Field 'ACTION_DEVICE_CUSTOMIZATION_READY' is missing @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION) +SdkConstant: android.content.Intent#ACTION_GLOBAL_BUTTON: + Field 'ACTION_GLOBAL_BUTTON' is missing @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION) +SdkConstant: android.content.Intent#ACTION_PRE_BOOT_COMPLETED: + Field 'ACTION_PRE_BOOT_COMPLETED' is missing @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION) +SdkConstant: android.content.Intent#ACTION_UNARCHIVE_PACKAGE: + Field 'ACTION_UNARCHIVE_PACKAGE' is missing @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION) +SdkConstant: android.content.pm.PackageInstaller#ACTION_CONFIRM_PRE_APPROVAL: + Field 'ACTION_CONFIRM_PRE_APPROVAL' is missing @SdkConstant(SdkConstantType.ACTIVITY_INTENT_ACTION) +SdkConstant: android.hardware.usb.UsbManager#ACTION_USB_PORT_CHANGED: + Field 'ACTION_USB_PORT_CHANGED' is missing @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION) +SdkConstant: android.hardware.usb.UsbManager#ACTION_USB_PORT_COMPLIANCE_CHANGED: + Field 'ACTION_USB_PORT_COMPLIANCE_CHANGED' is missing @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION) +SdkConstant: android.hardware.usb.UsbManager#ACTION_USB_STATE: + Field 'ACTION_USB_STATE' is missing @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION) +SdkConstant: android.nfc.NfcAdapter#ACTION_REQUIRE_UNLOCK_FOR_NFC: + Field 'ACTION_REQUIRE_UNLOCK_FOR_NFC' is missing @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION) +SdkConstant: android.service.euicc.EuiccService#ACTION_DELETE_SUBSCRIPTION_PRIVILEGED: + Field 'ACTION_DELETE_SUBSCRIPTION_PRIVILEGED' is missing @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION) +SdkConstant: android.service.euicc.EuiccService#ACTION_RENAME_SUBSCRIPTION_PRIVILEGED: + Field 'ACTION_RENAME_SUBSCRIPTION_PRIVILEGED' is missing @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION) +SdkConstant: android.service.euicc.EuiccService#ACTION_TOGGLE_SUBSCRIPTION_PRIVILEGED: + Field 'ACTION_TOGGLE_SUBSCRIPTION_PRIVILEGED' is missing @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION) +SdkConstant: android.telephony.TelephonyManager#ACTION_DEFAULT_DATA_SUBSCRIPTION_CHANGED: + Field 'ACTION_DEFAULT_DATA_SUBSCRIPTION_CHANGED' is missing @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION) +SdkConstant: android.telephony.TelephonyManager#ACTION_DEFAULT_VOICE_SUBSCRIPTION_CHANGED: + Field 'ACTION_DEFAULT_VOICE_SUBSCRIPTION_CHANGED' is missing @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION) +SdkConstant: android.telephony.TelephonyManager#ACTION_REQUEST_OMADM_CONFIGURATION_UPDATE: + Field 'ACTION_REQUEST_OMADM_CONFIGURATION_UPDATE' is missing @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION) +SdkConstant: android.telephony.TelephonyManager#ACTION_SHOW_NOTICE_ECM_BLOCK_OTHERS: + Field 'ACTION_SHOW_NOTICE_ECM_BLOCK_OTHERS' is missing @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION) + + +Todo: android.Manifest.permission#DOMAIN_VERIFICATION_AGENT: + Documentation mentions 'TODO' +Todo: android.Manifest.permission#INSTALL_EXISTING_PACKAGES: + Documentation mentions 'TODO' +Todo: android.Manifest.permission#READ_PEOPLE_DATA: + Documentation mentions 'TODO' +Todo: android.app.NotificationManager#isNotificationAssistantAccessGranted(android.content.ComponentName): + Documentation mentions 'TODO' +Todo: android.hardware.camera2.params.StreamConfigurationMap: + Documentation mentions 'TODO' +Todo: android.hardware.location.ContextHubManager#getNanoAppInstanceInfo(int): + Documentation mentions 'TODO' +Todo: android.hardware.location.ContextHubManager#loadNanoApp(int, android.hardware.location.NanoApp): + Documentation mentions 'TODO' +Todo: android.hardware.location.ContextHubManager#unloadNanoApp(int): + Documentation mentions 'TODO' +Todo: android.hardware.location.NanoAppInstanceInfo: + Documentation mentions 'TODO' +Todo: android.media.tv.TvContentRatingSystemInfo#getXmlUri(): + Documentation mentions 'TODO' +Todo: android.media.tv.TvInputInfo#isConnectedToHdmiSwitch(): + Documentation mentions 'TODO' +Todo: android.os.RecoverySystem#prepareForUnattendedUpdate(android.content.Context, String, android.content.IntentSender): + Documentation mentions 'TODO' +Todo: android.os.RecoverySystem#rebootAndApply(android.content.Context, String, String): + Documentation mentions 'TODO' +Todo: android.os.SystemConfigManager: + Documentation mentions 'TODO' +Todo: android.os.UpdateEngineCallback#onStatusUpdate(int, float): + Documentation mentions 'TODO' +Todo: android.provider.ContactsContract.RawContacts#newEntityIterator(android.database.Cursor): + Documentation mentions 'TODO' +Todo: android.service.voice.AlwaysOnHotwordDetector: + Documentation mentions 'TODO' +Todo: android.telephony.TelephonyManager#getCurrentPhoneType(): + Documentation mentions 'TODO' +Todo: android.telephony.TelephonyManager#setVoiceServiceStateOverride(boolean): + Documentation mentions 'TODO' +Todo: android.window.WindowContainerTransaction#setActivityWindowingMode(android.window.WindowContainerToken, int): + Documentation mentions 'TODO' + + UnflaggedApi: android.Manifest.permission#MANAGE_REMOTE_AUTH: New API must be flagged with @FlaggedApi: field android.Manifest.permission.MANAGE_REMOTE_AUTH UnflaggedApi: android.Manifest.permission#START_ACTIVITIES_FROM_SDK_SANDBOX: diff --git a/core/java/android/app/ActivityOptions.java b/core/java/android/app/ActivityOptions.java index f2c00517ad16..26f1c4b146a5 100644 --- a/core/java/android/app/ActivityOptions.java +++ b/core/java/android/app/ActivityOptions.java @@ -16,7 +16,6 @@ package android.app; -import static android.Manifest.permission.CONTROL_KEYGUARD; import static android.Manifest.permission.CONTROL_REMOTE_APP_TRANSITION_ANIMATIONS; import static android.Manifest.permission.START_TASKS_FROM_RECENTS; import static android.app.WindowConfiguration.ACTIVITY_TYPE_UNDEFINED; @@ -413,8 +412,9 @@ public class ActivityOptions extends ComponentOptions { private static final String KEY_LAUNCH_INTO_PIP_PARAMS = "android.activity.launchIntoPipParams"; - /** See {@link #setDismissKeyguard()}. */ - private static final String KEY_DISMISS_KEYGUARD = "android.activity.dismissKeyguard"; + /** See {@link #setDismissKeyguardIfInsecure()}. */ + private static final String KEY_DISMISS_KEYGUARD_IF_INSECURE = + "android.activity.dismissKeyguardIfInsecure"; private static final String KEY_PENDING_INTENT_CREATOR_BACKGROUND_ACTIVITY_START_MODE = "android.activity.pendingIntentCreatorBackgroundActivityStartMode"; @@ -519,7 +519,7 @@ public class ActivityOptions extends ComponentOptions { private boolean mLaunchedFromBubble; private boolean mTransientLaunch; private PictureInPictureParams mLaunchIntoPipParams; - private boolean mDismissKeyguard; + private boolean mDismissKeyguardIfInsecure; @BackgroundActivityStartMode private int mPendingIntentCreatorBackgroundActivityStartMode = MODE_BACKGROUND_ACTIVITY_START_SYSTEM_DEFINED; @@ -1333,7 +1333,7 @@ public class ActivityOptions extends ComponentOptions { mLaunchIntoPipParams = opts.getParcelable(KEY_LAUNCH_INTO_PIP_PARAMS, android.app.PictureInPictureParams.class); mIsEligibleForLegacyPermissionPrompt = opts.getBoolean(KEY_LEGACY_PERMISSION_PROMPT_ELIGIBLE); - mDismissKeyguard = opts.getBoolean(KEY_DISMISS_KEYGUARD); + mDismissKeyguardIfInsecure = opts.getBoolean(KEY_DISMISS_KEYGUARD_IF_INSECURE); mPendingIntentCreatorBackgroundActivityStartMode = opts.getInt( KEY_PENDING_INTENT_CREATOR_BACKGROUND_ACTIVITY_START_MODE, MODE_BACKGROUND_ACTIVITY_START_SYSTEM_DEFINED); @@ -2036,24 +2036,24 @@ public class ActivityOptions extends ComponentOptions { } /** - * Sets whether the keyguard should go away when this activity launches. + * Sets whether the insecure keyguard should go away when this activity launches. In case the + * keyguard is secure, this option will be ignored. * * @see Activity#setShowWhenLocked(boolean) * @see android.R.attr#showWhenLocked * @hide */ - @RequiresPermission(CONTROL_KEYGUARD) - public void setDismissKeyguard() { - mDismissKeyguard = true; + public void setDismissKeyguardIfInsecure() { + mDismissKeyguardIfInsecure = true; } /** - * @see #setDismissKeyguard() + * @see #setDismissKeyguardIfInsecure() * @return whether the insecure keyguard should go away when the activity launches. * @hide */ - public boolean getDismissKeyguard() { - return mDismissKeyguard; + public boolean getDismissKeyguardIfInsecure() { + return mDismissKeyguardIfInsecure; } /** @@ -2367,8 +2367,8 @@ public class ActivityOptions extends ComponentOptions { b.putBoolean(KEY_LEGACY_PERMISSION_PROMPT_ELIGIBLE, mIsEligibleForLegacyPermissionPrompt); } - if (mDismissKeyguard) { - b.putBoolean(KEY_DISMISS_KEYGUARD, mDismissKeyguard); + if (mDismissKeyguardIfInsecure) { + b.putBoolean(KEY_DISMISS_KEYGUARD_IF_INSECURE, mDismissKeyguardIfInsecure); } if (mPendingIntentCreatorBackgroundActivityStartMode != MODE_BACKGROUND_ACTIVITY_START_SYSTEM_DEFINED) { diff --git a/core/java/android/app/AppOpsManager.java b/core/java/android/app/AppOpsManager.java index 7e84ceb4a61d..b03bd59c305e 100644 --- a/core/java/android/app/AppOpsManager.java +++ b/core/java/android/app/AppOpsManager.java @@ -16,10 +16,13 @@ package android.app; +import static android.view.contentprotection.flags.Flags.FLAG_CREATE_ACCESSIBILITY_OVERLAY_APP_OP_ENABLED; + import static java.lang.Long.max; import android.Manifest; import android.annotation.CallbackExecutor; +import android.annotation.FlaggedApi; import android.annotation.IntDef; import android.annotation.IntRange; import android.annotation.NonNull; @@ -1495,9 +1498,17 @@ public class AppOpsManager { public static final int OP_RECEIVE_SANDBOXED_DETECTION_TRAINING_DATA = AppProtoEnums.APP_OP_RECEIVE_SANDBOXED_DETECTION_TRAINING_DATA; + /** + * Creation of an overlay using accessibility services + * + * @hide + */ + public static final int OP_CREATE_ACCESSIBILITY_OVERLAY = + AppProtoEnums.APP_OP_CREATE_ACCESSIBILITY_OVERLAY; + /** @hide */ @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553) - public static final int _NUM_OP = 138; + public static final int _NUM_OP = 139; /** * All app ops represented as strings. @@ -1641,7 +1652,8 @@ public class AppOpsManager { OPSTR_CAMERA_SANDBOXED, OPSTR_RECORD_AUDIO_SANDBOXED, OPSTR_RECEIVE_SANDBOX_TRIGGER_AUDIO, - OPSTR_RECEIVE_SANDBOXED_DETECTION_TRAINING_DATA + OPSTR_RECEIVE_SANDBOXED_DETECTION_TRAINING_DATA, + OPSTR_CREATE_ACCESSIBILITY_OVERLAY, }) public @interface AppOpString {} @@ -2270,6 +2282,16 @@ public class AppOpsManager { public static final String OPSTR_RECEIVE_SANDBOXED_DETECTION_TRAINING_DATA = "android:RECEIVE_SANDBOXED_DETECTION_TRAINING_DATA"; + /** + * Creation of an overlay using accessibility services + * + * @hide + */ + @SystemApi + @FlaggedApi(FLAG_CREATE_ACCESSIBILITY_OVERLAY_APP_OP_ENABLED) + public static final String OPSTR_CREATE_ACCESSIBILITY_OVERLAY = + "android:create_accessibility_overlay"; + /** {@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} */ @@ -2819,7 +2841,11 @@ public class AppOpsManager { OPSTR_RECEIVE_SANDBOXED_DETECTION_TRAINING_DATA, "RECEIVE_SANDBOXED_DETECTION_TRAINING_DATA") .setPermission(Manifest.permission.RECEIVE_SANDBOXED_DETECTION_TRAINING_DATA) - .setDefaultMode(AppOpsManager.MODE_DEFAULT).build() + .setDefaultMode(AppOpsManager.MODE_DEFAULT).build(), + new AppOpInfo.Builder(OP_CREATE_ACCESSIBILITY_OVERLAY, + OPSTR_CREATE_ACCESSIBILITY_OVERLAY, + "CREATE_ACCESSIBILITY_OVERLAY") + .setDefaultMode(AppOpsManager.MODE_ALLOWED).build(), }; // The number of longs needed to form a full bitmask of app ops diff --git a/core/java/android/app/ApplicationPackageManager.java b/core/java/android/app/ApplicationPackageManager.java index 367e92b9d960..ca6d8df1df12 100644 --- a/core/java/android/app/ApplicationPackageManager.java +++ b/core/java/android/app/ApplicationPackageManager.java @@ -2586,6 +2586,16 @@ public class ApplicationPackageManager extends PackageManager { } @Override + public boolean isAppArchivable(String packageName) throws NameNotFoundException { + try { + Objects.requireNonNull(packageName); + return mPM.isAppArchivable(packageName, new UserHandle(getUserId())); + } catch (RemoteException e) { + throw e.rethrowFromSystemServer(); + } + } + + @Override public int getMoveStatus(int moveId) { try { return mPM.getMoveStatus(moveId); diff --git a/core/java/android/app/Notification.java b/core/java/android/app/Notification.java index bbc843b0acc5..2d80b1ffca6c 100644 --- a/core/java/android/app/Notification.java +++ b/core/java/android/app/Notification.java @@ -31,6 +31,7 @@ import android.annotation.ColorRes; import android.annotation.DimenRes; import android.annotation.Dimension; import android.annotation.DrawableRes; +import android.annotation.FlaggedApi; import android.annotation.IdRes; import android.annotation.IntDef; import android.annotation.NonNull; @@ -12242,6 +12243,7 @@ public class Notification implements Parcelable * {@code TvExtender(Notification)} constructor, and then using the {@code get} methods * to access values. */ + @FlaggedApi(Flags.FLAG_API_TVEXTENDER) public static final class TvExtender implements Extender { private static final String TAG = "TvExtender"; diff --git a/core/java/android/app/OWNERS b/core/java/android/app/OWNERS index 9cf54e3b9063..cc56a1cee7a2 100644 --- a/core/java/android/app/OWNERS +++ b/core/java/android/app/OWNERS @@ -36,6 +36,7 @@ per-file GameMode* = file:/GAME_MANAGER_OWNERS per-file GameState* = file:/GAME_MANAGER_OWNERS per-file IGameManager* = file:/GAME_MANAGER_OWNERS per-file IGameMode* = file:/GAME_MANAGER_OWNERS +per-file BackgroundStartPrivileges.java = file:/BAL_OWNERS # ActivityThread per-file ActivityThread.java = file:/services/core/java/com/android/server/am/OWNERS diff --git a/core/java/android/app/admin/DevicePolicyManager.java b/core/java/android/app/admin/DevicePolicyManager.java index 7704486b606c..a46c1006d314 100644 --- a/core/java/android/app/admin/DevicePolicyManager.java +++ b/core/java/android/app/admin/DevicePolicyManager.java @@ -49,6 +49,7 @@ import static android.Manifest.permission.QUERY_ADMIN_POLICY; import static android.Manifest.permission.REQUEST_PASSWORD_COMPLEXITY; import static android.Manifest.permission.SET_TIME; import static android.Manifest.permission.SET_TIME_ZONE; +import static android.app.admin.flags.Flags.onboardingBugreportV2Enabled; import static android.content.Intent.LOCAL_FLAG_FROM_SYSTEM; import static android.net.NetworkCapabilities.NET_ENTERPRISE_ID_1; import static android.os.Build.VERSION_CODES.UPSIDE_DOWN_CAKE; @@ -17136,4 +17137,14 @@ public class DevicePolicyManager { } return null; } -} + + // TODO(b/308755220): Remove once the build is finalised. + /** + * Returns true if the flag for the onboarding bugreport V2 is enabled. + * + * @hide + */ + public boolean isOnboardingBugreportV2FlagEnabled() { + return onboardingBugreportV2Enabled(); + } +}
\ No newline at end of file diff --git a/core/java/android/app/notification.aconfig b/core/java/android/app/notification.aconfig index cd1d8ce66cb5..d9b521f1a9a8 100644 --- a/core/java/android/app/notification.aconfig +++ b/core/java/android/app/notification.aconfig @@ -5,4 +5,13 @@ flag { namespace: "systemui" description: "This flag controls new and updated DND apis" bug: "300477976" -}
\ No newline at end of file +} + +flag { + name: "api_tvextender" + namespace: "systemui" + description: "Guards new android.app.Notification.TvExtender api" + bug: "308164892" + is_fixed_read_only: true +} + diff --git a/core/java/android/appwidget/AppWidgetManager.java b/core/java/android/appwidget/AppWidgetManager.java index 3abe1d9494f0..c6012bbc7292 100644 --- a/core/java/android/appwidget/AppWidgetManager.java +++ b/core/java/android/appwidget/AppWidgetManager.java @@ -562,13 +562,6 @@ public class AppWidgetManager { }); } - private boolean isPostingTaskToBackground(@Nullable RemoteViews views) { - return Looper.myLooper() == Looper.getMainLooper() - && RemoteViews.isAdapterConversionEnabled() - && (mHasPostedLegacyLists = mHasPostedLegacyLists - || (views != null && views.hasLegacyLists())); - } - /** * Set the RemoteViews to use for the specified appWidgetIds. * <p> @@ -593,16 +586,25 @@ public class AppWidgetManager { return; } - if (isPostingTaskToBackground(views)) { - createUpdateExecutorIfNull().execute(() -> { - try { - mService.updateAppWidgetIds(mPackageName, appWidgetIds, views); - } catch (RemoteException e) { - Log.e(TAG, "Error updating app widget views in background", e); - } - }); + final boolean isConvertingAdapter = RemoteViews.isAdapterConversionEnabled() + && (mHasPostedLegacyLists = mHasPostedLegacyLists + || (views != null && views.hasLegacyLists())); - return; + if (isConvertingAdapter) { + views.collectAllIntents(); + + if (Looper.getMainLooper() == Looper.myLooper()) { + RemoteViews viewsCopy = new RemoteViews(views); + createUpdateExecutorIfNull().execute(() -> { + try { + mService.updateAppWidgetIds(mPackageName, appWidgetIds, viewsCopy); + } catch (RemoteException e) { + Log.e(TAG, "Error updating app widget views in background", e); + } + }); + + return; + } } try { @@ -714,16 +716,25 @@ public class AppWidgetManager { return; } - if (isPostingTaskToBackground(views)) { - createUpdateExecutorIfNull().execute(() -> { - try { - mService.partiallyUpdateAppWidgetIds(mPackageName, appWidgetIds, views); - } catch (RemoteException e) { - Log.e(TAG, "Error partially updating app widget views in background", e); - } - }); + final boolean isConvertingAdapter = RemoteViews.isAdapterConversionEnabled() + && (mHasPostedLegacyLists = mHasPostedLegacyLists + || (views != null && views.hasLegacyLists())); + + if (isConvertingAdapter) { + views.collectAllIntents(); - return; + if (Looper.getMainLooper() == Looper.myLooper()) { + RemoteViews viewsCopy = new RemoteViews(views); + createUpdateExecutorIfNull().execute(() -> { + try { + mService.partiallyUpdateAppWidgetIds(mPackageName, appWidgetIds, viewsCopy); + } catch (RemoteException e) { + Log.e(TAG, "Error partially updating app widget views in background", e); + } + }); + + return; + } } try { @@ -782,16 +793,26 @@ public class AppWidgetManager { return; } - if (isPostingTaskToBackground(views)) { - createUpdateExecutorIfNull().execute(() -> { - try { - mService.updateAppWidgetProvider(provider, views); - } catch (RemoteException e) { - Log.e(TAG, "Error updating app widget view using provider in background", e); - } - }); + final boolean isConvertingAdapter = RemoteViews.isAdapterConversionEnabled() + && (mHasPostedLegacyLists = mHasPostedLegacyLists + || (views != null && views.hasLegacyLists())); + + if (isConvertingAdapter) { + views.collectAllIntents(); - return; + if (Looper.getMainLooper() == Looper.myLooper()) { + RemoteViews viewsCopy = new RemoteViews(views); + createUpdateExecutorIfNull().execute(() -> { + try { + mService.updateAppWidgetProvider(provider, viewsCopy); + } catch (RemoteException e) { + Log.e(TAG, "Error updating app widget view using provider in background", + e); + } + }); + + return; + } } try { diff --git a/core/java/android/companion/virtual/VirtualDeviceParams.java b/core/java/android/companion/virtual/VirtualDeviceParams.java index 0975cbb8684f..97a7aa4a3bea 100644 --- a/core/java/android/companion/virtual/VirtualDeviceParams.java +++ b/core/java/android/companion/virtual/VirtualDeviceParams.java @@ -169,7 +169,8 @@ public final class VirtualDeviceParams implements Parcelable { * @see VirtualDeviceManager.VirtualDevice#setDevicePolicy * @hide */ - @IntDef(prefix = "POLICY_TYPE_", value = {POLICY_TYPE_RECENTS, POLICY_TYPE_ACTIVITY}) + @IntDef(prefix = "POLICY_TYPE_", value = {POLICY_TYPE_RECENTS, POLICY_TYPE_ACTIVITY, + POLICY_TYPE_CLIPBOARD}) @Retention(RetentionPolicy.SOURCE) @Target({ElementType.TYPE_PARAMETER, ElementType.TYPE_USE}) public @interface DynamicPolicyType {} @@ -230,6 +231,20 @@ public final class VirtualDeviceParams implements Parcelable { @FlaggedApi(Flags.FLAG_DYNAMIC_POLICY) public static final int POLICY_TYPE_ACTIVITY = 3; + /** + * Tells the clipboard manager whether this device's clipboard should be shared or not. + * + * <ul> + * <li>{@link #DEVICE_POLICY_DEFAULT}: By default the device's clipboard is its own and is + * not shared with other devices' clipboards, including the clipboard of the default device. + * <li>{@link #DEVICE_POLICY_CUSTOM}: The device's clipboard is shared with the default + * device's clipboard. Any clipboard operation on the virtual device is as if it was done on + * the default device. + * </ul> + */ + @FlaggedApi(Flags.FLAG_CROSS_DEVICE_CLIPBOARD) + public static final int POLICY_TYPE_CLIPBOARD = 4; + private final int mLockState; @NonNull private final ArraySet<UserHandle> mUsersWithMatchingAccounts; @NavigationPolicy @@ -1086,6 +1101,10 @@ public final class VirtualDeviceParams implements Parcelable { } } + if (!Flags.crossDeviceClipboard()) { + mDevicePolicies.delete(POLICY_TYPE_CLIPBOARD); + } + if ((mAudioPlaybackSessionId != AUDIO_SESSION_ID_GENERATE || mAudioRecordingSessionId != AUDIO_SESSION_ID_GENERATE) && mDevicePolicies.get(POLICY_TYPE_AUDIO, DEVICE_POLICY_DEFAULT) diff --git a/core/java/android/companion/virtual/flags.aconfig b/core/java/android/companion/virtual/flags.aconfig index 3cadb7c09d54..cfab9ebec593 100644 --- a/core/java/android/companion/virtual/flags.aconfig +++ b/core/java/android/companion/virtual/flags.aconfig @@ -16,6 +16,13 @@ flag { } flag { + name: "cross_device_clipboard" + namespace: "virtual_devices" + description: "Enable cross-device clipboard API" + bug: "306622082" +} + +flag { name: "vdm_custom_home" namespace: "virtual_devices" description: "Enable custom home API" diff --git a/core/java/android/content/Intent.java b/core/java/android/content/Intent.java index ffc4805df264..ea54c912d4b9 100644 --- a/core/java/android/content/Intent.java +++ b/core/java/android/content/Intent.java @@ -1164,6 +1164,11 @@ public class Intent implements Parcelable, Cloneable { * numbers. Applications can <strong>dial</strong> emergency numbers using * {@link #ACTION_DIAL}, however. * + * <p>Note: This Intent can only be used to dial call forwarding MMI codes if the application + * using this intent is set as the default or system dialer. The system will treat any other + * application using this Intent for the purpose of dialing call forwarding MMI codes as if the + * {@link #ACTION_DIAL} Intent was used instead. + * * <p>Note: An app filling the {@link android.app.role.RoleManager#ROLE_DIALER} role should use * {@link android.telecom.TelecomManager#placeCall(Uri, Bundle)} to place calls rather than * relying on this intent. diff --git a/core/java/android/content/pm/IPackageManager.aidl b/core/java/android/content/pm/IPackageManager.aidl index 99264150f7d0..babfba13afcd 100644 --- a/core/java/android/content/pm/IPackageManager.aidl +++ b/core/java/android/content/pm/IPackageManager.aidl @@ -838,4 +838,6 @@ interface IPackageManager { ArchivedPackageParcel getArchivedPackage(in String packageName, int userId); Bitmap getArchivedAppIcon(String packageName, in UserHandle user); + + boolean isAppArchivable(String packageName, in UserHandle user); } diff --git a/core/java/android/content/pm/PackageManager.java b/core/java/android/content/pm/PackageManager.java index dea4a12541e5..36433ce84618 100644 --- a/core/java/android/content/pm/PackageManager.java +++ b/core/java/android/content/pm/PackageManager.java @@ -8910,6 +8910,20 @@ public abstract class PackageManager { } /** + * Returns true if an app is archivable. + * + * @throws NameNotFoundException if the given package name is not available to the caller. + * @see PackageInstaller#requestArchive(String, IntentSender) + * + * @hide + */ + @SystemApi + @FlaggedApi(android.content.pm.Flags.FLAG_ARCHIVING) + public boolean isAppArchivable(@NonNull String packageName) throws NameNotFoundException { + throw new UnsupportedOperationException("isAppArchivable not implemented"); + } + + /** * Attempts to clear the user data directory of an application. * Since this may take a little while, the result will * be posted back to the given observer. A deletion will fail if the diff --git a/core/java/android/credentials/CredentialManager.java b/core/java/android/credentials/CredentialManager.java index 524afe975d73..ad3ccc41cf6d 100644 --- a/core/java/android/credentials/CredentialManager.java +++ b/core/java/android/credentials/CredentialManager.java @@ -437,7 +437,14 @@ public final class CredentialManager { * Returns {@code true} if the calling application provides a CredentialProviderService that is * enabled for the current user, or {@code false} otherwise. CredentialProviderServices are * enabled on a per-service basis so the individual component name of the service should be - * passed in here. + * passed in here. <strong>Usage of this API is discouraged as it is not fully functional, and + * may throw a NullPointerException on certain devices and/or API versions.</strong> + * + * @throws IllegalArgumentException if the componentName package does not match the calling + * package name this call will throw an exception + * + * @throws NullPointerException Usage of this API is discouraged as it is not fully + * functional, and may throw a NullPointerException on certain devices and/or API versions * * @param componentName the component name to check is enabled */ diff --git a/core/java/android/os/GraphicsEnvironment.java b/core/java/android/os/GraphicsEnvironment.java index a07735e7540e..8fcff78fb025 100644 --- a/core/java/android/os/GraphicsEnvironment.java +++ b/core/java/android/os/GraphicsEnvironment.java @@ -117,8 +117,6 @@ public class GraphicsEnvironment { private static final String ANGLE_GL_DRIVER_CHOICE_NATIVE = "native"; private static final String SYSTEM_ANGLE_STRING = "system"; - private static final String PROPERTY_RO_ANGLE_SUPPORTED = "ro.gfx.angle.supported"; - private ClassLoader mClassLoader; private String mLibrarySearchPaths; private String mLibraryPermittedPaths; @@ -620,8 +618,7 @@ public class GraphicsEnvironment { } /** - * Attempt to set up ANGLE from system, if the apk can be found, pass ANGLE details to - * the C++ GraphicsEnv class. + * Set up ANGLE from system. * * @param context - Context of the application. * @param bundle - Bundle of the application. @@ -630,14 +627,8 @@ public class GraphicsEnvironment { * false: can not set up to use system ANGLE because it doesn't exist. */ private boolean setupAngleFromSystem(Context context, Bundle bundle, String packageName) { - final boolean systemAngleSupported = SystemProperties - .getBoolean(PROPERTY_RO_ANGLE_SUPPORTED, false); - if (!systemAngleSupported) { - return false; - } - - // If we make it to here, system ANGLE will be used. Call nativeSetAngleInfo() with - // the application package name and ANGLE features to use. + // System ANGLE always exists, call nativeSetAngleInfo() with the application package + // name and ANGLE features to use. final String[] features = getAngleEglFeatures(context, bundle); nativeSetAngleInfo(SYSTEM_ANGLE_STRING, false, packageName, features); return true; diff --git a/core/java/android/os/Process.java b/core/java/android/os/Process.java index e37b2b5ef3ef..677143afd4fb 100644 --- a/core/java/android/os/Process.java +++ b/core/java/android/os/Process.java @@ -730,13 +730,14 @@ public class Process { whitelistedDataInfoMap, boolean bindMountAppsData, boolean bindMountAppStorageDirs, + boolean bindMountSystemOverrides, @Nullable String[] zygoteArgs) { return ZYGOTE_PROCESS.start(processClass, niceName, uid, gid, gids, runtimeFlags, mountExternal, targetSdkVersion, seInfo, abi, instructionSet, appDataDir, invokeWith, packageName, zygotePolicyFlags, isTopApp, disabledCompatChanges, pkgDataInfoMap, whitelistedDataInfoMap, bindMountAppsData, - bindMountAppStorageDirs, zygoteArgs); + bindMountAppStorageDirs, bindMountSystemOverrides, zygoteArgs); } /** @hide */ @@ -753,6 +754,7 @@ public class Process { @Nullable String invokeWith, @Nullable String packageName, @Nullable long[] disabledCompatChanges, + boolean bindMountSyspropOverrides, @Nullable String[] zygoteArgs) { // Webview zygote can't access app private data files, so doesn't need to know its data // info. @@ -761,7 +763,8 @@ public class Process { abi, instructionSet, appDataDir, invokeWith, packageName, /*zygotePolicyFlags=*/ ZYGOTE_POLICY_FLAG_EMPTY, /*isTopApp=*/ false, disabledCompatChanges, /* pkgDataInfoMap */ null, - /* whitelistedDataInfoMap */ null, false, false, zygoteArgs); + /* whitelistedDataInfoMap */ null, /* bindMountAppsData */ false, + /* bindMountAppStorageDirs */ false, bindMountSyspropOverrides, zygoteArgs); } /** diff --git a/core/java/android/os/ZygoteProcess.java b/core/java/android/os/ZygoteProcess.java index 3cb5c60259eb..c14810bbcd64 100644 --- a/core/java/android/os/ZygoteProcess.java +++ b/core/java/android/os/ZygoteProcess.java @@ -355,6 +355,7 @@ public class ZygoteProcess { allowlistedDataInfoList, boolean bindMountAppsData, boolean bindMountAppStorageDirs, + boolean bindOverrideSysprops, @Nullable String[] zygoteArgs) { // TODO (chriswailes): Is there a better place to check this value? if (fetchUsapPoolEnabledPropWithMinInterval()) { @@ -367,7 +368,7 @@ public class ZygoteProcess { abi, instructionSet, appDataDir, invokeWith, /*startChildZygote=*/ false, packageName, zygotePolicyFlags, isTopApp, disabledCompatChanges, pkgDataInfoMap, allowlistedDataInfoList, bindMountAppsData, - bindMountAppStorageDirs, zygoteArgs); + bindMountAppStorageDirs, bindOverrideSysprops, zygoteArgs); } catch (ZygoteStartFailedEx ex) { Log.e(LOG_TAG, "Starting VM process through Zygote failed"); @@ -638,6 +639,7 @@ public class ZygoteProcess { allowlistedDataInfoList, boolean bindMountAppsData, boolean bindMountAppStorageDirs, + boolean bindMountOverrideSysprops, @Nullable String[] extraArgs) throws ZygoteStartFailedEx { ArrayList<String> argsForZygote = new ArrayList<>(); @@ -753,6 +755,10 @@ public class ZygoteProcess { argsForZygote.add(Zygote.BIND_MOUNT_APP_DATA_DIRS); } + if (bindMountOverrideSysprops) { + argsForZygote.add(Zygote.BIND_MOUNT_SYSPROP_OVERRIDES); + } + if (disabledCompatChanges != null && disabledCompatChanges.length > 0) { StringBuilder sb = new StringBuilder(); sb.append("--disabled-compat-changes="); @@ -1306,7 +1312,8 @@ public class ZygoteProcess { ZYGOTE_POLICY_FLAG_SYSTEM_PROCESS /* zygotePolicyFlags */, false /* isTopApp */, null /* disabledCompatChanges */, null /* pkgDataInfoMap */, null /* allowlistedDataInfoList */, true /* bindMountAppsData*/, - /* bindMountAppStorageDirs */ false, extraArgs); + /* bindMountAppStorageDirs */ false, /*bindMountOverrideSysprops */ false, + extraArgs); } catch (ZygoteStartFailedEx ex) { throw new RuntimeException("Starting child-zygote through Zygote failed", ex); diff --git a/core/java/android/provider/Settings.java b/core/java/android/provider/Settings.java index c282c9685f24..9f931b4059c8 100644 --- a/core/java/android/provider/Settings.java +++ b/core/java/android/provider/Settings.java @@ -5914,6 +5914,7 @@ public final class Settings { * * @hide */ + @Readable public static final String TOUCHPAD_NATURAL_SCROLLING = "touchpad_natural_scrolling"; /** @@ -10308,6 +10309,13 @@ public final class Settings { @Readable public static final String SHOW_NOTIFICATION_SNOOZE = "show_notification_snooze"; + /** + * 1 if it is allowed to remove the primary GAIA account. 0 by default. + * @hide + */ + public static final String ALLOW_PRIMARY_GAIA_ACCOUNT_REMOVAL_FOR_TESTS = + "allow_primary_gaia_account_removal_for_tests"; + /** * List of TV inputs that are currently hidden. This is a string * containing the IDs of all hidden TV inputs. Each ID is encoded by diff --git a/core/java/android/provider/Telephony.java b/core/java/android/provider/Telephony.java index 27ad45de69e6..bcda25a1bf3b 100644 --- a/core/java/android/provider/Telephony.java +++ b/core/java/android/provider/Telephony.java @@ -3206,6 +3206,15 @@ public final class Telephony { public static final String INFRASTRUCTURE_BITMASK = "infrastructure_bitmask"; /** + * Indicating if the APN is used for eSIM bootsrap provisioning. The default value is 0 (Not + * used for eSIM bootstrap provisioning). + * + * <P>Type: INTEGER</P> + * @hide + */ + public static final String ESIM_BOOTSTRAP_PROVISIONING = "esim_bootstrap_provisioning"; + + /** * MVNO type: * {@code SPN (Service Provider Name), IMSI, GID (Group Identifier Level 1)}. * <P>Type: TEXT</P> diff --git a/core/java/android/security/OWNERS b/core/java/android/security/OWNERS index 96c0be7f803e..33a67aed6023 100644 --- a/core/java/android/security/OWNERS +++ b/core/java/android/security/OWNERS @@ -8,3 +8,4 @@ per-file *NetworkSecurityPolicy.java = file:net/OWNERS per-file Confirmation*.java = file:/keystore/OWNERS per-file FileIntegrityManager.java = file:platform/system/security:/fsverity/OWNERS per-file IFileIntegrityService.aidl = file:platform/system/security:/fsverity/OWNERS +per-file *.aconfig = victorhsieh@google.com diff --git a/core/java/android/security/flags.aconfig b/core/java/android/security/flags.aconfig index 94eca3d16187..0133bd822182 100644 --- a/core/java/android/security/flags.aconfig +++ b/core/java/android/security/flags.aconfig @@ -29,3 +29,10 @@ flag { bug: "277916185" is_fixed_read_only: true } + +flag { + name: "binary_transparency_sepolicy_hash" + namespace: "hardware_backed_security" + description: "Collect sepolicy hash from sysfs" + bug: "308471499" +} diff --git a/core/java/android/text/flags/flags.aconfig b/core/java/android/text/flags/flags.aconfig index 43c38f319713..a1885ae616e1 100644 --- a/core/java/android/text/flags/flags.aconfig +++ b/core/java/android/text/flags/flags.aconfig @@ -75,3 +75,10 @@ flag { description: "A feature flag that implements line break word style auto." bug: "280005585" } + +flag { + name: "inter_character_justification" + namespace: "text" + description: "A feature flag that implement inter character justification." + bug: "283193133" +} diff --git a/core/java/android/view/SurfaceControlRegistry.java b/core/java/android/view/SurfaceControlRegistry.java index 52be8f6a76fd..127d4a70a564 100644 --- a/core/java/android/view/SurfaceControlRegistry.java +++ b/core/java/android/view/SurfaceControlRegistry.java @@ -337,13 +337,13 @@ public class SurfaceControlRegistry { @VisibleForTesting public final boolean matchesForCallStackDebugging(@Nullable String name, @NonNull String call) { final boolean matchCall = !sCallStackDebuggingMatchCall.isEmpty(); - if (matchCall && !call.toLowerCase().contains(sCallStackDebuggingMatchCall)) { + if (matchCall && !sCallStackDebuggingMatchCall.contains(call.toLowerCase())) { // Skip if target call doesn't match requested caller return false; } final boolean matchName = !sCallStackDebuggingMatchName.isEmpty(); if (matchName && (name == null - || !name.toLowerCase().contains(sCallStackDebuggingMatchName))) { + || !sCallStackDebuggingMatchName.contains(name.toLowerCase()))) { // Skip if target surface doesn't match requested surface return false; } diff --git a/core/java/android/view/SurfaceView.java b/core/java/android/view/SurfaceView.java index 5b69d7fdeb35..0ae14a2fdb30 100644 --- a/core/java/android/view/SurfaceView.java +++ b/core/java/android/view/SurfaceView.java @@ -43,6 +43,7 @@ import android.os.IBinder; import android.os.Looper; import android.os.RemoteException; import android.os.SystemClock; +import android.text.TextUtils; import android.util.ArraySet; import android.util.AttributeSet; import android.util.Log; @@ -51,6 +52,7 @@ import android.view.accessibility.AccessibilityNodeInfo; import android.view.accessibility.IAccessibilityEmbeddedConnection; import android.window.SurfaceSyncGroup; +import com.android.graphics.hwui.flags.Flags; import com.android.internal.view.SurfaceCallbackHelper; import java.lang.annotation.Retention; @@ -326,6 +328,8 @@ public class SurfaceView extends View implements ViewRootImpl.SurfaceChangedCall } }; + private final boolean mRtDrivenClipping = Flags.clipSurfaceviews(); + public SurfaceView(Context context) { this(context, null); } @@ -572,6 +576,10 @@ public class SurfaceView extends View implements ViewRootImpl.SurfaceChangedCall public void setClipBounds(Rect clipBounds) { super.setClipBounds(clipBounds); + if (mRtDrivenClipping && isHardwareAccelerated()) { + return; + } + if (!mClipSurfaceToBounds || mSurfaceControl == null) { return; } @@ -915,15 +923,17 @@ public class SurfaceView extends View implements ViewRootImpl.SurfaceChangedCall } if (sizeChanged || creating || !isHardwareAccelerated()) { - // Set a window crop when creating the surface or changing its size to - // crop the buffer to the surface size since the buffer producer may - // use SCALING_MODE_SCALE and submit a larger size than the surface - // size. - if (mClipSurfaceToBounds && mClipBounds != null) { - surfaceUpdateTransaction.setWindowCrop(mSurfaceControl, mClipBounds); - } else { - surfaceUpdateTransaction.setWindowCrop(mSurfaceControl, mSurfaceWidth, - mSurfaceHeight); + if (!mRtDrivenClipping || !isHardwareAccelerated()) { + // Set a window crop when creating the surface or changing its size to + // crop the buffer to the surface size since the buffer producer may + // use SCALING_MODE_SCALE and submit a larger size than the surface + // size. + if (mClipSurfaceToBounds && mClipBounds != null) { + surfaceUpdateTransaction.setWindowCrop(mSurfaceControl, mClipBounds); + } else { + surfaceUpdateTransaction.setWindowCrop(mSurfaceControl, mSurfaceWidth, + mSurfaceHeight); + } } surfaceUpdateTransaction.setDesintationFrame(mBlastSurfaceControl, mSurfaceWidth, @@ -941,7 +951,7 @@ public class SurfaceView extends View implements ViewRootImpl.SurfaceChangedCall mScreenRect.height() / (float) mSurfaceHeight /*postScaleY*/); } if (DEBUG_POSITION) { - Log.d(TAG, String.format( + Log.d(TAG, TextUtils.formatSimple( "%d performSurfaceTransaction %s " + "position = [%d, %d, %d, %d] surfaceSize = %dx%d", System.identityHashCode(this), @@ -1453,6 +1463,7 @@ public class SurfaceView extends View implements ViewRootImpl.SurfaceChangedCall } private final Rect mRTLastReportedPosition = new Rect(); + private final Rect mRTLastSetCrop = new Rect(); private class SurfaceViewPositionUpdateListener implements RenderNode.PositionUpdateListener { private final int mRtSurfaceWidth; @@ -1496,6 +1507,45 @@ public class SurfaceView extends View implements ViewRootImpl.SurfaceChangedCall } @Override + public void positionChanged(long frameNumber, int left, int top, int right, int bottom, + int clipLeft, int clipTop, int clipRight, int clipBottom) { + try { + if (DEBUG_POSITION) { + Log.d(TAG, String.format( + "%d updateSurfacePosition RenderWorker, frameNr = %d, " + + "position = [%d, %d, %d, %d] clip = [%d, %d, %d, %d] " + + "surfaceSize = %dx%d", + System.identityHashCode(SurfaceView.this), frameNumber, + left, top, right, bottom, clipLeft, clipTop, clipRight, clipBottom, + mRtSurfaceWidth, mRtSurfaceHeight)); + } + synchronized (mSurfaceControlLock) { + if (mSurfaceControl == null) return; + + mRTLastReportedPosition.set(left, top, right, bottom); + onSetSurfacePositionAndScale(mPositionChangedTransaction, mSurfaceControl, + mRTLastReportedPosition.left /*positionLeft*/, + mRTLastReportedPosition.top /*positionTop*/, + mRTLastReportedPosition.width() + / (float) mRtSurfaceWidth /*postScaleX*/, + mRTLastReportedPosition.height() + / (float) mRtSurfaceHeight /*postScaleY*/); + + mRTLastSetCrop.set(clipLeft, clipTop, clipRight, clipBottom); + mPositionChangedTransaction.setCrop(mSurfaceControl, mRTLastSetCrop); + if (mRTLastSetCrop.isEmpty()) { + mPositionChangedTransaction.hide(mSurfaceControl); + } else { + mPositionChangedTransaction.show(mSurfaceControl); + } + } + applyOrMergeTransaction(mPositionChangedTransaction, frameNumber); + } catch (Exception ex) { + Log.e(TAG, "Exception from repositionChild", ex); + } + } + + @Override public void applyStretch(long frameNumber, float width, float height, float vecX, float vecY, float maxStretchX, float maxStretchY, float childRelativeLeft, float childRelativeTop, float childRelativeRight, diff --git a/core/java/android/view/ViewRootImpl.java b/core/java/android/view/ViewRootImpl.java index dd2a104e37f4..24223694e421 100644 --- a/core/java/android/view/ViewRootImpl.java +++ b/core/java/android/view/ViewRootImpl.java @@ -3983,8 +3983,17 @@ public final class ViewRootImpl implements ViewParent, } private void notifyContentCaptureEvents() { - Trace.traceBegin(Trace.TRACE_TAG_VIEW, "notifyContentCaptureEvents"); try { + if (!isContentCaptureEnabled()) { + if (DEBUG_CONTENT_CAPTURE) { + Log.d(mTag, "notifyContentCaptureEvents while disabled"); + } + mAttachInfo.mContentCaptureEvents = null; + return; + } + if (Trace.isTagEnabled(Trace.TRACE_TAG_VIEW)) { + Trace.traceBegin(Trace.TRACE_TAG_VIEW, "notifyContentCaptureEvents"); + } MainContentCaptureSession mainSession = mAttachInfo.mContentCaptureManager .getMainContentCaptureSession(); for (int i = 0; i < mAttachInfo.mContentCaptureEvents.size(); i++) { @@ -4898,13 +4907,14 @@ public final class ViewRootImpl implements ViewParent, if (DEBUG_CONTENT_CAPTURE) { Log.v(mTag, "performContentCaptureInitialReport() on " + rootView); } - if (Trace.isTagEnabled(Trace.TRACE_TAG_VIEW)) { - Trace.traceBegin(Trace.TRACE_TAG_VIEW, "dispatchContentCapture() for " - + getClass().getSimpleName()); - } try { if (!isContentCaptureEnabled()) return; + if (Trace.isTagEnabled(Trace.TRACE_TAG_VIEW)) { + Trace.traceBegin(Trace.TRACE_TAG_VIEW, "dispatchContentCapture() for " + + getClass().getSimpleName()); + } + // Initial dispatch of window bounds to content capture if (mAttachInfo.mContentCaptureManager != null) { MainContentCaptureSession session = @@ -4924,13 +4934,14 @@ public final class ViewRootImpl implements ViewParent, if (DEBUG_CONTENT_CAPTURE) { Log.v(mTag, "handleContentCaptureFlush()"); } - if (Trace.isTagEnabled(Trace.TRACE_TAG_VIEW)) { - Trace.traceBegin(Trace.TRACE_TAG_VIEW, "flushContentCapture for " - + getClass().getSimpleName()); - } try { if (!isContentCaptureEnabled()) return; + if (Trace.isTagEnabled(Trace.TRACE_TAG_VIEW)) { + Trace.traceBegin(Trace.TRACE_TAG_VIEW, "flushContentCapture for " + + getClass().getSimpleName()); + } + final ContentCaptureManager ccm = mAttachInfo.mContentCaptureManager; if (ccm == null) { Log.w(TAG, "No ContentCapture on AttachInfo"); diff --git a/core/java/android/view/contentcapture/ContentCaptureManager.java b/core/java/android/view/contentcapture/ContentCaptureManager.java index 970baf2ce264..5a058ff3de99 100644 --- a/core/java/android/view/contentcapture/ContentCaptureManager.java +++ b/core/java/android/view/contentcapture/ContentCaptureManager.java @@ -794,7 +794,9 @@ public final class ContentCaptureManager { (params.flags & WindowManager.LayoutParams.FLAG_SECURE) != 0; MainContentCaptureSession mainSession; + boolean alreadyDisabledByApp; synchronized (mLock) { + alreadyDisabledByApp = (mFlags & ContentCaptureContext.FLAG_DISABLED_BY_APP) != 0; if (flagSecureEnabled) { mFlags |= ContentCaptureContext.FLAG_DISABLED_BY_FLAG_SECURE; } else { @@ -802,7 +804,9 @@ public final class ContentCaptureManager { } mainSession = mMainSession; } - if (mainSession != null) { + + // Prevent overriding the status of disabling by app + if (mainSession != null && !alreadyDisabledByApp) { mainSession.setDisabled(flagSecureEnabled); } } diff --git a/core/java/android/view/contentcapture/MainContentCaptureSession.java b/core/java/android/view/contentcapture/MainContentCaptureSession.java index b44d6a496058..d9b0f8035a6d 100644 --- a/core/java/android/view/contentcapture/MainContentCaptureSession.java +++ b/core/java/android/view/contentcapture/MainContentCaptureSession.java @@ -44,6 +44,7 @@ import android.os.Handler; import android.os.IBinder; import android.os.IBinder.DeathRecipient; import android.os.RemoteException; +import android.os.Trace; import android.text.Selection; import android.text.Spannable; import android.text.TextUtils; @@ -373,12 +374,26 @@ public final class MainContentCaptureSession extends ContentCaptureSession { return; } + if (Trace.isTagEnabled(Trace.TRACE_TAG_VIEW)) { + if (eventType == TYPE_VIEW_TREE_APPEARING) { + Trace.asyncTraceBegin( + Trace.TRACE_TAG_VIEW, /* methodName= */ "sendEventAsync", /* cookie= */ 0); + } + } + if (isContentProtectionReceiverEnabled()) { sendContentProtectionEvent(event); } if (isContentCaptureReceiverEnabled()) { sendContentCaptureEvent(event, forceFlush); } + + if (Trace.isTagEnabled(Trace.TRACE_TAG_VIEW)) { + if (eventType == TYPE_VIEW_TREE_APPEARED) { + Trace.asyncTraceEnd( + Trace.TRACE_TAG_VIEW, /* methodName= */ "sendEventAsync", /* cookie= */ 0); + } + } } @UiThread diff --git a/core/java/android/view/contentprotection/flags/content_protection_flags.aconfig b/core/java/android/view/contentprotection/flags/content_protection_flags.aconfig index f6ee061fdd89..f3dc33cd2cc9 100644 --- a/core/java/android/view/contentprotection/flags/content_protection_flags.aconfig +++ b/core/java/android/view/contentprotection/flags/content_protection_flags.aconfig @@ -20,3 +20,10 @@ flag { description: "If true, content protection setting ui is displayed in Settings > Privacy & Security > More security & privacy." bug: "305792348" } + +flag { + name: "create_accessibility_overlay_app_op_enabled" + namespace: "content_protection" + description: "If true, an appop is logged on creation of accessibility overlays." + bug: "289081465" +} diff --git a/core/java/android/widget/RemoteViews.java b/core/java/android/widget/RemoteViews.java index 30788014ff92..403b403be961 100644 --- a/core/java/android/widget/RemoteViews.java +++ b/core/java/android/widget/RemoteViews.java @@ -85,6 +85,7 @@ import android.util.Log; import android.util.LongArray; import android.util.Pair; import android.util.SizeF; +import android.util.SparseArray; import android.util.SparseIntArray; import android.util.TypedValue; import android.util.TypedValue.ComplexDimensionUnit; @@ -367,6 +368,11 @@ public class RemoteViews implements Parcelable, Filter { @UnsupportedAppUsage private BitmapCache mBitmapCache = new BitmapCache(); + /** + * Maps Intent ID to RemoteCollectionItems to avoid duplicate items + */ + private RemoteCollectionCache mCollectionCache = new RemoteCollectionCache(); + /** Cache of ApplicationInfos used by collection items. */ private ApplicationInfoCache mApplicationInfoCache = new ApplicationInfoCache(); @@ -784,9 +790,12 @@ public class RemoteViews implements Parcelable, Filter { if (action instanceof SetRemoteCollectionItemListAdapterAction itemsAction && itemsAction.mViewId == viewId && itemsAction.mServiceIntent != null) { - mActions.set(i, - new SetRemoteCollectionItemListAdapterAction(itemsAction.mViewId, - itemsAction.mServiceIntent)); + SetRemoteCollectionItemListAdapterAction newCollectionAction = + new SetRemoteCollectionItemListAdapterAction( + itemsAction.mViewId, itemsAction.mServiceIntent); + newCollectionAction.mIntentId = itemsAction.mIntentId; + newCollectionAction.mIsReplacedIntoAction = true; + mActions.set(i, newCollectionAction); isActionReplaced = true; } else if (action instanceof SetRemoteViewsAdapterIntent intentAction && intentAction.mViewId == viewId) { @@ -1048,6 +1057,8 @@ public class RemoteViews implements Parcelable, Filter { @NonNull private CompletableFuture<RemoteCollectionItems> mItemsFuture; final Intent mServiceIntent; + int mIntentId = -1; + boolean mIsReplacedIntoAction = false; SetRemoteCollectionItemListAdapterAction(@IdRes int id, @NonNull RemoteCollectionItems items) { @@ -1108,38 +1119,36 @@ public class RemoteViews implements Parcelable, Filter { SetRemoteCollectionItemListAdapterAction(Parcel parcel) { mViewId = parcel.readInt(); - mItemsFuture = CompletableFuture.completedFuture( - new RemoteCollectionItems(parcel, getHierarchyRootData())); + mIntentId = parcel.readInt(); + mItemsFuture = CompletableFuture.completedFuture(mIntentId != -1 + ? null + : new RemoteCollectionItems(parcel, getHierarchyRootData())); mServiceIntent = parcel.readTypedObject(Intent.CREATOR); } @Override public void setHierarchyRootData(HierarchyRootData rootData) { - mItemsFuture = mItemsFuture - .thenApply(rc -> { - rc.setHierarchyRootData(rootData); - return rc; - }); - } - - private static RemoteCollectionItems getCollectionItemsFromFuture( - CompletableFuture<RemoteCollectionItems> itemsFuture) { - RemoteCollectionItems items; - try { - items = itemsFuture.get(); - } catch (Exception e) { - Log.e(LOG_TAG, "Error getting collection items from future", e); - items = new RemoteCollectionItems.Builder().build(); + if (mIntentId == -1) { + mItemsFuture = mItemsFuture + .thenApply(rc -> { + rc.setHierarchyRootData(rootData); + return rc; + }); + return; } - return items; + // Set the root data for items in the cache instead + mCollectionCache.setHierarchyDataForId(mIntentId, rootData); } @Override public void writeToParcel(Parcel dest, int flags) { dest.writeInt(mViewId); - RemoteCollectionItems items = getCollectionItemsFromFuture(mItemsFuture); - items.writeToParcel(dest, flags, /* attached= */ true); + dest.writeInt(mIntentId); + if (mIntentId == -1) { + RemoteCollectionItems items = getCollectionItemsFromFuture(mItemsFuture); + items.writeToParcel(dest, flags, /* attached= */ true); + } dest.writeTypedObject(mServiceIntent, flags); } @@ -1149,7 +1158,9 @@ public class RemoteViews implements Parcelable, Filter { View target = root.findViewById(mViewId); if (target == null) return; - RemoteCollectionItems items = getCollectionItemsFromFuture(mItemsFuture); + RemoteCollectionItems items = mIntentId == -1 + ? getCollectionItemsFromFuture(mItemsFuture) + : mCollectionCache.getItemsForId(mIntentId); // Ensure that we are applying to an AppWidget root if (!(rootParent instanceof AppWidgetHostView)) { @@ -1210,6 +1221,153 @@ public class RemoteViews implements Parcelable, Filter { } } + private static RemoteCollectionItems getCollectionItemsFromFuture( + CompletableFuture<RemoteCollectionItems> itemsFuture) { + RemoteCollectionItems items; + try { + items = itemsFuture.get(); + } catch (Exception e) { + Log.e(LOG_TAG, "Error getting collection items from future", e); + items = new RemoteCollectionItems.Builder().build(); + } + + return items; + } + + /** + * @hide + */ + public void collectAllIntents() { + mCollectionCache.collectAllIntentsNoComplete(this); + } + + private class RemoteCollectionCache { + private SparseArray<String> mIdToUriMapping = new SparseArray<>(); + private HashMap<String, RemoteCollectionItems> mUriToCollectionMapping = new HashMap<>(); + + // We don't put this into the parcel + private HashMap<String, CompletableFuture<RemoteCollectionItems>> mTempUriToFutureMapping = + new HashMap<>(); + + RemoteCollectionCache() { } + + RemoteCollectionCache(RemoteCollectionCache src) { + boolean isWaitingCache = src.mTempUriToFutureMapping.size() != 0; + for (int i = 0; i < src.mIdToUriMapping.size(); i++) { + String uri = src.mIdToUriMapping.valueAt(i); + mIdToUriMapping.put(src.mIdToUriMapping.keyAt(i), uri); + if (isWaitingCache) { + mTempUriToFutureMapping.put(uri, src.mTempUriToFutureMapping.get(uri)); + } else { + mUriToCollectionMapping.put(uri, src.mUriToCollectionMapping.get(uri)); + } + } + } + + RemoteCollectionCache(Parcel in) { + int cacheSize = in.readInt(); + HierarchyRootData currentRootData = new HierarchyRootData(mBitmapCache, + this, + mApplicationInfoCache, + mClassCookies); + for (int i = 0; i < cacheSize; i++) { + int intentId = in.readInt(); + String intentUri = in.readString8(); + RemoteCollectionItems items = new RemoteCollectionItems(in, currentRootData); + mIdToUriMapping.put(intentId, intentUri); + mUriToCollectionMapping.put(intentUri, items); + } + } + + void setHierarchyDataForId(int intentId, HierarchyRootData data) { + String uri = mIdToUriMapping.get(intentId); + if (mTempUriToFutureMapping.get(uri) != null) { + CompletableFuture<RemoteCollectionItems> itemsFuture = + mTempUriToFutureMapping.get(uri); + mTempUriToFutureMapping.put(uri, itemsFuture.thenApply(rc -> { + rc.setHierarchyRootData(data); + return rc; + })); + + return; + } + + RemoteCollectionItems items = mUriToCollectionMapping.get(uri); + items.setHierarchyRootData(data); + } + + RemoteCollectionItems getItemsForId(int intentId) { + String uri = mIdToUriMapping.get(intentId); + return mUriToCollectionMapping.get(uri); + } + + void collectAllIntentsNoComplete(@NonNull RemoteViews inViews) { + if (inViews.hasSizedRemoteViews()) { + for (RemoteViews remoteViews : inViews.mSizedRemoteViews) { + remoteViews.collectAllIntents(); + } + } else if (inViews.hasLandscapeAndPortraitLayouts()) { + inViews.mLandscape.collectAllIntents(); + inViews.mPortrait.collectAllIntents(); + } else if (inViews.mActions != null) { + for (Action action : inViews.mActions) { + if (action instanceof SetRemoteCollectionItemListAdapterAction rca) { + // Deal with the case where the intent is replaced into the action list + if (rca.mIntentId != -1 && !rca.mIsReplacedIntoAction) { + continue; + } + + if (rca.mIntentId != -1 && rca.mIsReplacedIntoAction) { + String uri = mIdToUriMapping.get(rca.mIntentId); + mTempUriToFutureMapping.put(uri, rca.mItemsFuture); + rca.mItemsFuture = CompletableFuture.completedFuture(null); + continue; + } + + // Differentiate between the normal collection actions and the ones with + // intents. + if (rca.mServiceIntent != null) { + String uri = rca.mServiceIntent.toUri(0); + int index = mIdToUriMapping.indexOfValue(uri); + if (index == -1) { + int newIntentId = mIdToUriMapping.size(); + rca.mIntentId = newIntentId; + mIdToUriMapping.put(newIntentId, uri); + // mUriToIntentMapping.put(uri, mServiceIntent); + mTempUriToFutureMapping.put(uri, rca.mItemsFuture); + } else { + rca.mIntentId = mIdToUriMapping.keyAt(index); + } + rca.mItemsFuture = CompletableFuture.completedFuture(null); + } else { + RemoteCollectionItems items = getCollectionItemsFromFuture( + rca.mItemsFuture); + for (RemoteViews views : items.mViews) { + views.collectAllIntents(); + } + } + } else if (action instanceof ViewGroupActionAdd vgaa + && vgaa.mNestedViews != null) { + vgaa.mNestedViews.collectAllIntents(); + } + } + } + } + + public void writeToParcel(Parcel out, int flags) { + out.writeInt(mIdToUriMapping.size()); + for (int i = 0; i < mIdToUriMapping.size(); i++) { + out.writeInt(mIdToUriMapping.keyAt(i)); + String intentUri = mIdToUriMapping.valueAt(i); + out.writeString8(intentUri); + RemoteCollectionItems items = mTempUriToFutureMapping.get(intentUri) != null + ? getCollectionItemsFromFuture(mTempUriToFutureMapping.get(intentUri)) + : mUriToCollectionMapping.get(intentUri); + items.writeToParcel(out, flags, true); + } + } + } + private class SetRemoteViewsAdapterIntent extends Action { Intent mIntent; boolean mIsAsync = false; @@ -3850,9 +4008,12 @@ public class RemoteViews implements Parcelable, Filter { private void initializeFrom(@NonNull RemoteViews src, @Nullable RemoteViews hierarchyRoot) { if (hierarchyRoot == null) { mBitmapCache = src.mBitmapCache; + // We need to create a new instance because we don't reconstruct collection cache + mCollectionCache = new RemoteCollectionCache(src.mCollectionCache); mApplicationInfoCache = src.mApplicationInfoCache; } else { mBitmapCache = hierarchyRoot.mBitmapCache; + mCollectionCache = hierarchyRoot.mCollectionCache; mApplicationInfoCache = hierarchyRoot.mApplicationInfoCache; } if (hierarchyRoot == null || src.mIsRoot) { @@ -3926,6 +4087,7 @@ public class RemoteViews implements Parcelable, Filter { mBitmapCache = new BitmapCache(parcel); // Store the class cookies such that they are available when we clone this RemoteView. mClassCookies = parcel.copyClassCookies(); + mCollectionCache = new RemoteCollectionCache(parcel); } else { configureAsChild(rootData); } @@ -4087,6 +4249,7 @@ public class RemoteViews implements Parcelable, Filter { private void configureAsChild(@NonNull HierarchyRootData rootData) { mIsRoot = false; mBitmapCache = rootData.mBitmapCache; + mCollectionCache = rootData.mRemoteCollectionCache; mApplicationInfoCache = rootData.mApplicationInfoCache; mClassCookies = rootData.mClassCookies; configureDescendantsAsChildren(); @@ -6357,6 +6520,7 @@ public class RemoteViews implements Parcelable, Filter { // is shared by all children. if (mIsRoot) { mBitmapCache.writeBitmapsToParcel(dest, flags); + mCollectionCache.writeToParcel(dest, flags); } mApplication.writeToParcel(dest, flags); if (mIsRoot || mIdealSize == null) { @@ -6373,6 +6537,7 @@ public class RemoteViews implements Parcelable, Filter { dest.writeInt(MODE_HAS_SIZED_REMOTEVIEWS); if (mIsRoot) { mBitmapCache.writeBitmapsToParcel(dest, flags); + mCollectionCache.writeToParcel(dest, flags); } dest.writeInt(mSizedRemoteViews.size()); for (RemoteViews view : mSizedRemoteViews) { @@ -6384,6 +6549,7 @@ public class RemoteViews implements Parcelable, Filter { // is shared by all children. if (mIsRoot) { mBitmapCache.writeBitmapsToParcel(dest, flags); + mCollectionCache.writeToParcel(dest, flags); } mLandscape.writeToParcel(dest, flags); // Both RemoteViews already share the same package and user @@ -7262,19 +7428,23 @@ public class RemoteViews implements Parcelable, Filter { } private HierarchyRootData getHierarchyRootData() { - return new HierarchyRootData(mBitmapCache, mApplicationInfoCache, mClassCookies); + return new HierarchyRootData(mBitmapCache, mCollectionCache, + mApplicationInfoCache, mClassCookies); } private static final class HierarchyRootData { final BitmapCache mBitmapCache; + final RemoteCollectionCache mRemoteCollectionCache; final ApplicationInfoCache mApplicationInfoCache; final Map<Class, Object> mClassCookies; HierarchyRootData( BitmapCache bitmapCache, + RemoteCollectionCache remoteCollectionCache, ApplicationInfoCache applicationInfoCache, Map<Class, Object> classCookies) { mBitmapCache = bitmapCache; + mRemoteCollectionCache = remoteCollectionCache; mApplicationInfoCache = applicationInfoCache; mClassCookies = classCookies; } diff --git a/core/java/android/window/ITaskFragmentOrganizerController.aidl b/core/java/android/window/ITaskFragmentOrganizerController.aidl index 7b7e34172fed..4706dfd1a76c 100644 --- a/core/java/android/window/ITaskFragmentOrganizerController.aidl +++ b/core/java/android/window/ITaskFragmentOrganizerController.aidl @@ -19,6 +19,7 @@ package android.window; import android.os.IBinder; import android.view.RemoteAnimationDefinition; import android.window.ITaskFragmentOrganizer; +import android.window.RemoteTransition; import android.window.WindowContainerTransaction; /** @hide */ @@ -65,7 +66,10 @@ interface ITaskFragmentOrganizerController { /** * Requests the server to apply the given {@link WindowContainerTransaction}. + * + * {@link RemoteTransition} can only be used by a system organizer and + * {@code shouldApplyIndependently} must be {@code true}. See {@link registerOrganizer}. */ void applyTransaction(in WindowContainerTransaction wct, int transitionType, - boolean shouldApplyIndependently); + boolean shouldApplyIndependently, in RemoteTransition remoteTransition); } diff --git a/core/java/android/window/TaskFragmentOrganizer.java b/core/java/android/window/TaskFragmentOrganizer.java index a6c9cecb508f..5c113f865d45 100644 --- a/core/java/android/window/TaskFragmentOrganizer.java +++ b/core/java/android/window/TaskFragmentOrganizer.java @@ -275,7 +275,31 @@ public class TaskFragmentOrganizer extends WindowOrganizer { } wct.setTaskFragmentOrganizer(mInterface); try { - getController().applyTransaction(wct, transitionType, shouldApplyIndependently); + getController().applyTransaction( + wct, transitionType, shouldApplyIndependently, null /* remoteTransition */); + } catch (RemoteException e) { + throw e.rethrowFromSystemServer(); + } + } + + /** + * Applies a transaction with a {@link RemoteTransition}. Only a system organizer is allowed to + * use {@link RemoteTransition}. See {@link TaskFragmentOrganizer#registerOrganizer(boolean)}. + * + * @hide + */ + @FlaggedApi(Flags.FLAG_TASK_FRAGMENT_SYSTEM_ORGANIZER_FLAG) + public void applySystemTransaction(@NonNull WindowContainerTransaction wct, + @TaskFragmentTransitionType int transitionType, + @Nullable RemoteTransition remoteTransition) { + if (wct.isEmpty()) { + return; + } + wct.setTaskFragmentOrganizer(mInterface); + try { + getController().applyTransaction( + wct, transitionType, remoteTransition != null /* shouldApplyIndependently */, + remoteTransition); } catch (RemoteException e) { throw e.rethrowFromSystemServer(); } diff --git a/core/java/android/window/flags/OWNERS b/core/java/android/window/flags/OWNERS new file mode 100644 index 000000000000..fa81ee3905c3 --- /dev/null +++ b/core/java/android/window/flags/OWNERS @@ -0,0 +1 @@ +per-file responsible_apis.aconfig = file:/BAL_OWNERS
\ No newline at end of file diff --git a/core/java/android/window/flags/wallpaper_manager.aconfig b/core/java/android/window/flags/wallpaper_manager.aconfig new file mode 100644 index 000000000000..09be0cfc5fb0 --- /dev/null +++ b/core/java/android/window/flags/wallpaper_manager.aconfig @@ -0,0 +1,8 @@ +package: "com.android.window.flags" + +flag { + name: "always_update_wallpaper_permission" + namespace: "wear_frameworks" + description: "Allow out of focus process to update wallpaper complications" + bug: "271132915" +}
\ No newline at end of file diff --git a/core/java/com/android/internal/config/sysui/SystemUiSystemPropertiesFlags.java b/core/java/com/android/internal/config/sysui/SystemUiSystemPropertiesFlags.java index 77e150239803..df6c1538fc6d 100644 --- a/core/java/com/android/internal/config/sysui/SystemUiSystemPropertiesFlags.java +++ b/core/java/com/android/internal/config/sysui/SystemUiSystemPropertiesFlags.java @@ -106,6 +106,10 @@ public class SystemUiSystemPropertiesFlags { /** b/301242692: Visit extra URIs used in notifications to prevent security issues. */ public static final Flag VISIT_RISKY_URIS = devFlag( "persist.sysui.notification.visit_risky_uris"); + + /** b/303716154: For debugging only: use short bitmap duration. */ + public static final Flag DEBUG_SHORT_BITMAP_DURATION = devFlag( + "persist.sysui.notification.debug_short_bitmap_duration"); } //// == End of flags. Everything below this line is the implementation. == //// diff --git a/core/java/com/android/internal/os/Zygote.java b/core/java/com/android/internal/os/Zygote.java index 1c5f4f0f1369..cab84bb01f70 100644 --- a/core/java/com/android/internal/os/Zygote.java +++ b/core/java/com/android/internal/os/Zygote.java @@ -236,6 +236,9 @@ public final class Zygote { /** Bind mount app storage dirs to lower fs not via fuse */ public static final String BIND_MOUNT_APP_DATA_DIRS = "--bind-mount-data-dirs"; + /** Bind the system properties to an alternate set, for appcompat reasons */ + public static final String BIND_MOUNT_SYSPROP_OVERRIDES = "--bind-mount-sysprop-overrides"; + /** * An extraArg passed when a zygote process is forking a child-zygote, specifying a name * in the abstract socket namespace. This socket name is what the new child zygote @@ -353,6 +356,8 @@ public final class Zygote { * @param allowlistedDataInfoList Like pkgDataInfoList, but it's for allowlisted apps. * @param bindMountAppDataDirs True if the zygote needs to mount data dirs. * @param bindMountAppStorageDirs True if the zygote needs to mount storage dirs. + * @param bindMountSyspropOverrides True if the zygote needs to mount the override system + * properties * * @return 0 if this is the child, pid of the child * if this is the parent, or -1 on error. @@ -361,14 +366,15 @@ public final class Zygote { int[][] rlimits, int mountExternal, String seInfo, String niceName, int[] fdsToClose, int[] fdsToIgnore, boolean startChildZygote, String instructionSet, String appDataDir, boolean isTopApp, String[] pkgDataInfoList, String[] allowlistedDataInfoList, - boolean bindMountAppDataDirs, boolean bindMountAppStorageDirs) { + boolean bindMountAppDataDirs, boolean bindMountAppStorageDirs, + boolean bindMountSyspropOverrides) { ZygoteHooks.preFork(); int pid = nativeForkAndSpecialize( uid, gid, gids, runtimeFlags, rlimits, mountExternal, seInfo, niceName, fdsToClose, fdsToIgnore, startChildZygote, instructionSet, appDataDir, isTopApp, pkgDataInfoList, allowlistedDataInfoList, bindMountAppDataDirs, - bindMountAppStorageDirs); + bindMountAppStorageDirs, bindMountSyspropOverrides); if (pid == 0) { // Note that this event ends at the end of handleChildProc, Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, "PostFork"); @@ -391,7 +397,7 @@ public final class Zygote { int[] fdsToClose, int[] fdsToIgnore, boolean startChildZygote, String instructionSet, String appDataDir, boolean isTopApp, String[] pkgDataInfoList, String[] allowlistedDataInfoList, boolean bindMountAppDataDirs, - boolean bindMountAppStorageDirs); + boolean bindMountAppStorageDirs, boolean bindMountSyspropOverrides); /** * Specialize an unspecialized app process. The current VM must have been started @@ -421,16 +427,19 @@ public final class Zygote { * @param allowlistedDataInfoList Like pkgDataInfoList, but it's for allowlisted apps. * @param bindMountAppDataDirs True if the zygote needs to mount data dirs. * @param bindMountAppStorageDirs True if the zygote needs to mount storage dirs. + * @param bindMountSyspropOverrides True if the zygote needs to mount the override system + * properties */ private static void specializeAppProcess(int uid, int gid, int[] gids, int runtimeFlags, int[][] rlimits, int mountExternal, String seInfo, String niceName, boolean startChildZygote, String instructionSet, String appDataDir, boolean isTopApp, String[] pkgDataInfoList, String[] allowlistedDataInfoList, - boolean bindMountAppDataDirs, boolean bindMountAppStorageDirs) { + boolean bindMountAppDataDirs, boolean bindMountAppStorageDirs, + boolean bindMountSyspropOverrides) { nativeSpecializeAppProcess(uid, gid, gids, runtimeFlags, rlimits, mountExternal, seInfo, niceName, startChildZygote, instructionSet, appDataDir, isTopApp, pkgDataInfoList, allowlistedDataInfoList, - bindMountAppDataDirs, bindMountAppStorageDirs); + bindMountAppDataDirs, bindMountAppStorageDirs, bindMountSyspropOverrides); // Note that this event ends at the end of handleChildProc. Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, "PostFork"); @@ -455,7 +464,8 @@ public final class Zygote { int runtimeFlags, int[][] rlimits, int mountExternal, String seInfo, String niceName, boolean startChildZygote, String instructionSet, String appDataDir, boolean isTopApp, String[] pkgDataInfoList, String[] allowlistedDataInfoList, - boolean bindMountAppDataDirs, boolean bindMountAppStorageDirs); + boolean bindMountAppDataDirs, boolean bindMountAppStorageDirs, + boolean bindMountSyspropOverrides); /** * Called to do any initialization before starting an application. @@ -866,7 +876,8 @@ public final class Zygote { args.mSeInfo, args.mNiceName, args.mStartChildZygote, args.mInstructionSet, args.mAppDataDir, args.mIsTopApp, args.mPkgDataInfoList, args.mAllowlistedDataInfoList, - args.mBindMountAppDataDirs, args.mBindMountAppStorageDirs); + args.mBindMountAppDataDirs, args.mBindMountAppStorageDirs, + args.mBindMountSyspropOverrides); // While `specializeAppProcess` sets the thread name on the process's main thread, this // is distinct from the app process name which appears in stack traces, as the latter is diff --git a/core/java/com/android/internal/os/ZygoteArguments.java b/core/java/com/android/internal/os/ZygoteArguments.java index ef8398294c5b..86b9a59fef72 100644 --- a/core/java/com/android/internal/os/ZygoteArguments.java +++ b/core/java/com/android/internal/os/ZygoteArguments.java @@ -243,6 +243,11 @@ class ZygoteArguments { boolean mBindMountAppDataDirs; /** + * @see Zygote#BIND_MOUNT_SYSPROP_OVERRIDES + */ + boolean mBindMountSyspropOverrides; + + /** * Constructs instance and parses args * * @param args zygote command-line args as ZygoteCommandBuffer, positioned after argument count. @@ -481,6 +486,8 @@ class ZygoteArguments { mBindMountAppStorageDirs = true; } else if (arg.equals(Zygote.BIND_MOUNT_APP_DATA_DIRS)) { mBindMountAppDataDirs = true; + } else if (arg.equals(Zygote.BIND_MOUNT_SYSPROP_OVERRIDES)) { + mBindMountSyspropOverrides = true; } else { unprocessedArg = arg; break; diff --git a/core/java/com/android/internal/os/ZygoteConnection.java b/core/java/com/android/internal/os/ZygoteConnection.java index 5fe086da8c6a..cbe070048811 100644 --- a/core/java/com/android/internal/os/ZygoteConnection.java +++ b/core/java/com/android/internal/os/ZygoteConnection.java @@ -257,7 +257,8 @@ class ZygoteConnection { parsedArgs.mInstructionSet, parsedArgs.mAppDataDir, parsedArgs.mIsTopApp, parsedArgs.mPkgDataInfoList, parsedArgs.mAllowlistedDataInfoList, parsedArgs.mBindMountAppDataDirs, - parsedArgs.mBindMountAppStorageDirs); + parsedArgs.mBindMountAppStorageDirs, + parsedArgs.mBindMountSyspropOverrides); try { if (pid == 0) { diff --git a/core/jni/com_android_internal_os_Zygote.cpp b/core/jni/com_android_internal_os_Zygote.cpp index b12e14782361..9c1bea779201 100644 --- a/core/jni/com_android_internal_os_Zygote.cpp +++ b/core/jni/com_android_internal_os_Zygote.cpp @@ -59,6 +59,8 @@ #include <sys/resource.h> #include <sys/socket.h> #include <sys/stat.h> +#define _REALLY_INCLUDE_SYS__SYSTEM_PROPERTIES_H_ +#include <sys/_system_properties.h> #include <sys/time.h> #include <sys/types.h> #include <sys/un.h> @@ -1691,6 +1693,131 @@ static void WaitUntilDirReady(const std::string& target, fail_fn_t fail_fn) { fail_fn(CREATE_ERROR("Error dir is not ready %s: %s", dir_path, strerror(errno))); } +// All public String android.os.Build constants, and the system properties they're pulled from +std::pair<const char*, const char*> build_constants[] = { + std::pair("ID", "ro.build.id"), + std::pair("DISPLAY", "ro.build.display.id"), + std::pair("PRODUCT", "ro.product.name"), + std::pair("DEVICE", "ro.product.device"), + std::pair("BOARD", "ro.product.board"), + std::pair("MANUFACTURER", "ro.product.manufacturer"), + std::pair("BRAND", "ro.product.brand"), + std::pair("MODEL", "ro.product.model"), + std::pair("BOOTLOADER", "ro.bootloader"), + std::pair("HARDWARE", "ro.hardware"), + std::pair("SKU", "ro.boot.hardware.sku"), + std::pair("ODM_SKU", "ro.boot.product.hardware.sku"), + std::pair("TAGS", "ro.build.tags"), + std::pair("TYPE", "ro.build.type"), + std::pair("USER", "ro.build.user"), + std::pair("HOST", "ro.build.host"), +}; + +// All public String Build.VERSION constants, and the system properties they're pulled from +std::pair<const char*, const char*> build_version_constants[] = { + std::pair("INCREMENTAL", "ro.build.version.incremental"), + std::pair("RELEASE", "ro.build.version.release"), + std::pair("RELEASE_OR_CODENAME", "ro.build.version.release_or_codename"), + std::pair("RELEASE_OR_PREVIEW_DISPLAY", "ro.build.version.release_or_preview_display"), + std::pair("BASE_OS", "ro.build.version.base_os"), + std::pair("SECURITY_PATCH", "ro.build.version.security_patch"), + std::pair("SDK", "ro.build.version.sdk"), + std::pair("PREVIEW_SDK_FINGERPRINT", "ro.build.version.preview_sdk_fingerprint"), + std::pair("CODENAME", "ro.build.version.codename"), +}; + +static void ReloadBuildJavaConstant(JNIEnv* env, jclass build_class, const char* field_name, + const char* field_signature, const char* sysprop_name) { + const prop_info* prop_info = __system_property_find(sysprop_name); + std::string new_value; + __system_property_read_callback( + prop_info, + [](void* cookie, const char* name, const char* value, unsigned serial) { + auto new_value = reinterpret_cast<std::string*>(cookie); + *new_value = value; + }, + &new_value); + jfieldID fieldId = env->GetStaticFieldID(build_class, field_name, field_signature); + if (strcmp(field_signature, "I") == 0) { + env->SetStaticIntField(build_class, fieldId, jint(strtol(new_value.c_str(), nullptr, 0))); + } else if (strcmp(field_signature, "Ljava/lang/String;") == 0) { + jstring string_val = env->NewStringUTF(new_value.c_str()); + env->SetStaticObjectField(build_class, fieldId, string_val); + } else if (strcmp(field_signature, "[Ljava/lang/String;") == 0) { + auto stream = std::stringstream(new_value); + std::vector<std::string> items; + std::string segment; + while (std::getline(stream, segment, ',')) { + items.push_back(segment); + } + jclass string_class = env->FindClass("java/lang/String"); + jobjectArray string_arr = env->NewObjectArray(items.size(), string_class, nullptr); + for (size_t i = 0; i < items.size(); i++) { + jstring string_arr_val = env->NewStringUTF(items.at(i).c_str()); + env->SetObjectArrayElement(string_arr, i, string_arr_val); + } + env->SetStaticObjectField(build_class, fieldId, string_arr); + } else if (strcmp(field_signature, "J") == 0) { + env->SetStaticLongField(build_class, fieldId, jlong(strtoll(new_value.c_str(), nullptr, 0))); + } +} + +static void ReloadBuildJavaConstants(JNIEnv* env) { + jclass build_cls = env->FindClass("android/os/Build"); + size_t arr_size = sizeof(build_constants) / sizeof(build_constants[0]); + for (int i = 0; i < arr_size; i++) { + const char* field_name = build_constants[i].first; + const char* sysprop_name = build_constants[i].second; + ReloadBuildJavaConstant(env, build_cls, field_name, "Ljava/lang/String;", sysprop_name); + } + jclass build_version_cls = env->FindClass("android/os/Build$VERSION"); + arr_size = sizeof(build_version_constants) / sizeof(build_version_constants[0]); + for (int i = 0; i < arr_size; i++) { + const char* field_name = build_version_constants[i].first; + const char* sysprop_name = build_version_constants[i].second; + ReloadBuildJavaConstant(env, build_version_cls, field_name, "Ljava/lang/String;", sysprop_name); + } + + // Reload the public String[] constants + ReloadBuildJavaConstant(env, build_cls, "SUPPORTED_ABIS", "[Ljava/lang/String;", + "ro.product.cpu.abilist"); + ReloadBuildJavaConstant(env, build_cls, "SUPPORTED_32_BIT_ABIS", "[Ljava/lang/String;", + "ro.product.cpu.abilist32"); + ReloadBuildJavaConstant(env, build_cls, "SUPPORTED_64_BIT_ABIS", "[Ljava/lang/String;", + "ro.product.cpu.abilist64"); + ReloadBuildJavaConstant(env, build_version_cls, "ALL_CODENAMES", "[Ljava/lang/String;", + "ro.build.version.all_codenames"); + + // Reload the public int/long constants + ReloadBuildJavaConstant(env, build_cls, "TIME", "J", "ro.build.date.utc"); + ReloadBuildJavaConstant(env, build_version_cls, "SDK_INT", "I", "ro.build.version.sdk"); + ReloadBuildJavaConstant(env, build_version_cls, "PREVIEW_SDK_INT", "I", + "ro.build.version.preview_sdk"); + + // Re-derive the fingerprint + jmethodID derive_fingerprint = + env->GetStaticMethodID(build_cls, "deriveFingerprint", "()Ljava/lang/String;"); + auto new_fingerprint = (jstring)(env->CallStaticObjectMethod(build_cls, derive_fingerprint)); + jfieldID fieldId = env->GetStaticFieldID(build_cls, "FINGERPRINT", "Ljava/lang/String;"); + env->SetStaticObjectField(build_cls, fieldId, new_fingerprint); +} + +static void BindMountSyspropOverride(fail_fn_t fail_fn, JNIEnv* env) { + std::string source = "/dev/__properties__/appcompat_override"; + std::string target = "/dev/__properties__"; + if (access(source.c_str(), F_OK) != 0) { + fail_fn(CREATE_ERROR("Error accessing %s: %s", source.c_str(), strerror(errno))); + } + if (access(target.c_str(), F_OK) != 0) { + fail_fn(CREATE_ERROR("Error accessing %s: %s", target.c_str(), strerror(errno))); + } + BindMount(source, target, fail_fn); + // Reload the system properties file, to ensure new values are read into memory + __system_properties_zygote_reload(); + // android.os.Build constants are pulled from system properties, so they must be reloaded, too + ReloadBuildJavaConstants(env); +} + static void BindMountStorageToLowerFs(const userid_t user_id, const uid_t uid, const char* dir_name, const char* package, fail_fn_t fail_fn) { bool hasSdcardFs = IsSdcardfsUsed(); @@ -1754,7 +1881,7 @@ static void SpecializeCommon(JNIEnv* env, uid_t uid, gid_t gid, jintArray gids, jstring managed_instruction_set, jstring managed_app_data_dir, bool is_top_app, jobjectArray pkg_data_info_list, jobjectArray allowlisted_data_info_list, bool mount_data_dirs, - bool mount_storage_dirs) { + bool mount_storage_dirs, bool mount_sysprop_overrides) { const char* process_name = is_system_server ? "system_server" : "zygote"; auto fail_fn = std::bind(ZygoteFailure, env, process_name, managed_nice_name, _1); auto extract_fn = std::bind(ExtractJString, env, process_name, managed_nice_name, _1); @@ -1807,6 +1934,10 @@ static void SpecializeCommon(JNIEnv* env, uid_t uid, gid_t gid, jintArray gids, fail_fn); } + if (mount_sysprop_overrides) { + BindMountSyspropOverride(fail_fn, env); + } + // If this zygote isn't root, it won't be able to create a process group, // since the directory is owned by root. if (!is_system_server && getuid() == 0) { @@ -2360,7 +2491,7 @@ static jint com_android_internal_os_Zygote_nativeForkAndSpecialize( jintArray managed_fds_to_close, jintArray managed_fds_to_ignore, jboolean is_child_zygote, jstring instruction_set, jstring app_data_dir, jboolean is_top_app, jobjectArray pkg_data_info_list, jobjectArray allowlisted_data_info_list, - jboolean mount_data_dirs, jboolean mount_storage_dirs) { + jboolean mount_data_dirs, jboolean mount_storage_dirs, jboolean mount_sysprop_overrides) { jlong capabilities = CalculateCapabilities(env, uid, gid, gids, is_child_zygote); if (UNLIKELY(managed_fds_to_close == nullptr)) { @@ -2403,7 +2534,7 @@ static jint com_android_internal_os_Zygote_nativeForkAndSpecialize( mount_external, se_info, nice_name, false, is_child_zygote == JNI_TRUE, instruction_set, app_data_dir, is_top_app == JNI_TRUE, pkg_data_info_list, allowlisted_data_info_list, mount_data_dirs == JNI_TRUE, - mount_storage_dirs == JNI_TRUE); + mount_storage_dirs == JNI_TRUE, mount_sysprop_overrides == JNI_TRUE); } return pid; } @@ -2439,7 +2570,7 @@ static jint com_android_internal_os_Zygote_nativeForkSystemServer( effective_capabilities, MOUNT_EXTERNAL_DEFAULT, nullptr, nullptr, true, false, nullptr, nullptr, /* is_top_app= */ false, /* pkg_data_info_list */ nullptr, - /* allowlisted_data_info_list */ nullptr, false, false); + /* allowlisted_data_info_list */ nullptr, false, false, false); } else if (pid > 0) { // The zygote process checks whether the child process has died or not. ALOGI("System server process %d has been created", pid); @@ -2591,14 +2722,14 @@ static void com_android_internal_os_Zygote_nativeSpecializeAppProcess( jboolean is_child_zygote, jstring instruction_set, jstring app_data_dir, jboolean is_top_app, jobjectArray pkg_data_info_list, jobjectArray allowlisted_data_info_list, jboolean mount_data_dirs, - jboolean mount_storage_dirs) { + jboolean mount_storage_dirs, jboolean mount_sysprop_overrides) { jlong capabilities = CalculateCapabilities(env, uid, gid, gids, is_child_zygote); SpecializeCommon(env, uid, gid, gids, runtime_flags, rlimits, capabilities, capabilities, mount_external, se_info, nice_name, false, is_child_zygote == JNI_TRUE, instruction_set, app_data_dir, is_top_app == JNI_TRUE, pkg_data_info_list, allowlisted_data_info_list, mount_data_dirs == JNI_TRUE, - mount_storage_dirs == JNI_TRUE); + mount_storage_dirs == JNI_TRUE, mount_sysprop_overrides == JNI_TRUE); } /** @@ -2876,7 +3007,7 @@ static void com_android_internal_os_Zygote_nativeAllowFilesOpenedByPreload(JNIEn static const JNINativeMethod gMethods[] = { {"nativeForkAndSpecialize", "(II[II[[IILjava/lang/String;Ljava/lang/String;[I[IZLjava/lang/String;Ljava/lang/" - "String;Z[Ljava/lang/String;[Ljava/lang/String;ZZ)I", + "String;Z[Ljava/lang/String;[Ljava/lang/String;ZZZ)I", (void*)com_android_internal_os_Zygote_nativeForkAndSpecialize}, {"nativeForkSystemServer", "(II[II[[IJJ)I", (void*)com_android_internal_os_Zygote_nativeForkSystemServer}, @@ -2892,7 +3023,7 @@ static const JNINativeMethod gMethods[] = { (void*)com_android_internal_os_Zygote_nativeAddUsapTableEntry}, {"nativeSpecializeAppProcess", "(II[II[[IILjava/lang/String;Ljava/lang/String;ZLjava/lang/String;Ljava/lang/" - "String;Z[Ljava/lang/String;[Ljava/lang/String;ZZ)V", + "String;Z[Ljava/lang/String;[Ljava/lang/String;ZZZ)V", (void*)com_android_internal_os_Zygote_nativeSpecializeAppProcess}, {"nativeInitNativeState", "(Z)V", (void*)com_android_internal_os_Zygote_nativeInitNativeState}, diff --git a/core/res/AndroidManifest.xml b/core/res/AndroidManifest.xml index 8c91be8b21c0..c75f99616f5b 100644 --- a/core/res/AndroidManifest.xml +++ b/core/res/AndroidManifest.xml @@ -4065,6 +4065,7 @@ <!-- Allow apps to always update wallpaper by sending data. @SystemApi @hide + @FlaggedApi("com.android.window.flags.always_update_wallpaper_permission") --> <permission android:name="android.permission.ALWAYS_UPDATE_WALLPAPER" android:protectionLevel="internal|role" /> diff --git a/core/res/res/values/config.xml b/core/res/res/values/config.xml index ab71b41bccd4..dbce054dd01a 100644 --- a/core/res/res/values/config.xml +++ b/core/res/res/values/config.xml @@ -2213,7 +2213,10 @@ <bool name="config_single_volume">false</bool> <!-- Volume policy --> + <!-- Strongly consider keeping these 2 values in sync - otherwise vol up/vol down have confusing + asymmetric behavior, as in b/279645379 --> <bool name="config_volume_down_to_enter_silent">false</bool> + <bool name="config_volume_up_to_exit_silent">false</bool> <!-- The number of volume steps for the notification stream --> <integer name="config_audio_notif_vol_steps">7</integer> @@ -4369,6 +4372,15 @@ UI is handled by ActivityManagerService --> <bool name="config_customUserSwitchUi">false</bool> + <!-- Flag specifying whether the first account added can be removed or renamed. By default, + this ability is enabled. When false, user will not be able to remove the first account. --> + <bool name="config_canRemoveFirstAccount">true</bool> + + <!-- Used together with config_canRemoveOrRenameFirstAccount when set to false. By default, this + is blank. Check if the first account is of this account type. If it is, then disable + remove/rename. --> + <string name="config_accountTypeToKeepFirstAccount"></string> + <!-- A array of regex to treat a SMS as VVM SMS if the message body matches. Each item represents an entry, which consists of two parts: a comma (,) separated list of MCCMNC the regex applies to, followed by a semicolon (;), and diff --git a/core/res/res/values/symbols.xml b/core/res/res/values/symbols.xml index 1aa1fea95049..a2f0086491a1 100644 --- a/core/res/res/values/symbols.xml +++ b/core/res/res/values/symbols.xml @@ -328,6 +328,7 @@ <java-symbol type="integer" name="config_phonenumber_compare_min_match" /> <java-symbol type="bool" name="config_single_volume" /> <java-symbol type="bool" name="config_volume_down_to_enter_silent" /> + <java-symbol type="bool" name="config_volume_up_to_exit_silent" /> <java-symbol type="bool" name="config_voice_capable" /> <java-symbol type="bool" name="config_requireCallCapableAccountForHandle" /> <java-symbol type="bool" name="config_user_notification_of_restrictied_mobile_access" /> @@ -1722,6 +1723,8 @@ <java-symbol type="bool" name="config_startDreamImmediatelyOnDock" /> <java-symbol type="bool" name="config_carDockEnablesAccelerometer" /> <java-symbol type="bool" name="config_customUserSwitchUi" /> + <java-symbol type="bool" name="config_canRemoveFirstAccount" /> + <java-symbol type="string" name="config_accountTypeToKeepFirstAccount" /> <java-symbol type="bool" name="config_deskDockEnablesAccelerometer" /> <java-symbol type="bool" name="config_disableMenuKeyInLockScreen" /> <java-symbol type="bool" name="config_enableCarDockHomeLaunch" /> diff --git a/core/tests/coretests/src/android/os/PowerManagerTest.java b/core/tests/coretests/src/android/os/PowerManagerTest.java index 21d1dbb04519..5d213caf61e6 100644 --- a/core/tests/coretests/src/android/os/PowerManagerTest.java +++ b/core/tests/coretests/src/android/os/PowerManagerTest.java @@ -19,11 +19,17 @@ package android.os; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertNotNull; import static org.junit.Assert.fail; +import static org.mockito.Mockito.mock; import static org.mockito.Mockito.reset; import static org.mockito.Mockito.timeout; import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.when; import android.content.Context; +import android.os.Flags; +import android.platform.test.annotations.RequiresFlagsEnabled; +import android.platform.test.flag.junit.CheckFlagsRule; +import android.platform.test.flag.junit.DeviceFlagsValueProvider; import android.test.AndroidTestCase; import androidx.test.InstrumentationRegistry; @@ -31,6 +37,7 @@ import androidx.test.filters.SmallTest; import androidx.test.uiautomator.UiDevice; import org.junit.After; +import org.junit.Rule; import org.junit.Test; import org.mockito.Mock; import org.mockito.MockitoAnnotations; @@ -64,6 +71,10 @@ public class PowerManagerTest extends AndroidTestCase { System.loadLibrary("powermanagertest_jni"); } + // Required for RequiresFlagsEnabled and RequiresFlagsDisabled annotations to take effect. + @Rule + public final CheckFlagsRule mCheckFlagsRule = DeviceFlagsValueProvider.createCheckFlagsRule(); + /** * Setup any common data for the upcoming tests. */ @@ -454,4 +465,27 @@ public class PowerManagerTest extends AndroidTestCase { parcelBatterySaverPolicyConfigToNativeAndVerify(bs2); } + @Test + @RequiresFlagsEnabled(Flags.FLAG_BATTERY_SAVER_SUPPORTED_CHECK_API) + public void testBatterySaverSupported_isSupported() throws RemoteException { + IPowerManager powerManager = mock(IPowerManager.class); + PowerManager pm = new PowerManager(mContext, powerManager, + mock(IThermalService.class), + Handler.createAsync(Looper.getMainLooper())); + when(powerManager.isBatterySaverSupported()).thenReturn(true); + + assertTrue(pm.isBatterySaverSupported()); + } + + @Test + @RequiresFlagsEnabled(Flags.FLAG_BATTERY_SAVER_SUPPORTED_CHECK_API) + public void testBatterySaverSupported_isNotSupported() throws RemoteException { + IPowerManager powerManager = mock(IPowerManager.class); + PowerManager pm = new PowerManager(mContext, powerManager, + mock(IThermalService.class), + Handler.createAsync(Looper.getMainLooper())); + when(powerManager.isBatterySaverSupported()).thenReturn(false); + + assertFalse(pm.isBatterySaverSupported()); + } } diff --git a/core/tests/coretests/src/android/view/contentcapture/ContentCaptureManagerTest.java b/core/tests/coretests/src/android/view/contentcapture/ContentCaptureManagerTest.java index 5c411d5335a7..35ddfdb3723b 100644 --- a/core/tests/coretests/src/android/view/contentcapture/ContentCaptureManagerTest.java +++ b/core/tests/coretests/src/android/view/contentcapture/ContentCaptureManagerTest.java @@ -23,6 +23,7 @@ import static org.testng.Assert.assertThrows; import android.content.ContentCaptureOptions; import android.content.Context; +import android.view.WindowManager; import com.android.internal.util.RingBuffer; @@ -147,6 +148,52 @@ public class ContentCaptureManagerTest { assertThat(manager.getFlushViewTreeAppearingEventDisabled()).isFalse(); } + @Test + public void testUpdateWindowAttribute_setFlagSecure() { + final ContentCaptureManager manager = + new ContentCaptureManager(mMockContext, mMockContentCaptureManager, EMPTY_OPTIONS); + // Ensure main session is created. + final MainContentCaptureSession unused = manager.getMainContentCaptureSession(); + final WindowManager.LayoutParams initialParam = new WindowManager.LayoutParams(); + initialParam.flags |= WindowManager.LayoutParams.FLAG_SECURE; + + manager.updateWindowAttributes(initialParam); + + assertThat(manager.isContentCaptureEnabled()).isFalse(); + } + + @Test + public void testUpdateWindowAttribute_clearFlagSecure() { + final ContentCaptureManager manager = + new ContentCaptureManager(mMockContext, mMockContentCaptureManager, EMPTY_OPTIONS); + // Ensure main session is created. + final MainContentCaptureSession unused = manager.getMainContentCaptureSession(); + final WindowManager.LayoutParams initialParam = new WindowManager.LayoutParams(); + initialParam.flags |= WindowManager.LayoutParams.FLAG_SECURE; + // Default param does not have FLAG_SECURE set. + final WindowManager.LayoutParams resetParam = new WindowManager.LayoutParams(); + + manager.updateWindowAttributes(initialParam); + manager.updateWindowAttributes(resetParam); + + assertThat(manager.isContentCaptureEnabled()).isTrue(); + } + + @Test + public void testUpdateWindowAttribute_clearFlagSecureAfterDisabledByApp() { + final ContentCaptureManager manager = + new ContentCaptureManager(mMockContext, mMockContentCaptureManager, EMPTY_OPTIONS); + // Ensure main session is created. + final MainContentCaptureSession unused = manager.getMainContentCaptureSession(); + // Default param does not have FLAG_SECURE set. + final WindowManager.LayoutParams resetParam = new WindowManager.LayoutParams(); + + manager.setContentCaptureEnabled(false); + manager.updateWindowAttributes(resetParam); + + assertThat(manager.isContentCaptureEnabled()).isFalse(); + } + private ContentCaptureOptions createOptions( ContentCaptureOptions.ContentProtectionOptions contentProtectionOptions) { return new ContentCaptureOptions( diff --git a/graphics/java/android/graphics/RenderNode.java b/graphics/java/android/graphics/RenderNode.java index 15d26ebe66f6..27325694073c 100644 --- a/graphics/java/android/graphics/RenderNode.java +++ b/graphics/java/android/graphics/RenderNode.java @@ -272,6 +272,17 @@ public final class RenderNode { void positionChanged(long frameNumber, int left, int top, int right, int bottom); /** + * Called by native by a Rendering Worker thread to update window position; includes + * the local rect that represents the clipped area of the RenderNode's bounds. + * + * @hide + */ + default void positionChanged(long frameNumber, int left, int top, int right, int bottom, + int clipLeft, int clipTop, int clipRight, int clipBottom) { + positionChanged(frameNumber, left, top, right, bottom); + } + + /** * Called by JNI * * @hide */ @@ -287,6 +298,23 @@ public final class RenderNode { } /** + * Called by JNI + * + * @hide */ + static boolean callPositionChanged2(WeakReference<PositionUpdateListener> weakListener, + long frameNumber, int left, int top, int right, int bottom, + int clipLeft, int clipTop, int clipRight, int clipBottom) { + final PositionUpdateListener listener = weakListener.get(); + if (listener != null) { + listener.positionChanged(frameNumber, left, top, right, bottom, clipLeft, + clipTop, clipRight, clipBottom); + return true; + } else { + return false; + } + } + + /** * Call to apply a stretch effect to any child SurfaceControl layers * * TODO: Fold this into positionChanged & have HWUI do the ASurfaceControl calls? @@ -371,6 +399,15 @@ public final class RenderNode { } @Override + public void positionChanged(long frameNumber, int left, int top, int right, int bottom, + int clipLeft, int clipTop, int clipRight, int clipBottom) { + for (PositionUpdateListener pul : mListeners) { + pul.positionChanged(frameNumber, left, top, right, bottom, clipLeft, clipTop, + clipRight, clipBottom); + } + } + + @Override public void positionLost(long frameNumber) { for (PositionUpdateListener pul : mListeners) { pul.positionLost(frameNumber); diff --git a/keystore/java/android/security/keystore/KeyGenParameterSpec.java b/keystore/java/android/security/keystore/KeyGenParameterSpec.java index 1ba41b106f56..b7140355e489 100644 --- a/keystore/java/android/security/keystore/KeyGenParameterSpec.java +++ b/keystore/java/android/security/keystore/KeyGenParameterSpec.java @@ -1596,6 +1596,8 @@ public final class KeyGenParameterSpec implements AlgorithmParameterSpec, UserAu * {@link #getAttestationChallenge()} returns non-null and the spec is used to generate a * symmetric (AES or HMAC) key, {@link javax.crypto.KeyGenerator#generateKey()} will throw * {@link java.security.InvalidAlgorithmParameterException}. + * + * <p>The challenge may be up to 128 bytes. */ @NonNull public Builder setAttestationChallenge(byte[] attestationChallenge) { diff --git a/libs/WindowManager/Shell/res/layout/bubble_manage_menu.xml b/libs/WindowManager/Shell/res/layout/bubble_manage_menu.xml index 10c9562cf651..d8ae9c8c64a6 100644 --- a/libs/WindowManager/Shell/res/layout/bubble_manage_menu.xml +++ b/libs/WindowManager/Shell/res/layout/bubble_manage_menu.xml @@ -26,7 +26,8 @@ android:id="@+id/bubble_manage_menu_dismiss_container" android:background="@drawable/bubble_manage_menu_row" android:layout_width="match_parent" - android:layout_height="@dimen/bubble_menu_item_height" + android:layout_height="wrap_content" + android:minHeight="@dimen/bubble_menu_item_height" android:gravity="center_vertical" android:paddingStart="@dimen/bubble_menu_padding" android:paddingEnd="@dimen/bubble_menu_padding" @@ -52,7 +53,8 @@ android:id="@+id/bubble_manage_menu_dont_bubble_container" android:background="@drawable/bubble_manage_menu_row" android:layout_width="match_parent" - android:layout_height="@dimen/bubble_menu_item_height" + android:layout_height="wrap_content" + android:minHeight="@dimen/bubble_menu_item_height" android:gravity="center_vertical" android:paddingStart="@dimen/bubble_menu_padding" android:paddingEnd="@dimen/bubble_menu_padding" @@ -78,7 +80,8 @@ android:id="@+id/bubble_manage_menu_settings_container" android:background="@drawable/bubble_manage_menu_row" android:layout_width="match_parent" - android:layout_height="@dimen/bubble_menu_item_height" + android:layout_height="wrap_content" + android:minHeight="@dimen/bubble_menu_item_height" android:gravity="center_vertical" android:paddingStart="@dimen/bubble_menu_padding" android:paddingEnd="@dimen/bubble_menu_padding" diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/activityembedding/ActivityEmbeddingAnimationRunner.java b/libs/WindowManager/Shell/src/com/android/wm/shell/activityembedding/ActivityEmbeddingAnimationRunner.java index 4d87c9583f64..ac75c73d7e6d 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/activityembedding/ActivityEmbeddingAnimationRunner.java +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/activityembedding/ActivityEmbeddingAnimationRunner.java @@ -255,8 +255,13 @@ class ActivityEmbeddingAnimationRunner { int offsetLayer = TYPE_LAYER_OFFSET; final List<ActivityEmbeddingAnimationAdapter> adapters = new ArrayList<>(); for (TransitionInfo.Change change : openingChanges) { + final Animation animation = + animationProvider.get(info, change, openingWholeScreenBounds); + if (animation.getDuration() == 0) { + continue; + } final ActivityEmbeddingAnimationAdapter adapter = createOpenCloseAnimationAdapter( - info, change, animationProvider, openingWholeScreenBounds); + info, change, animation, openingWholeScreenBounds); if (isOpening) { adapter.overrideLayer(offsetLayer++); } @@ -275,8 +280,13 @@ class ActivityEmbeddingAnimationRunner { adapters.add(snapshotAdapter); } } + final Animation animation = + animationProvider.get(info, change, closingWholeScreenBounds); + if (animation.getDuration() == 0) { + continue; + } final ActivityEmbeddingAnimationAdapter adapter = createOpenCloseAnimationAdapter( - info, change, animationProvider, closingWholeScreenBounds); + info, change, animation, closingWholeScreenBounds); if (!isOpening) { adapter.overrideLayer(offsetLayer++); } @@ -353,8 +363,7 @@ class ActivityEmbeddingAnimationRunner { @NonNull private ActivityEmbeddingAnimationAdapter createOpenCloseAnimationAdapter( @NonNull TransitionInfo info, @NonNull TransitionInfo.Change change, - @NonNull AnimationProvider animationProvider, @NonNull Rect wholeAnimationBounds) { - final Animation animation = animationProvider.get(info, change, wholeAnimationBounds); + @NonNull Animation animation, @NonNull Rect wholeAnimationBounds) { return new ActivityEmbeddingAnimationAdapter(animation, change, change.getLeash(), wholeAnimationBounds, TransitionUtil.getRootFor(change, info)); } diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/activityembedding/ActivityEmbeddingAnimationSpec.java b/libs/WindowManager/Shell/src/com/android/wm/shell/activityembedding/ActivityEmbeddingAnimationSpec.java index cc9c2beff873..6cd1324c7d24 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/activityembedding/ActivityEmbeddingAnimationSpec.java +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/activityembedding/ActivityEmbeddingAnimationSpec.java @@ -22,6 +22,8 @@ import static android.app.ActivityOptions.ANIM_CUSTOM; import static com.android.internal.policy.TransitionAnimation.WALLPAPER_TRANSITION_NONE; import static com.android.wm.shell.transition.TransitionAnimationHelper.loadAttributeAnimation; +import android.annotation.NonNull; +import android.annotation.Nullable; import android.content.Context; import android.graphics.Rect; import android.view.animation.AlphaAnimation; @@ -34,8 +36,6 @@ import android.view.animation.ScaleAnimation; import android.view.animation.TranslateAnimation; import android.window.TransitionInfo; -import androidx.annotation.NonNull; - import com.android.internal.policy.TransitionAnimation; import com.android.wm.shell.util.TransitionUtil; @@ -201,11 +201,10 @@ class ActivityEmbeddingAnimationSpec { Animation loadOpenAnimation(@NonNull TransitionInfo info, @NonNull TransitionInfo.Change change, @NonNull Rect wholeAnimationBounds) { final boolean isEnter = TransitionUtil.isOpeningType(change.getMode()); - final TransitionInfo.AnimationOptions options = info.getAnimationOptions(); + final Animation customAnimation = loadCustomAnimation(info, isEnter); final Animation animation; - if (options != null && options.getType() == ANIM_CUSTOM) { - animation = mTransitionAnimation.loadAnimationRes(options.getPackageName(), - isEnter ? options.getEnterResId() : options.getExitResId()); + if (customAnimation != null) { + animation = customAnimation; } else if (shouldShowBackdrop(info, change)) { animation = mTransitionAnimation.loadDefaultAnimationRes(isEnter ? com.android.internal.R.anim.task_fragment_clear_top_open_enter @@ -229,11 +228,10 @@ class ActivityEmbeddingAnimationSpec { Animation loadCloseAnimation(@NonNull TransitionInfo info, @NonNull TransitionInfo.Change change, @NonNull Rect wholeAnimationBounds) { final boolean isEnter = TransitionUtil.isOpeningType(change.getMode()); - final TransitionInfo.AnimationOptions options = info.getAnimationOptions(); + final Animation customAnimation = loadCustomAnimation(info, isEnter); final Animation animation; - if (options != null && options.getType() == ANIM_CUSTOM) { - animation = mTransitionAnimation.loadAnimationRes(options.getPackageName(), - isEnter ? options.getEnterResId() : options.getExitResId()); + if (customAnimation != null) { + animation = customAnimation; } else if (shouldShowBackdrop(info, change)) { animation = mTransitionAnimation.loadDefaultAnimationRes(isEnter ? com.android.internal.R.anim.task_fragment_clear_top_close_enter @@ -259,4 +257,21 @@ class ActivityEmbeddingAnimationSpec { mTransitionAnimation, false); return a != null && a.getShowBackdrop(); } + + @Nullable + private Animation loadCustomAnimation(@NonNull TransitionInfo info, boolean isEnter) { + final TransitionInfo.AnimationOptions options = info.getAnimationOptions(); + if (options == null || options.getType() != ANIM_CUSTOM) { + return null; + } + final Animation anim = mTransitionAnimation.loadAnimationRes(options.getPackageName(), + isEnter ? options.getEnterResId() : options.getExitResId()); + if (anim != null) { + return anim; + } + // The app may be intentional to use an invalid resource as a no-op animation. + // ActivityEmbeddingAnimationRunner#createOpenCloseAnimationAdapters will skip the + // animation with duration 0. Then it will use prepareForJumpCut for empty adapters. + return new AlphaAnimation(1f, 1f); + } } diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/back/CrossActivityAnimation.java b/libs/WindowManager/Shell/src/com/android/wm/shell/back/CrossActivityAnimation.java index 24479d7b5f39..a596cef9562a 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/back/CrossActivityAnimation.java +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/back/CrossActivityAnimation.java @@ -353,7 +353,6 @@ public class CrossActivityAnimation extends ShellBackAnimation { closingLeft += mapRange(interpolatedProgress, deltaXMin, deltaXMax); // Move the window along the Y axis. - final float deltaYRatio = (touchY - mInitialTouchPos.y) / height; final float closingTop = (height - closingHeight) * 0.5f; targetRect.set( closingLeft, closingTop, closingLeft + closingWidth, closingTop + closingHeight); diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/dagger/pip/Pip2Module.java b/libs/WindowManager/Shell/src/com/android/wm/shell/dagger/pip/Pip2Module.java index 1898ea737729..3b48c67a5bbd 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/dagger/pip/Pip2Module.java +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/dagger/pip/Pip2Module.java @@ -22,6 +22,8 @@ import android.content.Context; import com.android.wm.shell.ShellTaskOrganizer; import com.android.wm.shell.common.DisplayController; import com.android.wm.shell.common.DisplayInsetsController; +import com.android.wm.shell.common.ShellExecutor; +import com.android.wm.shell.common.annotations.ShellMainThread; import com.android.wm.shell.common.pip.PipBoundsAlgorithm; import com.android.wm.shell.common.pip.PipBoundsState; import com.android.wm.shell.common.pip.PipDisplayLayoutState; @@ -29,6 +31,7 @@ import com.android.wm.shell.common.pip.PipUtils; import com.android.wm.shell.dagger.WMShellBaseModule; import com.android.wm.shell.dagger.WMSingleton; import com.android.wm.shell.pip2.phone.PipController; +import com.android.wm.shell.pip2.phone.PipScheduler; import com.android.wm.shell.pip2.phone.PipTransition; import com.android.wm.shell.sysui.ShellController; import com.android.wm.shell.sysui.ShellInit; @@ -52,9 +55,10 @@ public abstract class Pip2Module { @NonNull Transitions transitions, PipBoundsState pipBoundsState, PipBoundsAlgorithm pipBoundsAlgorithm, - Optional<PipController> pipController) { + Optional<PipController> pipController, + @NonNull PipScheduler pipScheduler) { return new PipTransition(shellInit, shellTaskOrganizer, transitions, pipBoundsState, null, - pipBoundsAlgorithm); + pipBoundsAlgorithm, pipScheduler); } @WMSingleton @@ -73,4 +77,12 @@ public abstract class Pip2Module { pipDisplayLayoutState)); } } + + @WMSingleton + @Provides + static PipScheduler providePipScheduler(Context context, + PipBoundsState pipBoundsState, + @ShellMainThread ShellExecutor mainExecutor) { + return new PipScheduler(context, pipBoundsState, mainExecutor); + } } diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/pip2/phone/PipScheduler.java b/libs/WindowManager/Shell/src/com/android/wm/shell/pip2/phone/PipScheduler.java new file mode 100644 index 000000000000..9bb383f0b61a --- /dev/null +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/pip2/phone/PipScheduler.java @@ -0,0 +1,138 @@ +/* + * Copyright (C) 2023 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.wm.shell.pip2.phone; + +import static android.app.WindowConfiguration.WINDOWING_MODE_UNDEFINED; + +import static com.android.wm.shell.transition.Transitions.TRANSIT_EXIT_PIP; + +import android.content.BroadcastReceiver; +import android.content.Context; +import android.content.Intent; +import android.content.IntentFilter; +import android.view.SurfaceControl; +import android.window.WindowContainerToken; +import android.window.WindowContainerTransaction; + +import androidx.annotation.Nullable; +import androidx.core.content.ContextCompat; + +import com.android.wm.shell.common.ShellExecutor; +import com.android.wm.shell.common.pip.PipBoundsState; +import com.android.wm.shell.common.pip.PipUtils; +import com.android.wm.shell.pip.PipTransitionController; + +/** + * Scheduler for Shell initiated PiP transitions and animations. + */ +public class PipScheduler { + private static final String TAG = PipScheduler.class.getSimpleName(); + private static final String BROADCAST_FILTER = PipScheduler.class.getCanonicalName(); + + private final Context mContext; + private final PipBoundsState mPipBoundsState; + private final ShellExecutor mMainExecutor; + private PipSchedulerReceiver mSchedulerReceiver; + private PipTransitionController mPipTransitionController; + + // pinned PiP task's WC token + @Nullable + private WindowContainerToken mPipTaskToken; + + // pinned PiP task's leash + @Nullable + private SurfaceControl mPinnedTaskLeash; + + // the leash of the original task of the PiP activity; + // used to synchronize app drawings in the multi-activity case + @Nullable + private SurfaceControl mOriginalTaskLeash; + + /** + * A temporary broadcast receiver to initiate exit PiP via expand. + * This will later be modified to be triggered by the PiP menu. + */ + private class PipSchedulerReceiver extends BroadcastReceiver { + @Override + public void onReceive(Context context, Intent intent) { + scheduleExitPipViaExpand(); + } + } + + public PipScheduler(Context context, PipBoundsState pipBoundsState, + ShellExecutor mainExecutor) { + mContext = context; + mPipBoundsState = pipBoundsState; + mMainExecutor = mainExecutor; + + if (PipUtils.isPip2ExperimentEnabled()) { + // temporary broadcast receiver to initiate exit PiP via expand + mSchedulerReceiver = new PipSchedulerReceiver(); + ContextCompat.registerReceiver(mContext, mSchedulerReceiver, + new IntentFilter(BROADCAST_FILTER), ContextCompat.RECEIVER_EXPORTED); + } + } + + void setPipTransitionController(PipTransitionController pipTransitionController) { + mPipTransitionController = pipTransitionController; + } + + void setPinnedTaskLeash(SurfaceControl pinnedTaskLeash) { + mPinnedTaskLeash = pinnedTaskLeash; + } + + void setOriginalTaskLeash(SurfaceControl originalTaskLeash) { + mOriginalTaskLeash = originalTaskLeash; + } + + void setPipTaskToken(@Nullable WindowContainerToken pipTaskToken) { + mPipTaskToken = pipTaskToken; + } + + @Nullable + private WindowContainerTransaction getExitPipViaExpandTransaction() { + if (mPipTaskToken == null || mPinnedTaskLeash == null) { + return null; + } + WindowContainerTransaction wct = new WindowContainerTransaction(); + // final expanded bounds to be inherited from the parent + wct.setBounds(mPipTaskToken, null); + // if we are hitting a multi-activity case + // windowing mode change will reparent to original host task + wct.setWindowingMode(mPipTaskToken, WINDOWING_MODE_UNDEFINED); + return wct; + } + + /** + * Schedules exit PiP via expand transition. + */ + public void scheduleExitPipViaExpand() { + WindowContainerTransaction wct = getExitPipViaExpandTransaction(); + if (wct != null) { + mMainExecutor.execute(() -> { + mPipTransitionController.startExitTransition(TRANSIT_EXIT_PIP, wct, + null /* destinationBounds */); + }); + } + } + + void onExitPip() { + mPipTaskToken = null; + mPinnedTaskLeash = null; + mOriginalTaskLeash = null; + } +} diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/pip2/phone/PipTransition.java b/libs/WindowManager/Shell/src/com/android/wm/shell/pip2/phone/PipTransition.java index d704b091754f..7d3bd658d126 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/pip2/phone/PipTransition.java +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/pip2/phone/PipTransition.java @@ -16,8 +16,12 @@ package com.android.wm.shell.pip2.phone; +import static android.app.ActivityTaskManager.INVALID_TASK_ID; +import static android.app.WindowConfiguration.WINDOWING_MODE_PINNED; import static android.view.WindowManager.TRANSIT_OPEN; +import static com.android.wm.shell.transition.Transitions.TRANSIT_EXIT_PIP; + import android.annotation.NonNull; import android.app.ActivityManager; import android.app.PictureInPictureParams; @@ -26,6 +30,7 @@ import android.os.IBinder; import android.view.SurfaceControl; import android.window.TransitionInfo; import android.window.TransitionRequestInfo; +import android.window.WindowContainerToken; import android.window.WindowContainerTransaction; import androidx.annotation.Nullable; @@ -43,8 +48,15 @@ import com.android.wm.shell.transition.Transitions; * Implementation of transitions for PiP on phone. */ public class PipTransition extends PipTransitionController { + private static final String TAG = PipTransition.class.getSimpleName(); + + private PipScheduler mPipScheduler; + @Nullable + private WindowContainerToken mPipTaskToken; @Nullable private IBinder mAutoEnterButtonNavTransition; + @Nullable + private IBinder mExitViaExpandTransition; public PipTransition( @NonNull ShellInit shellInit, @@ -52,9 +64,13 @@ public class PipTransition extends PipTransitionController { @NonNull Transitions transitions, PipBoundsState pipBoundsState, PipMenuController pipMenuController, - PipBoundsAlgorithm pipBoundsAlgorithm) { + PipBoundsAlgorithm pipBoundsAlgorithm, + PipScheduler pipScheduler) { super(shellInit, shellTaskOrganizer, transitions, pipBoundsState, pipMenuController, pipBoundsAlgorithm); + + mPipScheduler = pipScheduler; + mPipScheduler.setPipTransitionController(this); } @Override @@ -64,6 +80,18 @@ public class PipTransition extends PipTransitionController { } } + @Override + public void startExitTransition(int type, WindowContainerTransaction out, + @android.annotation.Nullable Rect destinationBounds) { + if (out == null) { + return; + } + IBinder transition = mTransitions.startTransition(type, out, this); + if (type == TRANSIT_EXIT_PIP) { + mExitViaExpandTransition = transition; + } + } + @Nullable @Override public WindowContainerTransaction handleRequest(@NonNull IBinder transition, @@ -84,8 +112,18 @@ public class PipTransition extends PipTransitionController { } } + @Override + public void mergeAnimation(@NonNull IBinder transition, @NonNull TransitionInfo info, + @NonNull SurfaceControl.Transaction t, @NonNull IBinder mergeTarget, + @NonNull Transitions.TransitionFinishCallback finishCallback) {} + + @Override + public void onTransitionConsumed(@NonNull IBinder transition, boolean aborted, + @Nullable SurfaceControl.Transaction finishT) {} + private WindowContainerTransaction getEnterPipTransaction(@NonNull IBinder transition, @NonNull TransitionRequestInfo request) { + // cache the original task token to check for multi-activity case later final ActivityManager.RunningTaskInfo pipTask = request.getPipTask(); PictureInPictureParams pipParams = pipTask.pictureInPictureParams; mPipBoundsState.setBoundsStateForEntry(pipTask.topActivity, pipTask.topActivityInfo, @@ -93,6 +131,8 @@ public class PipTransition extends PipTransitionController { // calculate the entry bounds and notify core to move task to pinned with final bounds final Rect entryBounds = mPipBoundsAlgorithm.getEntryDestinationBounds(); + mPipBoundsState.setBounds(entryBounds); + WindowContainerTransaction wct = new WindowContainerTransaction(); wct.movePipActivityToPinnedRootTask(pipTask.token, entryBounds); return wct; @@ -121,19 +161,59 @@ public class PipTransition extends PipTransitionController { @NonNull SurfaceControl.Transaction finishTransaction, @NonNull Transitions.TransitionFinishCallback finishCallback) { if (transition == mAutoEnterButtonNavTransition) { + mAutoEnterButtonNavTransition = null; + TransitionInfo.Change pipChange = getPipChange(info); + if (pipChange == null) { + return false; + } + mPipTaskToken = pipChange.getContainer(); + + // cache the PiP task token and the relevant leashes + mPipScheduler.setPipTaskToken(mPipTaskToken); + mPipScheduler.setPinnedTaskLeash(pipChange.getLeash()); + // check if we entered PiP from a multi-activity task and set the original task leash + final int lastParentTaskId = pipChange.getTaskInfo().lastParentTaskIdBeforePip; + final boolean isSingleActivity = lastParentTaskId == INVALID_TASK_ID; + mPipScheduler.setOriginalTaskLeash(isSingleActivity ? null : + findChangeByTaskId(info, lastParentTaskId).getLeash()); + startTransaction.apply(); finishCallback.onTransitionFinished(null); return true; + } else if (transition == mExitViaExpandTransition) { + mExitViaExpandTransition = null; + startTransaction.apply(); + finishCallback.onTransitionFinished(null); + onExitPip(); + return true; } return false; } - @Override - public void mergeAnimation(@NonNull IBinder transition, @NonNull TransitionInfo info, - @NonNull SurfaceControl.Transaction t, @NonNull IBinder mergeTarget, - @NonNull Transitions.TransitionFinishCallback finishCallback) {} + @Nullable + private TransitionInfo.Change getPipChange(TransitionInfo info) { + for (TransitionInfo.Change change : info.getChanges()) { + if (change.getTaskInfo() != null + && change.getTaskInfo().getWindowingMode() == WINDOWING_MODE_PINNED) { + return change; + } + } + return null; + } - @Override - public void onTransitionConsumed(@NonNull IBinder transition, boolean aborted, - @Nullable SurfaceControl.Transaction finishT) {} + @Nullable + private TransitionInfo.Change findChangeByTaskId(TransitionInfo info, int taskId) { + for (TransitionInfo.Change change : info.getChanges()) { + if (change.getTaskInfo() != null + && change.getTaskInfo().taskId == taskId) { + return change; + } + } + return null; + } + + private void onExitPip() { + mPipTaskToken = null; + mPipScheduler.onExitPip(); + } } diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/transition/DefaultTransitionHandler.java b/libs/WindowManager/Shell/src/com/android/wm/shell/transition/DefaultTransitionHandler.java index 9cd318f27355..723a4a7ca664 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/transition/DefaultTransitionHandler.java +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/transition/DefaultTransitionHandler.java @@ -40,7 +40,6 @@ import static android.view.WindowManager.LayoutParams.ROTATION_ANIMATION_UNSPECI import static android.view.WindowManager.TRANSIT_CHANGE; import static android.view.WindowManager.TRANSIT_KEYGUARD_UNOCCLUDE; import static android.view.WindowManager.TRANSIT_RELAUNCH; -import static android.window.TransitionInfo.FLAG_BACK_GESTURE_ANIMATED; import static android.window.TransitionInfo.FLAG_CROSS_PROFILE_OWNER_THUMBNAIL; import static android.window.TransitionInfo.FLAG_CROSS_PROFILE_WORK_THUMBNAIL; import static android.window.TransitionInfo.FLAG_DISPLAY_HAS_ALERT_WINDOWS; @@ -422,11 +421,6 @@ public class DefaultTransitionHandler implements Transitions.TransitionHandler { continue; } - // The back gesture has animated this change before transition happen, so here we don't - // play the animation again. - if (change.hasFlags(FLAG_BACK_GESTURE_ANIMATED)) { - continue; - } // Don't animate anything that isn't independent. if (!TransitionInfo.isIndependent(change, info)) continue; diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/transition/OneShotRemoteHandler.java b/libs/WindowManager/Shell/src/com/android/wm/shell/transition/OneShotRemoteHandler.java index b1fc16ddf19b..030f601a7b60 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/transition/OneShotRemoteHandler.java +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/transition/OneShotRemoteHandler.java @@ -44,7 +44,7 @@ public class OneShotRemoteHandler implements Transitions.TransitionHandler { private IBinder mTransition = null; /** The remote to delegate animation to */ - private final RemoteTransition mRemote; + private RemoteTransition mRemote; public OneShotRemoteHandler(@NonNull ShellExecutor mainExecutor, @NonNull RemoteTransition remote) { @@ -83,6 +83,8 @@ public class OneShotRemoteHandler implements Transitions.TransitionHandler { mMainExecutor.execute(() -> { finishCallback.onTransitionFinished(wct); }); + Log.d("b/302551868", "OneShotRemoteHandler#start remote anim null"); + mRemote = null; } }; Transitions.setRunningRemoteTransitionDelegate(mRemote.getAppThread()); @@ -105,6 +107,8 @@ public class OneShotRemoteHandler implements Transitions.TransitionHandler { mRemote.asBinder().unlinkToDeath(remoteDied, 0 /* flags */); } finishCallback.onTransitionFinished(null /* wct */); + Log.d("b/302551868", "OneShotRemoteHandler#exception remote anim null"); + mRemote = null; } return true; } @@ -123,6 +127,8 @@ public class OneShotRemoteHandler implements Transitions.TransitionHandler { // so just assume the worst-case and clear the local transaction. t.clear(); mMainExecutor.execute(() -> finishCallback.onTransitionFinished(wct)); + Log.d("b/302551868", "OneShotRemoteHandler#merge remote anim null"); + mRemote = null; } }; try { diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/transition/Transitions.java b/libs/WindowManager/Shell/src/com/android/wm/shell/transition/Transitions.java index baa9acaafa4b..718c704f2c65 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/transition/Transitions.java +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/transition/Transitions.java @@ -28,6 +28,7 @@ import static android.view.WindowManager.TRANSIT_SLEEP; import static android.view.WindowManager.TRANSIT_TO_BACK; import static android.view.WindowManager.TRANSIT_TO_FRONT; import static android.view.WindowManager.fixScale; +import static android.window.TransitionInfo.FLAG_BACK_GESTURE_ANIMATED; import static android.window.TransitionInfo.FLAG_IS_BEHIND_STARTING_WINDOW; import static android.window.TransitionInfo.FLAG_IS_OCCLUDED; import static android.window.TransitionInfo.FLAG_IS_WALLPAPER; @@ -204,12 +205,6 @@ public class Transitions implements RemoteCallable<Transitions>, */ private static final int SYNC_ALLOWANCE_MS = 120; - /** - * Keyguard gets a more generous timeout to finish its animations, because we are always holding - * a sleep token during occlude/unocclude transitions and we want them to finish playing cleanly - */ - private static final int SYNC_ALLOWANCE_KEYGUARD_MS = 2000; - /** For testing only. Disables the force-finish timeout on sync. */ private boolean mDisableForceSync = false; @@ -743,6 +738,11 @@ public class Transitions implements RemoteCallable<Transitions>, if (!change.hasFlags(FLAG_IS_OCCLUDED)) { allOccluded = false; } + // The change has already animated by back gesture, don't need to play transition + // animation on it. + if (change.hasFlags(FLAG_BACK_GESTURE_ANIMATED)) { + info.getChanges().remove(i); + } } // There does not need animation when: // A. Transfer starting window. Apply transfer starting window directly if there is no other @@ -1203,11 +1203,8 @@ public class Transitions implements RemoteCallable<Transitions>, if (track.mActiveTransition == playing) { if (!mDisableForceSync) { // Give it a short amount of time to process it before forcing. - final int tolerance = KeyguardTransitionHandler.handles(playing.mInfo) - ? SYNC_ALLOWANCE_KEYGUARD_MS - : SYNC_ALLOWANCE_MS; mMainExecutor.executeDelayed( - () -> finishForSync(reason, trackIdx, playing), tolerance); + () -> finishForSync(reason, trackIdx, playing), SYNC_ALLOWANCE_MS); } break; } diff --git a/libs/WindowManager/Shell/tests/flicker/Android.bp b/libs/WindowManager/Shell/tests/flicker/Android.bp index bd2eb5b4a8ae..366f7b1e678f 100644 --- a/libs/WindowManager/Shell/tests/flicker/Android.bp +++ b/libs/WindowManager/Shell/tests/flicker/Android.bp @@ -28,93 +28,6 @@ filegroup { srcs: ["src/com/android/wm/shell/flicker/utils/*.kt"], } -filegroup { - name: "WMShellFlickerTestsBase-src", - srcs: ["src/com/android/wm/shell/flicker/*.kt"], -} - -filegroup { - name: "WMShellFlickerTestsBubbles-src", - srcs: ["src/com/android/wm/shell/flicker/bubble/*.kt"], -} - -filegroup { - name: "WMShellFlickerTestsPip1-src", - srcs: [ - "src/com/android/wm/shell/flicker/pip/A*.kt", - "src/com/android/wm/shell/flicker/pip/B*.kt", - "src/com/android/wm/shell/flicker/pip/C*.kt", - "src/com/android/wm/shell/flicker/pip/D*.kt", - "src/com/android/wm/shell/flicker/pip/S*.kt", - ], -} - -filegroup { - name: "WMShellFlickerTestsPip2-src", - srcs: [ - "src/com/android/wm/shell/flicker/pip/E*.kt", - ], -} - -filegroup { - name: "WMShellFlickerTestsPip3-src", - srcs: ["src/com/android/wm/shell/flicker/pip/*.kt"], -} - -filegroup { - name: "WMShellFlickerTestsPipCommon-src", - srcs: ["src/com/android/wm/shell/flicker/pip/common/*.kt"], -} - -filegroup { - name: "WMShellFlickerTestsPipApps-src", - srcs: ["src/com/android/wm/shell/flicker/pip/apps/*.kt"], -} - -filegroup { - name: "WMShellFlickerTestsSplitScreenBase-src", - srcs: [ - "src/com/android/wm/shell/flicker/splitscreen/benchmark/*.kt", - ], -} - -filegroup { - name: "WMShellFlickerTestsSplitScreenGroup1-src", - srcs: [ - "src/com/android/wm/shell/flicker/splitscreen/A*.kt", - "src/com/android/wm/shell/flicker/splitscreen/B*.kt", - "src/com/android/wm/shell/flicker/splitscreen/C*.kt", - "src/com/android/wm/shell/flicker/splitscreen/D*.kt", - "src/com/android/wm/shell/flicker/splitscreen/E*.kt", - ], -} - -filegroup { - name: "WMShellFlickerTestsSplitScreenGroup2-src", - srcs: [ - "src/com/android/wm/shell/flicker/splitscreen/*.kt", - ], -} - -filegroup { - name: "WMShellFlickerServicePlatinumTests-src", - srcs: [ - "src/com/android/wm/shell/flicker/service/*/platinum/**/*.kt", - "src/com/android/wm/shell/flicker/service/*/scenarios/**/*.kt", - "src/com/android/wm/shell/flicker/service/common/**/*.kt", - ], -} - -filegroup { - name: "WMShellFlickerServiceTests-src", - srcs: [ - "src/com/android/wm/shell/flicker/service/**/*.kt", - ], - exclude_srcs: [ - "src/com/android/wm/shell/flicker/service/*/platinum/**/*.kt", - ], -} - java_library { name: "wm-shell-flicker-utils", platform_apis: true, @@ -138,23 +51,8 @@ java_library { ], } -java_library { - name: "wm-shell-flicker-platinum-tests", - platform_apis: true, - optimize: { - enabled: false, - }, - srcs: [ - ":WMShellFlickerServicePlatinumTests-src", - ], - static_libs: [ - "wm-shell-flicker-utils", - ], -} - java_defaults { name: "WMShellFlickerTestsDefaultWithoutTemplate", - manifest: "manifests/AndroidManifest.xml", platform_apis: true, certificate: "platform", optimize: { @@ -187,170 +85,8 @@ java_defaults { test_config_template: "AndroidTestTemplate.xml", } -android_test { - name: "WMShellFlickerTestsOther", - defaults: ["WMShellFlickerTestsDefault"], - additional_manifests: ["manifests/AndroidManifestOther.xml"], - package_name: "com.android.wm.shell.flicker", - instrumentation_target_package: "com.android.wm.shell.flicker", - srcs: [ - "src/**/*.java", - "src/**/*.kt", - ], - exclude_srcs: [ - ":WMShellFlickerTestsBubbles-src", - ":WMShellFlickerTestsPip1-src", - ":WMShellFlickerTestsPip2-src", - ":WMShellFlickerTestsPip3-src", - ":WMShellFlickerTestsPipCommon-src", - ":WMShellFlickerTestsPipApps-src", - ":WMShellFlickerTestsSplitScreenGroup1-src", - ":WMShellFlickerTestsSplitScreenGroup2-src", - ":WMShellFlickerTestsSplitScreenBase-src", - ":WMShellFlickerServiceTests-src", - ":WMShellFlickerServicePlatinumTests-src", - ], -} - -android_test { - name: "WMShellFlickerTestsBubbles", - defaults: ["WMShellFlickerTestsDefault"], - additional_manifests: ["manifests/AndroidManifestBubbles.xml"], - package_name: "com.android.wm.shell.flicker.bubbles", - instrumentation_target_package: "com.android.wm.shell.flicker.bubbles", - srcs: [ - ":WMShellFlickerTestsBase-src", - ":WMShellFlickerTestsBubbles-src", - ], -} - -android_test { - name: "WMShellFlickerTestsPip1", - defaults: ["WMShellFlickerTestsDefault"], - additional_manifests: ["manifests/AndroidManifestPip.xml"], - package_name: "com.android.wm.shell.flicker.pip", - instrumentation_target_package: "com.android.wm.shell.flicker.pip", - srcs: [ - ":WMShellFlickerTestsBase-src", - ":WMShellFlickerTestsPip1-src", - ":WMShellFlickerTestsPipCommon-src", - ], -} - -android_test { - name: "WMShellFlickerTestsPip2", - defaults: ["WMShellFlickerTestsDefault"], - additional_manifests: ["manifests/AndroidManifestPip.xml"], - package_name: "com.android.wm.shell.flicker.pip", - instrumentation_target_package: "com.android.wm.shell.flicker.pip", - srcs: [ - ":WMShellFlickerTestsBase-src", - ":WMShellFlickerTestsPip2-src", - ":WMShellFlickerTestsPipCommon-src", - ], -} - -android_test { - name: "WMShellFlickerTestsPip3", - defaults: ["WMShellFlickerTestsDefault"], - additional_manifests: ["manifests/AndroidManifestPip.xml"], - package_name: "com.android.wm.shell.flicker.pip", - instrumentation_target_package: "com.android.wm.shell.flicker.pip", - srcs: [ - ":WMShellFlickerTestsBase-src", - ":WMShellFlickerTestsPip3-src", - ":WMShellFlickerTestsPipCommon-src", - ], - exclude_srcs: [ - ":WMShellFlickerTestsPip1-src", - ":WMShellFlickerTestsPip2-src", - ], -} - -android_test { - name: "WMShellFlickerTestsPipApps", - defaults: ["WMShellFlickerTestsDefault"], - additional_manifests: ["manifests/AndroidManifestPip.xml"], - package_name: "com.android.wm.shell.flicker.pip.apps", - instrumentation_target_package: "com.android.wm.shell.flicker.pip.apps", - srcs: [ - ":WMShellFlickerTestsBase-src", - ":WMShellFlickerTestsPipApps-src", - ":WMShellFlickerTestsPipCommon-src", - ], -} - -android_test { - name: "WMShellFlickerTestsPipAppsCSuite", - defaults: ["WMShellFlickerTestsDefaultWithoutTemplate"], - additional_manifests: ["manifests/AndroidManifestPip.xml"], - package_name: "com.android.wm.shell.flicker.pip.apps", - instrumentation_target_package: "com.android.wm.shell.flicker.pip.apps", - srcs: [ - ":WMShellFlickerTestsBase-src", - ":WMShellFlickerTestsPipApps-src", - ":WMShellFlickerTestsPipCommon-src", - ], - test_suites: [ - "device-tests", - "csuite", - ], -} - -android_test { - name: "WMShellFlickerTestsSplitScreenGroup1", - defaults: ["WMShellFlickerTestsDefault"], - additional_manifests: ["manifests/AndroidManifestSplitScreen.xml"], - package_name: "com.android.wm.shell.flicker.splitscreen", - instrumentation_target_package: "com.android.wm.shell.flicker.splitscreen", - srcs: [ - ":WMShellFlickerTestsBase-src", - ":WMShellFlickerTestsSplitScreenBase-src", - ":WMShellFlickerTestsSplitScreenGroup1-src", - ], -} - -android_test { - name: "WMShellFlickerTestsSplitScreenGroup2", - defaults: ["WMShellFlickerTestsDefault"], - additional_manifests: ["manifests/AndroidManifestSplitScreen.xml"], - package_name: "com.android.wm.shell.flicker.splitscreen", - instrumentation_target_package: "com.android.wm.shell.flicker.splitscreen", - srcs: [ - ":WMShellFlickerTestsBase-src", - ":WMShellFlickerTestsSplitScreenBase-src", - ":WMShellFlickerTestsSplitScreenGroup2-src", - ], - exclude_srcs: [ - ":WMShellFlickerTestsSplitScreenGroup1-src", - ], -} - -android_test { - name: "WMShellFlickerServiceTests", - defaults: ["WMShellFlickerTestsDefault"], - additional_manifests: ["manifests/AndroidManifestService.xml"], - package_name: "com.android.wm.shell.flicker.service", - instrumentation_target_package: "com.android.wm.shell.flicker.service", - srcs: [ - ":WMShellFlickerTestsBase-src", - ":WMShellFlickerServiceTests-src", - ], -} - -android_test { - name: "WMShellFlickerServicePlatinumTests", +java_library { + name: "WMShellFlickerTestsBase", defaults: ["WMShellFlickerTestsDefault"], - additional_manifests: ["manifests/AndroidManifestService.xml"], - package_name: "com.android.wm.shell.flicker.service", - instrumentation_target_package: "com.android.wm.shell.flicker.service", - srcs: [ - ":WMShellFlickerTestsBase-src", - ":WMShellFlickerServicePlatinumTests-src", - ], -} - -csuite_test { - name: "csuite-1p3p-pip-flickers", - test_config_template: "csuiteDefaultTemplate.xml", + srcs: ["src/com/android/wm/shell/flicker/*.kt"], } diff --git a/libs/WindowManager/Shell/tests/flicker/appcompat/Android.bp b/libs/WindowManager/Shell/tests/flicker/appcompat/Android.bp new file mode 100644 index 000000000000..bae701f2cbeb --- /dev/null +++ b/libs/WindowManager/Shell/tests/flicker/appcompat/Android.bp @@ -0,0 +1,41 @@ +// +// Copyright (C) 2020 The Android Open Source Project +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// + +package { + // See: http://go/android-license-faq + // A large-scale-change added 'default_applicable_licenses' to import + // all of the 'license_kinds' from "frameworks_base_license" + // to get the below license kinds: + // SPDX-license-identifier-Apache-2.0 + default_applicable_licenses: ["frameworks_base_license"], +} + +filegroup { + name: "WMShellFlickerTestsAppCompat-src", + srcs: [ + "src/**/*.kt", + ], +} + +android_test { + name: "WMShellFlickerTestsOther", + defaults: ["WMShellFlickerTestsDefault"], + manifest: "AndroidManifest.xml", + package_name: "com.android.wm.shell.flicker", + instrumentation_target_package: "com.android.wm.shell.flicker", + srcs: [":WMShellFlickerTestsAppCompat-src"], + static_libs: ["WMShellFlickerTestsBase"], +} diff --git a/libs/WindowManager/Shell/tests/flicker/manifests/AndroidManifest.xml b/libs/WindowManager/Shell/tests/flicker/appcompat/AndroidManifest.xml index ae130b8f6f7d..2af1e74fb3d5 100644 --- a/libs/WindowManager/Shell/tests/flicker/manifests/AndroidManifest.xml +++ b/libs/WindowManager/Shell/tests/flicker/appcompat/AndroidManifest.xml @@ -1,18 +1,18 @@ -<?xml version="1.0" encoding="utf-8"?> -<!-- Copyright (C) 2020 The Android Open Source Project - - Licensed under the Apache License, Version 2.0 (the "License"); - you may not use this file except in compliance with the License. - You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - - Unless required by applicable law or agreed to in writing, software - distributed under the License is distributed on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - See the License for the specific language governing permissions and - limitations under the License. ---> +<!-- + ~ Copyright (C) 2023 The Android Open Source Project + ~ + ~ Licensed under the Apache License, Version 2.0 (the "License"); + ~ you may not use this file except in compliance with the License. + ~ You may obtain a copy of the License at + ~ + ~ http://www.apache.org/licenses/LICENSE-2.0 + ~ + ~ Unless required by applicable law or agreed to in writing, software + ~ distributed under the License is distributed on an "AS IS" BASIS, + ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + ~ See the License for the specific language governing permissions and + ~ limitations under the License. + --> <manifest xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools="http://schemas.android.com/tools" @@ -69,4 +69,9 @@ android:authorities="${applicationId}.androidx-startup" tools:node="remove" /> </application> + + <instrumentation android:name="androidx.test.runner.AndroidJUnitRunner" + android:targetPackage="com.android.wm.shell.flicker" + android:label="WindowManager Flicker Tests"> + </instrumentation> </manifest> diff --git a/libs/WindowManager/Shell/tests/flicker/appcompat/AndroidTestTemplate.xml b/libs/WindowManager/Shell/tests/flicker/appcompat/AndroidTestTemplate.xml new file mode 100644 index 000000000000..1df11369a049 --- /dev/null +++ b/libs/WindowManager/Shell/tests/flicker/appcompat/AndroidTestTemplate.xml @@ -0,0 +1,109 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- + ~ Copyright (C) 2023 The Android Open Source Project + ~ + ~ Licensed under the Apache License, Version 2.0 (the "License"); + ~ you may not use this file except in compliance with the License. + ~ You may obtain a copy of the License at + ~ + ~ http://www.apache.org/licenses/LICENSE-2.0 + ~ + ~ Unless required by applicable law or agreed to in writing, software + ~ distributed under the License is distributed on an "AS IS" BASIS, + ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + ~ See the License for the specific language governing permissions and + ~ limitations under the License. + --> +<configuration description="Runs WindowManager Shell Flicker Tests {MODULE}"> + <option name="test-tag" value="FlickerTests"/> + <!-- Needed for storing the perfetto trace files in the sdcard/test_results--> + <option name="isolated-storage" value="false"/> + + <target_preparer class="com.android.tradefed.targetprep.DeviceSetup"> + <!-- keeps the screen on during tests --> + <option name="screen-always-on" value="on"/> + <!-- prevents the phone from restarting --> + <option name="force-skip-system-props" value="true"/> + <!-- set WM tracing verbose level to all --> + <option name="run-command" value="cmd window tracing level all"/> + <!-- set WM tracing to frame (avoid incomplete states) --> + <option name="run-command" value="cmd window tracing frame"/> + <!-- disable betterbug as it's log collection dialogues cause flakes in e2e tests --> + <option name="run-command" value="pm disable com.google.android.internal.betterbug"/> + <!-- ensure lock screen mode is swipe --> + <option name="run-command" value="locksettings set-disabled false"/> + <!-- restart launcher to activate TAPL --> + <option name="run-command" + value="setprop ro.test_harness 1 ; am force-stop com.google.android.apps.nexuslauncher"/> + <!-- Increase trace size: 20mb for WM and 80mb for SF --> + <option name="run-command" value="cmd window tracing size 20480"/> + <option name="run-command" value="su root service call SurfaceFlinger 1029 i32 81920"/> + </target_preparer> + <target_preparer class="com.android.tradefed.targetprep.RunCommandTargetPreparer"> + <option name="test-user-token" value="%TEST_USER%"/> + <option name="run-command" value="rm -rf /data/user/%TEST_USER%/files/*"/> + <option name="run-command" value="settings put secure show_ime_with_hard_keyboard 1"/> + <option name="run-command" value="settings put system show_touches 1"/> + <option name="run-command" value="settings put system pointer_location 1"/> + <option name="teardown-command" + value="settings delete secure show_ime_with_hard_keyboard"/> + <option name="teardown-command" value="settings delete system show_touches"/> + <option name="teardown-command" value="settings delete system pointer_location"/> + <option name="teardown-command" + value="cmd overlay enable com.android.internal.systemui.navbar.gestural"/> + </target_preparer> + <target_preparer class="com.android.tradefed.targetprep.suite.SuiteApkInstaller"> + <option name="cleanup-apks" value="true"/> + <option name="test-file-name" value="{MODULE}.apk"/> + <option name="test-file-name" value="FlickerTestApp.apk"/> + </target_preparer> + <!-- Enable mocking GPS location by the test app --> + <target_preparer class="com.android.tradefed.targetprep.RunCommandTargetPreparer"> + <option name="run-command" + value="appops set com.android.wm.shell.flicker.pip.apps android:mock_location allow"/> + <option name="teardown-command" + value="appops set com.android.wm.shell.flicker.pip.apps android:mock_location deny"/> + </target_preparer> + + <!-- Needed for pushing the trace config file --> + <target_preparer class="com.android.tradefed.targetprep.RootTargetPreparer"/> + <target_preparer class="com.android.tradefed.targetprep.PushFilePreparer"> + <option name="push-file" + key="trace_config.textproto" + value="/data/misc/perfetto-traces/trace_config.textproto" + /> + <!--Install the content provider automatically when we push some file in sdcard folder.--> + <!--Needed to avoid the installation during the test suite.--> + <option name="push-file" key="trace_config.textproto" value="/sdcard/sample.textproto"/> + </target_preparer> + <test class="com.android.tradefed.testtype.AndroidJUnitTest"> + <option name="package" value="{PACKAGE}"/> + <option name="shell-timeout" value="6600s"/> + <option name="test-timeout" value="6000s"/> + <option name="hidden-api-checks" value="false"/> + <option name="device-listeners" value="android.device.collectors.PerfettoListener"/> + <!-- PerfettoListener related arguments --> + <option name="instrumentation-arg" key="perfetto_config_text_proto" value="true"/> + <option name="instrumentation-arg" + key="perfetto_config_file" + value="trace_config.textproto" + /> + <option name="instrumentation-arg" key="per_run" value="true"/> + </test> + <!-- Needed for pulling the collected trace config on to the host --> + <metrics_collector class="com.android.tradefed.device.metric.FilePullerLogCollector"> + <option name="pull-pattern-keys" value="perfetto_file_path"/> + <option name="directory-keys" + value="/data/user/0/com.android.wm.shell.flicker/files"/> + <option name="directory-keys" + value="/data/user/0/com.android.wm.shell.flicker.bubbles/files"/> + <option name="directory-keys" + value="/data/user/0/com.android.wm.shell.flicker.pip/files"/> + <option name="directory-keys" + value="/data/user/0/com.android.wm.shell.flicker.splitscreen/files"/> + <option name="directory-keys" + value="/data/user/0/com.android.wm.shell.flicker.service/files"/> + <option name="collect-on-run-ended-only" value="true"/> + <option name="clean-up" value="true"/> + </metrics_collector> +</configuration> diff --git a/libs/WindowManager/Shell/tests/flicker/res/xml/network_security_config.xml b/libs/WindowManager/Shell/tests/flicker/appcompat/res/xml/network_security_config.xml index 4bd9ca049f55..4bd9ca049f55 100644 --- a/libs/WindowManager/Shell/tests/flicker/res/xml/network_security_config.xml +++ b/libs/WindowManager/Shell/tests/flicker/appcompat/res/xml/network_security_config.xml diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/appcompat/BaseAppCompat.kt b/libs/WindowManager/Shell/tests/flicker/appcompat/src/com/android/wm/shell/flicker/appcompat/BaseAppCompat.kt index adf92d8854ff..adf92d8854ff 100644 --- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/appcompat/BaseAppCompat.kt +++ b/libs/WindowManager/Shell/tests/flicker/appcompat/src/com/android/wm/shell/flicker/appcompat/BaseAppCompat.kt diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/appcompat/LetterboxRule.kt b/libs/WindowManager/Shell/tests/flicker/appcompat/src/com/android/wm/shell/flicker/appcompat/LetterboxRule.kt index 744e8c2eb06f..744e8c2eb06f 100644 --- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/appcompat/LetterboxRule.kt +++ b/libs/WindowManager/Shell/tests/flicker/appcompat/src/com/android/wm/shell/flicker/appcompat/LetterboxRule.kt diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/appcompat/OpenAppInSizeCompatModeTest.kt b/libs/WindowManager/Shell/tests/flicker/appcompat/src/com/android/wm/shell/flicker/appcompat/OpenAppInSizeCompatModeTest.kt index 1e5e42fb077e..1e5e42fb077e 100644 --- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/appcompat/OpenAppInSizeCompatModeTest.kt +++ b/libs/WindowManager/Shell/tests/flicker/appcompat/src/com/android/wm/shell/flicker/appcompat/OpenAppInSizeCompatModeTest.kt diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/appcompat/OpenTransparentActivityTest.kt b/libs/WindowManager/Shell/tests/flicker/appcompat/src/com/android/wm/shell/flicker/appcompat/OpenTransparentActivityTest.kt index 2fa1ec386781..2fa1ec386781 100644 --- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/appcompat/OpenTransparentActivityTest.kt +++ b/libs/WindowManager/Shell/tests/flicker/appcompat/src/com/android/wm/shell/flicker/appcompat/OpenTransparentActivityTest.kt diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/appcompat/QuickSwitchLauncherToLetterboxAppTest.kt b/libs/WindowManager/Shell/tests/flicker/appcompat/src/com/android/wm/shell/flicker/appcompat/QuickSwitchLauncherToLetterboxAppTest.kt index b74aa1d7bf73..b74aa1d7bf73 100644 --- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/appcompat/QuickSwitchLauncherToLetterboxAppTest.kt +++ b/libs/WindowManager/Shell/tests/flicker/appcompat/src/com/android/wm/shell/flicker/appcompat/QuickSwitchLauncherToLetterboxAppTest.kt diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/appcompat/RepositionFixedPortraitAppTest.kt b/libs/WindowManager/Shell/tests/flicker/appcompat/src/com/android/wm/shell/flicker/appcompat/RepositionFixedPortraitAppTest.kt index 68fa8d2fc2e8..68fa8d2fc2e8 100644 --- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/appcompat/RepositionFixedPortraitAppTest.kt +++ b/libs/WindowManager/Shell/tests/flicker/appcompat/src/com/android/wm/shell/flicker/appcompat/RepositionFixedPortraitAppTest.kt diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/appcompat/RestartAppInSizeCompatModeTest.kt b/libs/WindowManager/Shell/tests/flicker/appcompat/src/com/android/wm/shell/flicker/appcompat/RestartAppInSizeCompatModeTest.kt index fcb6931af9a2..fcb6931af9a2 100644 --- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/appcompat/RestartAppInSizeCompatModeTest.kt +++ b/libs/WindowManager/Shell/tests/flicker/appcompat/src/com/android/wm/shell/flicker/appcompat/RestartAppInSizeCompatModeTest.kt diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/appcompat/RotateImmersiveAppInFullscreenTest.kt b/libs/WindowManager/Shell/tests/flicker/appcompat/src/com/android/wm/shell/flicker/appcompat/RotateImmersiveAppInFullscreenTest.kt index ba2b3e7e2781..446aad8a8936 100644 --- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/appcompat/RotateImmersiveAppInFullscreenTest.kt +++ b/libs/WindowManager/Shell/tests/flicker/appcompat/src/com/android/wm/shell/flicker/appcompat/RotateImmersiveAppInFullscreenTest.kt @@ -17,11 +17,11 @@ package com.android.wm.shell.flicker.appcompat import android.os.Build -import android.tools.common.datatypes.Rect import android.platform.test.annotations.Postsubmit import android.system.helpers.CommandsHelper import android.tools.common.NavBar import android.tools.common.Rotation +import android.tools.common.datatypes.Rect import android.tools.common.flicker.assertions.FlickerTest import android.tools.common.traces.component.ComponentNameMatcher import android.tools.device.flicker.junit.FlickerParametersRunnerFactory @@ -65,10 +65,12 @@ import org.junit.runners.Parameterized @Parameterized.UseParametersRunnerFactory(FlickerParametersRunnerFactory::class) class RotateImmersiveAppInFullscreenTest(flicker: LegacyFlickerTest) : BaseAppCompat(flicker) { - private val immersiveApp = LetterboxAppHelper(instrumentation, + private val immersiveApp = + LetterboxAppHelper( + instrumentation, launcherName = ActivityOptions.PortraitImmersiveActivity.LABEL, - component = - ActivityOptions.PortraitImmersiveActivity.COMPONENT.toFlickerComponent()) + component = ActivityOptions.PortraitImmersiveActivity.COMPONENT.toFlickerComponent() + ) private val cmdHelper: CommandsHelper = CommandsHelper.getInstance(instrumentation) private val execAdb: (String) -> String = { cmd -> cmdHelper.executeShellCommand(cmd) } @@ -84,8 +86,8 @@ class RotateImmersiveAppInFullscreenTest(flicker: LegacyFlickerTest) : BaseAppCo setStartRotation() immersiveApp.launchViaIntent(wmHelper) startDisplayBounds = - wmHelper.currentState.layerState.physicalDisplayBounds - ?: error("Display not found") + wmHelper.currentState.layerState.physicalDisplayBounds + ?: error("Display not found") } transitions { if (isCuttlefishDevice) { @@ -96,12 +98,10 @@ class RotateImmersiveAppInFullscreenTest(flicker: LegacyFlickerTest) : BaseAppCo val rotationButtonSelector = By.res(LAUNCHER_PACKAGE, "rotate_suggestion") uiDevice.wait(Until.hasObject(rotationButtonSelector), FIND_TIMEOUT) uiDevice.findObject(rotationButtonSelector) - ?: error("rotation button not found") + ?: error("rotation button not found") } } - teardown { - immersiveApp.exit(wmHelper) - } + teardown { immersiveApp.exit(wmHelper) } } @Before @@ -112,48 +112,40 @@ class RotateImmersiveAppInFullscreenTest(flicker: LegacyFlickerTest) : BaseAppCo /** {@inheritDoc} */ @Test @Ignore("Not applicable to this CUJ. App is in immersive mode.") - override fun taskBarLayerIsVisibleAtStartAndEnd() { - } + override fun taskBarLayerIsVisibleAtStartAndEnd() {} /** {@inheritDoc} */ @Test @Ignore("Not applicable to this CUJ. App is in immersive mode.") - override fun navBarLayerIsVisibleAtStartAndEnd() { - } + override fun navBarLayerIsVisibleAtStartAndEnd() {} /** {@inheritDoc} */ @Test @Ignore("Not applicable to this CUJ. App is in immersive mode.") - override fun statusBarLayerIsVisibleAtStartAndEnd() { - } + override fun statusBarLayerIsVisibleAtStartAndEnd() {} /** {@inheritDoc} */ @Test @Ignore("Not applicable to this CUJ. App is in immersive mode.") - override fun taskBarWindowIsAlwaysVisible() { - } + override fun taskBarWindowIsAlwaysVisible() {} /** {@inheritDoc} */ @Test @Ignore("Not applicable to this CUJ. App is in immersive mode.") - override fun navBarWindowIsAlwaysVisible() { - } + override fun navBarWindowIsAlwaysVisible() {} /** {@inheritDoc} */ @Test @Ignore("Not applicable to this CUJ. App is in immersive mode.") - override fun statusBarWindowIsAlwaysVisible() { - } + override fun statusBarWindowIsAlwaysVisible() {} @Test @Ignore("Not applicable to this CUJ. App is in immersive mode.") - override fun statusBarLayerPositionAtStartAndEnd() { - } + override fun statusBarLayerPositionAtStartAndEnd() {} @Test @Ignore("Not applicable to this CUJ. App is in immersive mode.") - override fun visibleWindowsShownMoreThanOneConsecutiveEntry() { - } + override fun visibleWindowsShownMoreThanOneConsecutiveEntry() {} /** Test that app is fullscreen by checking status bar and task bar visibility. */ @Postsubmit @@ -161,8 +153,9 @@ class RotateImmersiveAppInFullscreenTest(flicker: LegacyFlickerTest) : BaseAppCo fun appWindowFullScreen() { flicker.assertWmEnd { this.isAppWindowInvisible(ComponentNameMatcher.STATUS_BAR) - .isAppWindowInvisible(ComponentNameMatcher.TASK_BAR) - .visibleRegion(immersiveApp).coversExactly(startDisplayBounds) + .isAppWindowInvisible(ComponentNameMatcher.TASK_BAR) + .visibleRegion(immersiveApp) + .coversExactly(startDisplayBounds) } } @@ -170,9 +163,7 @@ class RotateImmersiveAppInFullscreenTest(flicker: LegacyFlickerTest) : BaseAppCo @Postsubmit @Test fun appInOriginalRotation() { - flicker.assertWmEnd { - this.hasRotation(Rotation.ROTATION_90) - } + flicker.assertWmEnd { this.hasRotation(Rotation.ROTATION_90) } } companion object { @@ -189,10 +180,10 @@ class RotateImmersiveAppInFullscreenTest(flicker: LegacyFlickerTest) : BaseAppCo @JvmStatic fun getParams(): Collection<FlickerTest> { return LegacyFlickerTestFactory.nonRotationTests( - supportedRotations = listOf(Rotation.ROTATION_90), - // TODO(b/292403378): 3 button mode not added as rotation button is hidden in taskbar - supportedNavigationModes = listOf(NavBar.MODE_GESTURAL) - + supportedRotations = listOf(Rotation.ROTATION_90), + // TODO(b/292403378): 3 button mode not added as rotation button is hidden in + // taskbar + supportedNavigationModes = listOf(NavBar.MODE_GESTURAL) ) } } diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/appcompat/TransparentBaseAppCompat.kt b/libs/WindowManager/Shell/tests/flicker/appcompat/src/com/android/wm/shell/flicker/appcompat/TransparentBaseAppCompat.kt index 9792c859cced..9792c859cced 100644 --- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/appcompat/TransparentBaseAppCompat.kt +++ b/libs/WindowManager/Shell/tests/flicker/appcompat/src/com/android/wm/shell/flicker/appcompat/TransparentBaseAppCompat.kt diff --git a/libs/WindowManager/Shell/tests/flicker/appcompat/trace_config/trace_config.textproto b/libs/WindowManager/Shell/tests/flicker/appcompat/trace_config/trace_config.textproto new file mode 100644 index 000000000000..406ada97a07d --- /dev/null +++ b/libs/WindowManager/Shell/tests/flicker/appcompat/trace_config/trace_config.textproto @@ -0,0 +1,75 @@ +# 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. + +# proto-message: TraceConfig + +# Enable periodic flushing of the trace buffer into the output file. +write_into_file: true + +# Writes the userspace buffer into the file every 1s. +file_write_period_ms: 2500 + +# See b/126487238 - we need to guarantee ordering of events. +flush_period_ms: 30000 + +# The trace buffers needs to be big enough to hold |file_write_period_ms| of +# trace data. The trace buffer sizing depends on the number of trace categories +# enabled and the device activity. + +# RSS events +buffers: { + size_kb: 63488 + fill_policy: RING_BUFFER +} + +data_sources { + config { + name: "linux.process_stats" + target_buffer: 0 + # polled per-process memory counters and process/thread names. + # If you don't want the polled counters, remove the "process_stats_config" + # section, but keep the data source itself as it still provides on-demand + # thread/process naming for ftrace data below. + process_stats_config { + scan_all_processes_on_start: true + } + } +} + +data_sources: { + config { + name: "linux.ftrace" + ftrace_config { + ftrace_events: "ftrace/print" + ftrace_events: "task/task_newtask" + ftrace_events: "task/task_rename" + atrace_categories: "ss" + atrace_categories: "wm" + atrace_categories: "am" + atrace_categories: "aidl" + atrace_categories: "input" + atrace_categories: "binder_driver" + atrace_categories: "sched_process_exit" + atrace_apps: "com.android.server.wm.flicker.testapp" + atrace_apps: "com.android.systemui" + atrace_apps: "com.android.wm.shell.flicker" + atrace_apps: "com.android.wm.shell.flicker.other" + atrace_apps: "com.android.wm.shell.flicker.bubbles" + atrace_apps: "com.android.wm.shell.flicker.pip" + atrace_apps: "com.android.wm.shell.flicker.splitscreen" + atrace_apps: "com.google.android.apps.nexuslauncher" + } + } +} + diff --git a/libs/WindowManager/Shell/tests/flicker/bubble/Android.bp b/libs/WindowManager/Shell/tests/flicker/bubble/Android.bp new file mode 100644 index 000000000000..c4e9a8479563 --- /dev/null +++ b/libs/WindowManager/Shell/tests/flicker/bubble/Android.bp @@ -0,0 +1,34 @@ +// +// Copyright (C) 2020 The Android Open Source Project +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// + +package { + // See: http://go/android-license-faq + // A large-scale-change added 'default_applicable_licenses' to import + // all of the 'license_kinds' from "frameworks_base_license" + // to get the below license kinds: + // SPDX-license-identifier-Apache-2.0 + default_applicable_licenses: ["frameworks_base_license"], +} + +android_test { + name: "WMShellFlickerTestsBubbles", + defaults: ["WMShellFlickerTestsDefault"], + manifest: "AndroidManifest.xml", + package_name: "com.android.wm.shell.flicker.bubbles", + instrumentation_target_package: "com.android.wm.shell.flicker.bubbles", + srcs: ["src/**/*.kt"], + static_libs: ["WMShellFlickerTestsBase"], +} diff --git a/libs/WindowManager/Shell/tests/flicker/bubble/AndroidManifest.xml b/libs/WindowManager/Shell/tests/flicker/bubble/AndroidManifest.xml new file mode 100644 index 000000000000..e6e6f1b21bc3 --- /dev/null +++ b/libs/WindowManager/Shell/tests/flicker/bubble/AndroidManifest.xml @@ -0,0 +1,77 @@ +<!-- + ~ Copyright (C) 2023 The Android Open Source Project + ~ + ~ Licensed under the Apache License, Version 2.0 (the "License"); + ~ you may not use this file except in compliance with the License. + ~ You may obtain a copy of the License at + ~ + ~ http://www.apache.org/licenses/LICENSE-2.0 + ~ + ~ Unless required by applicable law or agreed to in writing, software + ~ distributed under the License is distributed on an "AS IS" BASIS, + ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + ~ See the License for the specific language governing permissions and + ~ limitations under the License. + --> + +<manifest xmlns:android="http://schemas.android.com/apk/res/android" + xmlns:tools="http://schemas.android.com/tools" + package="com.android.wm.shell.flicker.bubble"> + + <uses-sdk android:minSdkVersion="29" android:targetSdkVersion="29"/> + <!-- Read and write traces from external storage --> + <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" /> + <uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" /> + <!-- Allow the test to write directly to /sdcard/ --> + <uses-permission android:name="android.permission.MANAGE_EXTERNAL_STORAGE" /> + <!-- Write secure settings --> + <uses-permission android:name="android.permission.WRITE_SECURE_SETTINGS" /> + <!-- Capture screen contents --> + <uses-permission android:name="android.permission.ACCESS_SURFACE_FLINGER" /> + <!-- Enable / Disable tracing !--> + <uses-permission android:name="android.permission.DUMP" /> + <!-- Run layers trace --> + <uses-permission android:name="android.permission.HARDWARE_TEST"/> + <!-- Capture screen recording --> + <uses-permission android:name="android.permission.CAPTURE_VIDEO_OUTPUT"/> + <!-- Workaround grant runtime permission exception from b/152733071 --> + <uses-permission android:name="android.permission.PACKAGE_USAGE_STATS"/> + <uses-permission android:name="android.permission.READ_LOGS"/> + <!-- Force-stop test apps --> + <uses-permission android:name="android.permission.FORCE_STOP_PACKAGES"/> + <!-- Control test app's media session --> + <uses-permission android:name="android.permission.MEDIA_CONTENT_CONTROL"/> + <!-- ATM.removeRootTasksWithActivityTypes() --> + <uses-permission android:name="android.permission.MANAGE_ACTIVITY_TASKS" /> + <!-- Enable bubble notification--> + <uses-permission android:name="android.permission.STATUS_BAR_SERVICE" /> + <!-- Allow the test to connect to perfetto trace processor --> + <uses-permission android:name="android.permission.INTERNET"/> + + <!-- Allow the test to write directly to /sdcard/ and connect to trace processor --> + <application android:requestLegacyExternalStorage="true" + android:networkSecurityConfig="@xml/network_security_config" + android:largeHeap="true"> + <uses-library android:name="android.test.runner"/> + + <service android:name=".NotificationListener" + android:exported="true" + android:label="WMShellTestsNotificationListenerService" + android:permission="android.permission.BIND_NOTIFICATION_LISTENER_SERVICE"> + <intent-filter> + <action android:name="android.service.notification.NotificationListenerService" /> + </intent-filter> + </service> + + <!-- (b/197936012) Remove startup provider due to test timeout issue --> + <provider + android:name="androidx.startup.InitializationProvider" + android:authorities="${applicationId}.androidx-startup" + tools:node="remove" /> + </application> + + <instrumentation android:name="androidx.test.runner.AndroidJUnitRunner" + android:targetPackage="com.android.wm.shell.flicker.bubble" + android:label="WindowManager Flicker Tests"> + </instrumentation> +</manifest> diff --git a/libs/WindowManager/Shell/tests/flicker/bubble/AndroidTestTemplate.xml b/libs/WindowManager/Shell/tests/flicker/bubble/AndroidTestTemplate.xml new file mode 100644 index 000000000000..1df11369a049 --- /dev/null +++ b/libs/WindowManager/Shell/tests/flicker/bubble/AndroidTestTemplate.xml @@ -0,0 +1,109 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- + ~ Copyright (C) 2023 The Android Open Source Project + ~ + ~ Licensed under the Apache License, Version 2.0 (the "License"); + ~ you may not use this file except in compliance with the License. + ~ You may obtain a copy of the License at + ~ + ~ http://www.apache.org/licenses/LICENSE-2.0 + ~ + ~ Unless required by applicable law or agreed to in writing, software + ~ distributed under the License is distributed on an "AS IS" BASIS, + ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + ~ See the License for the specific language governing permissions and + ~ limitations under the License. + --> +<configuration description="Runs WindowManager Shell Flicker Tests {MODULE}"> + <option name="test-tag" value="FlickerTests"/> + <!-- Needed for storing the perfetto trace files in the sdcard/test_results--> + <option name="isolated-storage" value="false"/> + + <target_preparer class="com.android.tradefed.targetprep.DeviceSetup"> + <!-- keeps the screen on during tests --> + <option name="screen-always-on" value="on"/> + <!-- prevents the phone from restarting --> + <option name="force-skip-system-props" value="true"/> + <!-- set WM tracing verbose level to all --> + <option name="run-command" value="cmd window tracing level all"/> + <!-- set WM tracing to frame (avoid incomplete states) --> + <option name="run-command" value="cmd window tracing frame"/> + <!-- disable betterbug as it's log collection dialogues cause flakes in e2e tests --> + <option name="run-command" value="pm disable com.google.android.internal.betterbug"/> + <!-- ensure lock screen mode is swipe --> + <option name="run-command" value="locksettings set-disabled false"/> + <!-- restart launcher to activate TAPL --> + <option name="run-command" + value="setprop ro.test_harness 1 ; am force-stop com.google.android.apps.nexuslauncher"/> + <!-- Increase trace size: 20mb for WM and 80mb for SF --> + <option name="run-command" value="cmd window tracing size 20480"/> + <option name="run-command" value="su root service call SurfaceFlinger 1029 i32 81920"/> + </target_preparer> + <target_preparer class="com.android.tradefed.targetprep.RunCommandTargetPreparer"> + <option name="test-user-token" value="%TEST_USER%"/> + <option name="run-command" value="rm -rf /data/user/%TEST_USER%/files/*"/> + <option name="run-command" value="settings put secure show_ime_with_hard_keyboard 1"/> + <option name="run-command" value="settings put system show_touches 1"/> + <option name="run-command" value="settings put system pointer_location 1"/> + <option name="teardown-command" + value="settings delete secure show_ime_with_hard_keyboard"/> + <option name="teardown-command" value="settings delete system show_touches"/> + <option name="teardown-command" value="settings delete system pointer_location"/> + <option name="teardown-command" + value="cmd overlay enable com.android.internal.systemui.navbar.gestural"/> + </target_preparer> + <target_preparer class="com.android.tradefed.targetprep.suite.SuiteApkInstaller"> + <option name="cleanup-apks" value="true"/> + <option name="test-file-name" value="{MODULE}.apk"/> + <option name="test-file-name" value="FlickerTestApp.apk"/> + </target_preparer> + <!-- Enable mocking GPS location by the test app --> + <target_preparer class="com.android.tradefed.targetprep.RunCommandTargetPreparer"> + <option name="run-command" + value="appops set com.android.wm.shell.flicker.pip.apps android:mock_location allow"/> + <option name="teardown-command" + value="appops set com.android.wm.shell.flicker.pip.apps android:mock_location deny"/> + </target_preparer> + + <!-- Needed for pushing the trace config file --> + <target_preparer class="com.android.tradefed.targetprep.RootTargetPreparer"/> + <target_preparer class="com.android.tradefed.targetprep.PushFilePreparer"> + <option name="push-file" + key="trace_config.textproto" + value="/data/misc/perfetto-traces/trace_config.textproto" + /> + <!--Install the content provider automatically when we push some file in sdcard folder.--> + <!--Needed to avoid the installation during the test suite.--> + <option name="push-file" key="trace_config.textproto" value="/sdcard/sample.textproto"/> + </target_preparer> + <test class="com.android.tradefed.testtype.AndroidJUnitTest"> + <option name="package" value="{PACKAGE}"/> + <option name="shell-timeout" value="6600s"/> + <option name="test-timeout" value="6000s"/> + <option name="hidden-api-checks" value="false"/> + <option name="device-listeners" value="android.device.collectors.PerfettoListener"/> + <!-- PerfettoListener related arguments --> + <option name="instrumentation-arg" key="perfetto_config_text_proto" value="true"/> + <option name="instrumentation-arg" + key="perfetto_config_file" + value="trace_config.textproto" + /> + <option name="instrumentation-arg" key="per_run" value="true"/> + </test> + <!-- Needed for pulling the collected trace config on to the host --> + <metrics_collector class="com.android.tradefed.device.metric.FilePullerLogCollector"> + <option name="pull-pattern-keys" value="perfetto_file_path"/> + <option name="directory-keys" + value="/data/user/0/com.android.wm.shell.flicker/files"/> + <option name="directory-keys" + value="/data/user/0/com.android.wm.shell.flicker.bubbles/files"/> + <option name="directory-keys" + value="/data/user/0/com.android.wm.shell.flicker.pip/files"/> + <option name="directory-keys" + value="/data/user/0/com.android.wm.shell.flicker.splitscreen/files"/> + <option name="directory-keys" + value="/data/user/0/com.android.wm.shell.flicker.service/files"/> + <option name="collect-on-run-ended-only" value="true"/> + <option name="clean-up" value="true"/> + </metrics_collector> +</configuration> diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/bubble/OWNERS b/libs/WindowManager/Shell/tests/flicker/bubble/OWNERS index 566acc87e42d..566acc87e42d 100644 --- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/bubble/OWNERS +++ b/libs/WindowManager/Shell/tests/flicker/bubble/OWNERS diff --git a/libs/WindowManager/Shell/tests/flicker/manifests/AndroidManifestOther.xml b/libs/WindowManager/Shell/tests/flicker/bubble/res/xml/network_security_config.xml index cf642f63a41d..4bd9ca049f55 100644 --- a/libs/WindowManager/Shell/tests/flicker/manifests/AndroidManifestOther.xml +++ b/libs/WindowManager/Shell/tests/flicker/bubble/res/xml/network_security_config.xml @@ -1,3 +1,4 @@ +<?xml version="1.0" encoding="utf-8"?> <!-- ~ Copyright (C) 2023 The Android Open Source Project ~ @@ -14,11 +15,8 @@ ~ limitations under the License. --> -<manifest xmlns:android="http://schemas.android.com/apk/res/android" - package="com.android.wm.shell.flicker"> - - <instrumentation android:name="androidx.test.runner.AndroidJUnitRunner" - android:targetPackage="com.android.wm.shell.flicker" - android:label="WindowManager Flicker Tests"> - </instrumentation> -</manifest> +<network-security-config> + <domain-config cleartextTrafficPermitted="true"> + <domain includeSubdomains="true">localhost</domain> + </domain-config> +</network-security-config> diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/bubble/BaseBubbleScreen.kt b/libs/WindowManager/Shell/tests/flicker/bubble/src/com/android/wm/shell/flicker/bubble/BaseBubbleScreen.kt index bc095bbacc5a..0c36e29a8315 100644 --- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/bubble/BaseBubbleScreen.kt +++ b/libs/WindowManager/Shell/tests/flicker/bubble/src/com/android/wm/shell/flicker/bubble/BaseBubbleScreen.kt @@ -58,8 +58,9 @@ abstract class BaseBubbleScreen(flicker: LegacyFlickerTest) : BaseTest(flicker) return { setup { MultiWindowUtils.executeShellCommand( - instrumentation, - "settings put secure force_hide_bubbles_user_education 1") + instrumentation, + "settings put secure force_hide_bubbles_user_education 1" + ) notifyManager.setBubblesAllowed( testApp.packageName, uid, @@ -72,8 +73,9 @@ abstract class BaseBubbleScreen(flicker: LegacyFlickerTest) : BaseTest(flicker) teardown { MultiWindowUtils.executeShellCommand( - instrumentation, - "settings put secure force_hide_bubbles_user_education 0") + instrumentation, + "settings put secure force_hide_bubbles_user_education 0" + ) notifyManager.setBubblesAllowed( testApp.packageName, uid, diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/bubble/ChangeActiveActivityFromBubbleTest.kt b/libs/WindowManager/Shell/tests/flicker/bubble/src/com/android/wm/shell/flicker/bubble/ChangeActiveActivityFromBubbleTest.kt index 55039f59190b..55039f59190b 100644 --- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/bubble/ChangeActiveActivityFromBubbleTest.kt +++ b/libs/WindowManager/Shell/tests/flicker/bubble/src/com/android/wm/shell/flicker/bubble/ChangeActiveActivityFromBubbleTest.kt diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/bubble/DragToDismissBubbleScreenTest.kt b/libs/WindowManager/Shell/tests/flicker/bubble/src/com/android/wm/shell/flicker/bubble/DragToDismissBubbleScreenTest.kt index 9ca7bf113589..9ca7bf113589 100644 --- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/bubble/DragToDismissBubbleScreenTest.kt +++ b/libs/WindowManager/Shell/tests/flicker/bubble/src/com/android/wm/shell/flicker/bubble/DragToDismissBubbleScreenTest.kt diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/bubble/OpenActivityFromBubbleOnLocksreenTest.kt b/libs/WindowManager/Shell/tests/flicker/bubble/src/com/android/wm/shell/flicker/bubble/OpenActivityFromBubbleOnLocksreenTest.kt index b007e6b3535c..b007e6b3535c 100644 --- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/bubble/OpenActivityFromBubbleOnLocksreenTest.kt +++ b/libs/WindowManager/Shell/tests/flicker/bubble/src/com/android/wm/shell/flicker/bubble/OpenActivityFromBubbleOnLocksreenTest.kt diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/bubble/OpenActivityFromBubbleTest.kt b/libs/WindowManager/Shell/tests/flicker/bubble/src/com/android/wm/shell/flicker/bubble/OpenActivityFromBubbleTest.kt index 4959672d865b..4959672d865b 100644 --- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/bubble/OpenActivityFromBubbleTest.kt +++ b/libs/WindowManager/Shell/tests/flicker/bubble/src/com/android/wm/shell/flicker/bubble/OpenActivityFromBubbleTest.kt diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/bubble/SendBubbleNotificationTest.kt b/libs/WindowManager/Shell/tests/flicker/bubble/src/com/android/wm/shell/flicker/bubble/SendBubbleNotificationTest.kt index 0d95574aca06..0d95574aca06 100644 --- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/bubble/SendBubbleNotificationTest.kt +++ b/libs/WindowManager/Shell/tests/flicker/bubble/src/com/android/wm/shell/flicker/bubble/SendBubbleNotificationTest.kt diff --git a/libs/WindowManager/Shell/tests/flicker/bubble/trace_config/trace_config.textproto b/libs/WindowManager/Shell/tests/flicker/bubble/trace_config/trace_config.textproto new file mode 100644 index 000000000000..406ada97a07d --- /dev/null +++ b/libs/WindowManager/Shell/tests/flicker/bubble/trace_config/trace_config.textproto @@ -0,0 +1,75 @@ +# 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. + +# proto-message: TraceConfig + +# Enable periodic flushing of the trace buffer into the output file. +write_into_file: true + +# Writes the userspace buffer into the file every 1s. +file_write_period_ms: 2500 + +# See b/126487238 - we need to guarantee ordering of events. +flush_period_ms: 30000 + +# The trace buffers needs to be big enough to hold |file_write_period_ms| of +# trace data. The trace buffer sizing depends on the number of trace categories +# enabled and the device activity. + +# RSS events +buffers: { + size_kb: 63488 + fill_policy: RING_BUFFER +} + +data_sources { + config { + name: "linux.process_stats" + target_buffer: 0 + # polled per-process memory counters and process/thread names. + # If you don't want the polled counters, remove the "process_stats_config" + # section, but keep the data source itself as it still provides on-demand + # thread/process naming for ftrace data below. + process_stats_config { + scan_all_processes_on_start: true + } + } +} + +data_sources: { + config { + name: "linux.ftrace" + ftrace_config { + ftrace_events: "ftrace/print" + ftrace_events: "task/task_newtask" + ftrace_events: "task/task_rename" + atrace_categories: "ss" + atrace_categories: "wm" + atrace_categories: "am" + atrace_categories: "aidl" + atrace_categories: "input" + atrace_categories: "binder_driver" + atrace_categories: "sched_process_exit" + atrace_apps: "com.android.server.wm.flicker.testapp" + atrace_apps: "com.android.systemui" + atrace_apps: "com.android.wm.shell.flicker" + atrace_apps: "com.android.wm.shell.flicker.other" + atrace_apps: "com.android.wm.shell.flicker.bubbles" + atrace_apps: "com.android.wm.shell.flicker.pip" + atrace_apps: "com.android.wm.shell.flicker.splitscreen" + atrace_apps: "com.google.android.apps.nexuslauncher" + } + } +} + diff --git a/libs/WindowManager/Shell/tests/flicker/manifests/AndroidManifestPip.xml b/libs/WindowManager/Shell/tests/flicker/manifests/AndroidManifestPip.xml deleted file mode 100644 index fa42a4570b7d..000000000000 --- a/libs/WindowManager/Shell/tests/flicker/manifests/AndroidManifestPip.xml +++ /dev/null @@ -1,27 +0,0 @@ -<!-- - ~ Copyright (C) 2023 The Android Open Source Project - ~ - ~ Licensed under the Apache License, Version 2.0 (the "License"); - ~ you may not use this file except in compliance with the License. - ~ You may obtain a copy of the License at - ~ - ~ http://www.apache.org/licenses/LICENSE-2.0 - ~ - ~ Unless required by applicable law or agreed to in writing, software - ~ distributed under the License is distributed on an "AS IS" BASIS, - ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - ~ See the License for the specific language governing permissions and - ~ limitations under the License. - --> - -<manifest xmlns:android="http://schemas.android.com/apk/res/android" - package="com.android.wm.shell.flicker.pip"> - - <!-- Enable mocking GPS location --> - <uses-permission android:name="android.permission.ACCESS_MOCK_LOCATION"/> - - <instrumentation android:name="androidx.test.runner.AndroidJUnitRunner" - android:targetPackage="com.android.wm.shell.flicker.pip" - android:label="WindowManager Flicker Tests"> - </instrumentation> -</manifest> diff --git a/libs/WindowManager/Shell/tests/flicker/pip/Android.bp b/libs/WindowManager/Shell/tests/flicker/pip/Android.bp new file mode 100644 index 000000000000..386983ce6aae --- /dev/null +++ b/libs/WindowManager/Shell/tests/flicker/pip/Android.bp @@ -0,0 +1,136 @@ +// +// Copyright (C) 2020 The Android Open Source Project +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// + +package { + // See: http://go/android-license-faq + // A large-scale-change added 'default_applicable_licenses' to import + // all of the 'license_kinds' from "frameworks_base_license" + // to get the below license kinds: + // SPDX-license-identifier-Apache-2.0 + default_applicable_licenses: ["frameworks_base_license"], +} + +filegroup { + name: "WMShellFlickerTestsPip1-src", + srcs: [ + "src/**/A*.kt", + "src/**/B*.kt", + "src/**/C*.kt", + "src/**/D*.kt", + "src/**/S*.kt", + ], +} + +filegroup { + name: "WMShellFlickerTestsPip2-src", + srcs: [ + "src/**/E*.kt", + ], +} + +filegroup { + name: "WMShellFlickerTestsPip3-src", + srcs: ["src/**/*.kt"], +} + +filegroup { + name: "WMShellFlickerTestsPipCommon-src", + srcs: ["src/**/common/*.kt"], +} + +filegroup { + name: "WMShellFlickerTestsPipApps-src", + srcs: ["src/**/apps/*.kt"], +} + +android_test { + name: "WMShellFlickerTestsPip1", + defaults: ["WMShellFlickerTestsDefault"], + manifest: "AndroidManifest.xml", + package_name: "com.android.wm.shell.flicker.pip", + instrumentation_target_package: "com.android.wm.shell.flicker.pip", + srcs: [ + ":WMShellFlickerTestsPip1-src", + ":WMShellFlickerTestsPipCommon-src", + ], + static_libs: ["WMShellFlickerTestsBase"], +} + +android_test { + name: "WMShellFlickerTestsPip2", + defaults: ["WMShellFlickerTestsDefault"], + manifest: "AndroidManifest.xml", + package_name: "com.android.wm.shell.flicker.pip", + instrumentation_target_package: "com.android.wm.shell.flicker.pip", + srcs: [ + ":WMShellFlickerTestsPip2-src", + ":WMShellFlickerTestsPipCommon-src", + ], + static_libs: ["WMShellFlickerTestsBase"], +} + +android_test { + name: "WMShellFlickerTestsPip3", + defaults: ["WMShellFlickerTestsDefault"], + manifest: "AndroidManifest.xml", + package_name: "com.android.wm.shell.flicker.pip", + instrumentation_target_package: "com.android.wm.shell.flicker.pip", + srcs: [ + ":WMShellFlickerTestsPip3-src", + ":WMShellFlickerTestsPipCommon-src", + ], + exclude_srcs: [ + ":WMShellFlickerTestsPip1-src", + ":WMShellFlickerTestsPip2-src", + ":WMShellFlickerTestsPipApps-src", + ], + static_libs: ["WMShellFlickerTestsBase"], +} + +android_test { + name: "WMShellFlickerTestsPipApps", + defaults: ["WMShellFlickerTestsDefault"], + manifest: "AndroidManifest.xml", + package_name: "com.android.wm.shell.flicker.pip.apps", + instrumentation_target_package: "com.android.wm.shell.flicker.pip.apps", + srcs: [ + ":WMShellFlickerTestsPipApps-src", + ":WMShellFlickerTestsPipCommon-src", + ], + static_libs: ["WMShellFlickerTestsBase"], +} + +android_test { + name: "WMShellFlickerTestsPipAppsCSuite", + defaults: ["WMShellFlickerTestsDefaultWithoutTemplate"], + additional_manifests: ["AndroidManifest.xml"], + package_name: "com.android.wm.shell.flicker.pip.apps", + instrumentation_target_package: "com.android.wm.shell.flicker.pip.apps", + srcs: [ + ":WMShellFlickerTestsPipApps-src", + ":WMShellFlickerTestsPipCommon-src", + ], + static_libs: ["WMShellFlickerTestsBase"], + test_suites: [ + "device-tests", + "csuite", + ], +} + +csuite_test { + name: "csuite-1p3p-pip-flickers", + test_config_template: "csuiteDefaultTemplate.xml", +} diff --git a/libs/WindowManager/Shell/tests/flicker/pip/AndroidManifest.xml b/libs/WindowManager/Shell/tests/flicker/pip/AndroidManifest.xml new file mode 100644 index 000000000000..6d5423b28f39 --- /dev/null +++ b/libs/WindowManager/Shell/tests/flicker/pip/AndroidManifest.xml @@ -0,0 +1,80 @@ +<!-- + ~ Copyright (C) 2023 The Android Open Source Project + ~ + ~ Licensed under the Apache License, Version 2.0 (the "License"); + ~ you may not use this file except in compliance with the License. + ~ You may obtain a copy of the License at + ~ + ~ http://www.apache.org/licenses/LICENSE-2.0 + ~ + ~ Unless required by applicable law or agreed to in writing, software + ~ distributed under the License is distributed on an "AS IS" BASIS, + ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + ~ See the License for the specific language governing permissions and + ~ limitations under the License. + --> + +<manifest xmlns:android="http://schemas.android.com/apk/res/android" + xmlns:tools="http://schemas.android.com/tools" + package="com.android.wm.shell.flicker.pip"> + + <uses-sdk android:minSdkVersion="29" android:targetSdkVersion="29"/> + <!-- Read and write traces from external storage --> + <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" /> + <uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" /> + <!-- Allow the test to write directly to /sdcard/ --> + <uses-permission android:name="android.permission.MANAGE_EXTERNAL_STORAGE" /> + <!-- Write secure settings --> + <uses-permission android:name="android.permission.WRITE_SECURE_SETTINGS" /> + <!-- Capture screen contents --> + <uses-permission android:name="android.permission.ACCESS_SURFACE_FLINGER" /> + <!-- Enable / Disable tracing !--> + <uses-permission android:name="android.permission.DUMP" /> + <!-- Run layers trace --> + <uses-permission android:name="android.permission.HARDWARE_TEST"/> + <!-- Capture screen recording --> + <uses-permission android:name="android.permission.CAPTURE_VIDEO_OUTPUT"/> + <!-- Workaround grant runtime permission exception from b/152733071 --> + <uses-permission android:name="android.permission.PACKAGE_USAGE_STATS"/> + <uses-permission android:name="android.permission.READ_LOGS"/> + <!-- Force-stop test apps --> + <uses-permission android:name="android.permission.FORCE_STOP_PACKAGES"/> + <!-- Control test app's media session --> + <uses-permission android:name="android.permission.MEDIA_CONTENT_CONTROL"/> + <!-- ATM.removeRootTasksWithActivityTypes() --> + <uses-permission android:name="android.permission.MANAGE_ACTIVITY_TASKS" /> + <!-- Enable bubble notification--> + <uses-permission android:name="android.permission.STATUS_BAR_SERVICE" /> + <!-- Allow the test to connect to perfetto trace processor --> + <uses-permission android:name="android.permission.INTERNET"/> + + <!-- Allow the test to write directly to /sdcard/ and connect to trace processor --> + <application android:requestLegacyExternalStorage="true" + android:networkSecurityConfig="@xml/network_security_config" + android:largeHeap="true"> + <uses-library android:name="android.test.runner"/> + + <service android:name=".NotificationListener" + android:exported="true" + android:label="WMShellTestsNotificationListenerService" + android:permission="android.permission.BIND_NOTIFICATION_LISTENER_SERVICE"> + <intent-filter> + <action android:name="android.service.notification.NotificationListenerService" /> + </intent-filter> + </service> + + <!-- (b/197936012) Remove startup provider due to test timeout issue --> + <provider + android:name="androidx.startup.InitializationProvider" + android:authorities="${applicationId}.androidx-startup" + tools:node="remove" /> + </application> + + <!-- Enable mocking GPS location --> + <uses-permission android:name="android.permission.ACCESS_MOCK_LOCATION"/> + + <instrumentation android:name="androidx.test.runner.AndroidJUnitRunner" + android:targetPackage="com.android.wm.shell.flicker.pip" + android:label="WindowManager Flicker Tests"> + </instrumentation> +</manifest> diff --git a/libs/WindowManager/Shell/tests/flicker/pip/AndroidTestTemplate.xml b/libs/WindowManager/Shell/tests/flicker/pip/AndroidTestTemplate.xml new file mode 100644 index 000000000000..1df11369a049 --- /dev/null +++ b/libs/WindowManager/Shell/tests/flicker/pip/AndroidTestTemplate.xml @@ -0,0 +1,109 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- + ~ Copyright (C) 2023 The Android Open Source Project + ~ + ~ Licensed under the Apache License, Version 2.0 (the "License"); + ~ you may not use this file except in compliance with the License. + ~ You may obtain a copy of the License at + ~ + ~ http://www.apache.org/licenses/LICENSE-2.0 + ~ + ~ Unless required by applicable law or agreed to in writing, software + ~ distributed under the License is distributed on an "AS IS" BASIS, + ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + ~ See the License for the specific language governing permissions and + ~ limitations under the License. + --> +<configuration description="Runs WindowManager Shell Flicker Tests {MODULE}"> + <option name="test-tag" value="FlickerTests"/> + <!-- Needed for storing the perfetto trace files in the sdcard/test_results--> + <option name="isolated-storage" value="false"/> + + <target_preparer class="com.android.tradefed.targetprep.DeviceSetup"> + <!-- keeps the screen on during tests --> + <option name="screen-always-on" value="on"/> + <!-- prevents the phone from restarting --> + <option name="force-skip-system-props" value="true"/> + <!-- set WM tracing verbose level to all --> + <option name="run-command" value="cmd window tracing level all"/> + <!-- set WM tracing to frame (avoid incomplete states) --> + <option name="run-command" value="cmd window tracing frame"/> + <!-- disable betterbug as it's log collection dialogues cause flakes in e2e tests --> + <option name="run-command" value="pm disable com.google.android.internal.betterbug"/> + <!-- ensure lock screen mode is swipe --> + <option name="run-command" value="locksettings set-disabled false"/> + <!-- restart launcher to activate TAPL --> + <option name="run-command" + value="setprop ro.test_harness 1 ; am force-stop com.google.android.apps.nexuslauncher"/> + <!-- Increase trace size: 20mb for WM and 80mb for SF --> + <option name="run-command" value="cmd window tracing size 20480"/> + <option name="run-command" value="su root service call SurfaceFlinger 1029 i32 81920"/> + </target_preparer> + <target_preparer class="com.android.tradefed.targetprep.RunCommandTargetPreparer"> + <option name="test-user-token" value="%TEST_USER%"/> + <option name="run-command" value="rm -rf /data/user/%TEST_USER%/files/*"/> + <option name="run-command" value="settings put secure show_ime_with_hard_keyboard 1"/> + <option name="run-command" value="settings put system show_touches 1"/> + <option name="run-command" value="settings put system pointer_location 1"/> + <option name="teardown-command" + value="settings delete secure show_ime_with_hard_keyboard"/> + <option name="teardown-command" value="settings delete system show_touches"/> + <option name="teardown-command" value="settings delete system pointer_location"/> + <option name="teardown-command" + value="cmd overlay enable com.android.internal.systemui.navbar.gestural"/> + </target_preparer> + <target_preparer class="com.android.tradefed.targetprep.suite.SuiteApkInstaller"> + <option name="cleanup-apks" value="true"/> + <option name="test-file-name" value="{MODULE}.apk"/> + <option name="test-file-name" value="FlickerTestApp.apk"/> + </target_preparer> + <!-- Enable mocking GPS location by the test app --> + <target_preparer class="com.android.tradefed.targetprep.RunCommandTargetPreparer"> + <option name="run-command" + value="appops set com.android.wm.shell.flicker.pip.apps android:mock_location allow"/> + <option name="teardown-command" + value="appops set com.android.wm.shell.flicker.pip.apps android:mock_location deny"/> + </target_preparer> + + <!-- Needed for pushing the trace config file --> + <target_preparer class="com.android.tradefed.targetprep.RootTargetPreparer"/> + <target_preparer class="com.android.tradefed.targetprep.PushFilePreparer"> + <option name="push-file" + key="trace_config.textproto" + value="/data/misc/perfetto-traces/trace_config.textproto" + /> + <!--Install the content provider automatically when we push some file in sdcard folder.--> + <!--Needed to avoid the installation during the test suite.--> + <option name="push-file" key="trace_config.textproto" value="/sdcard/sample.textproto"/> + </target_preparer> + <test class="com.android.tradefed.testtype.AndroidJUnitTest"> + <option name="package" value="{PACKAGE}"/> + <option name="shell-timeout" value="6600s"/> + <option name="test-timeout" value="6000s"/> + <option name="hidden-api-checks" value="false"/> + <option name="device-listeners" value="android.device.collectors.PerfettoListener"/> + <!-- PerfettoListener related arguments --> + <option name="instrumentation-arg" key="perfetto_config_text_proto" value="true"/> + <option name="instrumentation-arg" + key="perfetto_config_file" + value="trace_config.textproto" + /> + <option name="instrumentation-arg" key="per_run" value="true"/> + </test> + <!-- Needed for pulling the collected trace config on to the host --> + <metrics_collector class="com.android.tradefed.device.metric.FilePullerLogCollector"> + <option name="pull-pattern-keys" value="perfetto_file_path"/> + <option name="directory-keys" + value="/data/user/0/com.android.wm.shell.flicker/files"/> + <option name="directory-keys" + value="/data/user/0/com.android.wm.shell.flicker.bubbles/files"/> + <option name="directory-keys" + value="/data/user/0/com.android.wm.shell.flicker.pip/files"/> + <option name="directory-keys" + value="/data/user/0/com.android.wm.shell.flicker.splitscreen/files"/> + <option name="directory-keys" + value="/data/user/0/com.android.wm.shell.flicker.service/files"/> + <option name="collect-on-run-ended-only" value="true"/> + <option name="clean-up" value="true"/> + </metrics_collector> +</configuration> diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/OWNERS b/libs/WindowManager/Shell/tests/flicker/pip/OWNERS index 172e24bf4574..172e24bf4574 100644 --- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/OWNERS +++ b/libs/WindowManager/Shell/tests/flicker/pip/OWNERS diff --git a/libs/WindowManager/Shell/tests/flicker/csuiteDefaultTemplate.xml b/libs/WindowManager/Shell/tests/flicker/pip/csuiteDefaultTemplate.xml index ca182fa5a266..ca182fa5a266 100644 --- a/libs/WindowManager/Shell/tests/flicker/csuiteDefaultTemplate.xml +++ b/libs/WindowManager/Shell/tests/flicker/pip/csuiteDefaultTemplate.xml diff --git a/libs/WindowManager/Shell/tests/flicker/manifests/AndroidManifestBubbles.xml b/libs/WindowManager/Shell/tests/flicker/pip/res/xml/network_security_config.xml index 437871f1bb8f..4bd9ca049f55 100644 --- a/libs/WindowManager/Shell/tests/flicker/manifests/AndroidManifestBubbles.xml +++ b/libs/WindowManager/Shell/tests/flicker/pip/res/xml/network_security_config.xml @@ -1,3 +1,4 @@ +<?xml version="1.0" encoding="utf-8"?> <!-- ~ Copyright (C) 2023 The Android Open Source Project ~ @@ -14,11 +15,8 @@ ~ limitations under the License. --> -<manifest xmlns:android="http://schemas.android.com/apk/res/android" - package="com.android.wm.shell.flicker.bubble"> - - <instrumentation android:name="androidx.test.runner.AndroidJUnitRunner" - android:targetPackage="com.android.wm.shell.flicker.bubble" - android:label="WindowManager Flicker Tests"> - </instrumentation> -</manifest> +<network-security-config> + <domain-config cleartextTrafficPermitted="true"> + <domain includeSubdomains="true">localhost</domain> + </domain-config> +</network-security-config> diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/AutoEnterPipFromSplitScreenOnGoToHomeTest.kt b/libs/WindowManager/Shell/tests/flicker/pip/src/com/android/wm/shell/flicker/pip/AutoEnterPipFromSplitScreenOnGoToHomeTest.kt index 943b16c33a98..a5c2c8988e70 100644 --- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/AutoEnterPipFromSplitScreenOnGoToHomeTest.kt +++ b/libs/WindowManager/Shell/tests/flicker/pip/src/com/android/wm/shell/flicker/pip/AutoEnterPipFromSplitScreenOnGoToHomeTest.kt @@ -81,8 +81,13 @@ class AutoEnterPipFromSplitScreenOnGoToHomeTest(flicker: LegacyFlickerTest) : pipApp.launchViaIntent(wmHelper) tapl.goHome() SplitScreenUtils.enterSplit( - wmHelper, tapl, device, pipApp, secondAppForSplitScreen, - flicker.scenario.startRotation) + wmHelper, + tapl, + device, + pipApp, + secondAppForSplitScreen, + flicker.scenario.startRotation + ) pipApp.enableAutoEnterForPipActivity() } teardown { @@ -132,9 +137,7 @@ class AutoEnterPipFromSplitScreenOnGoToHomeTest(flicker: LegacyFlickerTest) : if (flicker.scenario.isLandscapeOrSeascapeAtStart) { flicker.assertWmVisibleRegion(pipApp) { // first check against landscape bounds then against portrait bounds - coversAtMost(displayBounds).then().coversAtMost( - portraitDisplayBounds - ) + coversAtMost(displayBounds).then().coversAtMost(portraitDisplayBounds) } } else { // always check against the display bounds which do not change during transition diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/AutoEnterPipOnGoToHomeTest.kt b/libs/WindowManager/Shell/tests/flicker/pip/src/com/android/wm/shell/flicker/pip/AutoEnterPipOnGoToHomeTest.kt index 94e3959782ed..af2db12faf3a 100644 --- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/AutoEnterPipOnGoToHomeTest.kt +++ b/libs/WindowManager/Shell/tests/flicker/pip/src/com/android/wm/shell/flicker/pip/AutoEnterPipOnGoToHomeTest.kt @@ -55,8 +55,7 @@ import org.junit.runners.Parameterized @RunWith(Parameterized::class) @Parameterized.UseParametersRunnerFactory(FlickerParametersRunnerFactory::class) @FixMethodOrder(MethodSorters.NAME_ASCENDING) -open class AutoEnterPipOnGoToHomeTest(flicker: LegacyFlickerTest) : - EnterPipTransition(flicker) { +open class AutoEnterPipOnGoToHomeTest(flicker: LegacyFlickerTest) : EnterPipTransition(flicker) { override val thisTransition: FlickerBuilder.() -> Unit = { transitions { tapl.goHome() } } override val defaultEnterPip: FlickerBuilder.() -> Unit = { @@ -66,11 +65,7 @@ open class AutoEnterPipOnGoToHomeTest(flicker: LegacyFlickerTest) : } } - override val defaultTeardown: FlickerBuilder.() -> Unit = { - teardown { - pipApp.exit(wmHelper) - } - } + override val defaultTeardown: FlickerBuilder.() -> Unit = { teardown { pipApp.exit(wmHelper) } } @FlakyTest(bugId = 293133362) @Test diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/ClosePipBySwipingDownTest.kt b/libs/WindowManager/Shell/tests/flicker/pip/src/com/android/wm/shell/flicker/pip/ClosePipBySwipingDownTest.kt index 9256725c6180..9256725c6180 100644 --- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/ClosePipBySwipingDownTest.kt +++ b/libs/WindowManager/Shell/tests/flicker/pip/src/com/android/wm/shell/flicker/pip/ClosePipBySwipingDownTest.kt diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/ClosePipWithDismissButtonTest.kt b/libs/WindowManager/Shell/tests/flicker/pip/src/com/android/wm/shell/flicker/pip/ClosePipWithDismissButtonTest.kt index 002c019eff93..002c019eff93 100644 --- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/ClosePipWithDismissButtonTest.kt +++ b/libs/WindowManager/Shell/tests/flicker/pip/src/com/android/wm/shell/flicker/pip/ClosePipWithDismissButtonTest.kt diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/EnterPipOnUserLeaveHintTest.kt b/libs/WindowManager/Shell/tests/flicker/pip/src/com/android/wm/shell/flicker/pip/EnterPipOnUserLeaveHintTest.kt index 820af9316aae..4cc9547ba2e3 100644 --- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/EnterPipOnUserLeaveHintTest.kt +++ b/libs/WindowManager/Shell/tests/flicker/pip/src/com/android/wm/shell/flicker/pip/EnterPipOnUserLeaveHintTest.kt @@ -53,11 +53,7 @@ class EnterPipOnUserLeaveHintTest(flicker: LegacyFlickerTest) : EnterPipTransiti } } - override val defaultTeardown: FlickerBuilder.() -> Unit = { - teardown { - pipApp.exit(wmHelper) - } - } + override val defaultTeardown: FlickerBuilder.() -> Unit = { teardown { pipApp.exit(wmHelper) } } @Presubmit @Test diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/EnterPipToOtherOrientation.kt b/libs/WindowManager/Shell/tests/flicker/pip/src/com/android/wm/shell/flicker/pip/EnterPipToOtherOrientation.kt index 8207b85c3e0c..8207b85c3e0c 100644 --- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/EnterPipToOtherOrientation.kt +++ b/libs/WindowManager/Shell/tests/flicker/pip/src/com/android/wm/shell/flicker/pip/EnterPipToOtherOrientation.kt diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/EnterPipViaAppUiButtonTest.kt b/libs/WindowManager/Shell/tests/flicker/pip/src/com/android/wm/shell/flicker/pip/EnterPipViaAppUiButtonTest.kt index cc943678d492..cc943678d492 100644 --- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/EnterPipViaAppUiButtonTest.kt +++ b/libs/WindowManager/Shell/tests/flicker/pip/src/com/android/wm/shell/flicker/pip/EnterPipViaAppUiButtonTest.kt diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/ExitPipToAppViaExpandButtonTest.kt b/libs/WindowManager/Shell/tests/flicker/pip/src/com/android/wm/shell/flicker/pip/ExitPipToAppViaExpandButtonTest.kt index 7da442901e40..7da442901e40 100644 --- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/ExitPipToAppViaExpandButtonTest.kt +++ b/libs/WindowManager/Shell/tests/flicker/pip/src/com/android/wm/shell/flicker/pip/ExitPipToAppViaExpandButtonTest.kt diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/ExitPipToAppViaIntentTest.kt b/libs/WindowManager/Shell/tests/flicker/pip/src/com/android/wm/shell/flicker/pip/ExitPipToAppViaIntentTest.kt index 0ad9e4c61d83..0ad9e4c61d83 100644 --- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/ExitPipToAppViaIntentTest.kt +++ b/libs/WindowManager/Shell/tests/flicker/pip/src/com/android/wm/shell/flicker/pip/ExitPipToAppViaIntentTest.kt diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/ExpandPipOnDoubleClickTest.kt b/libs/WindowManager/Shell/tests/flicker/pip/src/com/android/wm/shell/flicker/pip/ExpandPipOnDoubleClickTest.kt index 89a6c93e478c..89a6c93e478c 100644 --- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/ExpandPipOnDoubleClickTest.kt +++ b/libs/WindowManager/Shell/tests/flicker/pip/src/com/android/wm/shell/flicker/pip/ExpandPipOnDoubleClickTest.kt diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/ExpandPipOnPinchOpenTest.kt b/libs/WindowManager/Shell/tests/flicker/pip/src/com/android/wm/shell/flicker/pip/ExpandPipOnPinchOpenTest.kt index 8978af0088b8..8978af0088b8 100644 --- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/ExpandPipOnPinchOpenTest.kt +++ b/libs/WindowManager/Shell/tests/flicker/pip/src/com/android/wm/shell/flicker/pip/ExpandPipOnPinchOpenTest.kt diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/MovePipDownOnShelfHeightChange.kt b/libs/WindowManager/Shell/tests/flicker/pip/src/com/android/wm/shell/flicker/pip/MovePipDownOnShelfHeightChange.kt index 4776206724cc..4776206724cc 100644 --- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/MovePipDownOnShelfHeightChange.kt +++ b/libs/WindowManager/Shell/tests/flicker/pip/src/com/android/wm/shell/flicker/pip/MovePipDownOnShelfHeightChange.kt diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/MovePipOnImeVisibilityChangeTest.kt b/libs/WindowManager/Shell/tests/flicker/pip/src/com/android/wm/shell/flicker/pip/MovePipOnImeVisibilityChangeTest.kt index 425cbfaffedd..425cbfaffedd 100644 --- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/MovePipOnImeVisibilityChangeTest.kt +++ b/libs/WindowManager/Shell/tests/flicker/pip/src/com/android/wm/shell/flicker/pip/MovePipOnImeVisibilityChangeTest.kt diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/MovePipUpOnShelfHeightChangeTest.kt b/libs/WindowManager/Shell/tests/flicker/pip/src/com/android/wm/shell/flicker/pip/MovePipUpOnShelfHeightChangeTest.kt index 18f30d96938b..18f30d96938b 100644 --- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/MovePipUpOnShelfHeightChangeTest.kt +++ b/libs/WindowManager/Shell/tests/flicker/pip/src/com/android/wm/shell/flicker/pip/MovePipUpOnShelfHeightChangeTest.kt diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/PipAspectRatioChangeTest.kt b/libs/WindowManager/Shell/tests/flicker/pip/src/com/android/wm/shell/flicker/pip/PipAspectRatioChangeTest.kt index 4f27ceddd705..36047cca55ea 100644 --- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/PipAspectRatioChangeTest.kt +++ b/libs/WindowManager/Shell/tests/flicker/pip/src/com/android/wm/shell/flicker/pip/PipAspectRatioChangeTest.kt @@ -35,9 +35,7 @@ import org.junit.runners.Parameterized @FixMethodOrder(MethodSorters.NAME_ASCENDING) class PipAspectRatioChangeTest(flicker: LegacyFlickerTest) : PipTransition(flicker) { override val thisTransition: FlickerBuilder.() -> Unit = { - transitions { - pipApp.changeAspectRatio() - } + transitions { pipApp.changeAspectRatio() } } @Presubmit diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/PipDragTest.kt b/libs/WindowManager/Shell/tests/flicker/pip/src/com/android/wm/shell/flicker/pip/PipDragTest.kt index c7f2786debd0..c7f2786debd0 100644 --- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/PipDragTest.kt +++ b/libs/WindowManager/Shell/tests/flicker/pip/src/com/android/wm/shell/flicker/pip/PipDragTest.kt diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/PipDragThenSnapTest.kt b/libs/WindowManager/Shell/tests/flicker/pip/src/com/android/wm/shell/flicker/pip/PipDragThenSnapTest.kt index cabc1cc0b023..cabc1cc0b023 100644 --- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/PipDragThenSnapTest.kt +++ b/libs/WindowManager/Shell/tests/flicker/pip/src/com/android/wm/shell/flicker/pip/PipDragThenSnapTest.kt diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/PipPinchInTest.kt b/libs/WindowManager/Shell/tests/flicker/pip/src/com/android/wm/shell/flicker/pip/PipPinchInTest.kt index 0fd1b2c3f0de..381f947cbc84 100644 --- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/PipPinchInTest.kt +++ b/libs/WindowManager/Shell/tests/flicker/pip/src/com/android/wm/shell/flicker/pip/PipPinchInTest.kt @@ -42,8 +42,8 @@ class PipPinchInTest(flicker: LegacyFlickerTest) : PipTransition(flicker) { } /** - * Checks that the visible region area of [pipApp] decreases - * and then increases during the animation. + * Checks that the visible region area of [pipApp] decreases and then increases during the + * animation. */ @Presubmit @Test diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/SetRequestedOrientationWhilePinned.kt b/libs/WindowManager/Shell/tests/flicker/pip/src/com/android/wm/shell/flicker/pip/SetRequestedOrientationWhilePinned.kt index 1f69847e5481..1f69847e5481 100644 --- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/SetRequestedOrientationWhilePinned.kt +++ b/libs/WindowManager/Shell/tests/flicker/pip/src/com/android/wm/shell/flicker/pip/SetRequestedOrientationWhilePinned.kt diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/ShowPipAndRotateDisplay.kt b/libs/WindowManager/Shell/tests/flicker/pip/src/com/android/wm/shell/flicker/pip/ShowPipAndRotateDisplay.kt index 308ece40402f..308ece40402f 100644 --- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/ShowPipAndRotateDisplay.kt +++ b/libs/WindowManager/Shell/tests/flicker/pip/src/com/android/wm/shell/flicker/pip/ShowPipAndRotateDisplay.kt diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/apps/AppsEnterPipTransition.kt b/libs/WindowManager/Shell/tests/flicker/pip/src/com/android/wm/shell/flicker/pip/apps/AppsEnterPipTransition.kt index c9a98c73e5e5..be5a27ac7dcc 100644 --- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/apps/AppsEnterPipTransition.kt +++ b/libs/WindowManager/Shell/tests/flicker/pip/src/com/android/wm/shell/flicker/pip/apps/AppsEnterPipTransition.kt @@ -81,9 +81,8 @@ abstract class AppsEnterPipTransition(flicker: LegacyFlickerTest) : EnterPipTran @Test override fun pipLayerReduces() { flicker.assertLayers { - val pipLayerList = this.layers { - standardAppHelper.layerMatchesAnyOf(it) && it.isVisible - } + val pipLayerList = + this.layers { standardAppHelper.layerMatchesAnyOf(it) && it.isVisible } pipLayerList.zipWithNext { previous, current -> current.visibleRegion.notBiggerThan(previous.visibleRegion.region) } @@ -194,7 +193,8 @@ abstract class AppsEnterPipTransition(flicker: LegacyFlickerTest) : EnterPipTran * transition */ @Postsubmit - @Test override fun statusBarWindowIsAlwaysVisible() = super.statusBarWindowIsAlwaysVisible() + @Test + override fun statusBarWindowIsAlwaysVisible() = super.statusBarWindowIsAlwaysVisible() /** * Checks that all layers that are visible on the trace, are visible for at least 2 consecutive @@ -215,9 +215,7 @@ abstract class AppsEnterPipTransition(flicker: LegacyFlickerTest) : EnterPipTran super.visibleWindowsShownMoreThanOneConsecutiveEntry() /** Checks that all parts of the screen are covered during the transition */ - @Postsubmit - @Test - override fun entireScreenCovered() = super.entireScreenCovered() + @Postsubmit @Test override fun entireScreenCovered() = super.entireScreenCovered() companion object { /** diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/apps/MapsEnterPipTest.kt b/libs/WindowManager/Shell/tests/flicker/pip/src/com/android/wm/shell/flicker/pip/apps/MapsEnterPipTest.kt index d7ba3d57b548..4da52ef1272c 100644 --- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/apps/MapsEnterPipTest.kt +++ b/libs/WindowManager/Shell/tests/flicker/pip/src/com/android/wm/shell/flicker/pip/apps/MapsEnterPipTest.kt @@ -69,20 +69,21 @@ open class MapsEnterPipTest(flicker: LegacyFlickerTest) : AppsEnterPipTransition val mainHandler = Handler(Looper.getMainLooper()) var mockLocationEnabled = false - val updateLocation = object : Runnable { - override fun run() { - // early bail out if mocking location is not enabled - if (!mockLocationEnabled) return - val location = Location("Googleplex") - location.latitude = 37.42243438411294 - location.longitude = -122.08426281892311 - location.time = System.currentTimeMillis() - location.elapsedRealtimeNanos = SystemClock.elapsedRealtimeNanos() - location.accuracy = 100f - locationManager.setTestProviderLocation(LocationManager.GPS_PROVIDER, location) - mainHandler.postDelayed(this, 5) + val updateLocation = + object : Runnable { + override fun run() { + // early bail out if mocking location is not enabled + if (!mockLocationEnabled) return + val location = Location("Googleplex") + location.latitude = 37.42243438411294 + location.longitude = -122.08426281892311 + location.time = System.currentTimeMillis() + location.elapsedRealtimeNanos = SystemClock.elapsedRealtimeNanos() + location.accuracy = 100f + locationManager.setTestProviderLocation(LocationManager.GPS_PROVIDER, location) + mainHandler.postDelayed(this, 5) + } } - } override val defaultEnterPip: FlickerBuilder.() -> Unit = { setup { @@ -129,9 +130,7 @@ open class MapsEnterPipTest(flicker: LegacyFlickerTest) : AppsEnterPipTransition } } - override val thisTransition: FlickerBuilder.() -> Unit = { - transitions { tapl.goHome() } - } + override val thisTransition: FlickerBuilder.() -> Unit = { transitions { tapl.goHome() } } @Postsubmit @Test diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/apps/NetflixEnterPipTest.kt b/libs/WindowManager/Shell/tests/flicker/pip/src/com/android/wm/shell/flicker/pip/apps/NetflixEnterPipTest.kt index 596580547d59..5498e8c4f970 100644 --- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/apps/NetflixEnterPipTest.kt +++ b/libs/WindowManager/Shell/tests/flicker/pip/src/com/android/wm/shell/flicker/pip/apps/NetflixEnterPipTest.kt @@ -67,25 +67,18 @@ open class NetflixEnterPipTest(flicker: LegacyFlickerTest) : AppsEnterPipTransit standardAppHelper.launchViaIntent( wmHelper, NetflixAppHelper.getNetflixWatchVideoIntent("70184207"), - ComponentNameMatcher( - NetflixAppHelper.PACKAGE_NAME, - NetflixAppHelper.WATCH_ACTIVITY - ) + ComponentNameMatcher(NetflixAppHelper.PACKAGE_NAME, NetflixAppHelper.WATCH_ACTIVITY) ) standardAppHelper.waitForVideoPlaying() } } override val defaultTeardown: FlickerBuilder.() -> Unit = { - teardown { - standardAppHelper.exit(wmHelper) - } + teardown { standardAppHelper.exit(wmHelper) } } override val thisTransition: FlickerBuilder.() -> Unit = { - transitions { - tapl.goHomeFromImmersiveFullscreenApp() - } + transitions { tapl.goHomeFromImmersiveFullscreenApp() } } @Postsubmit @@ -133,7 +126,8 @@ open class NetflixEnterPipTest(flicker: LegacyFlickerTest) : AppsEnterPipTransit } @Postsubmit - @Test override fun statusBarWindowIsAlwaysVisible() { + @Test + override fun statusBarWindowIsAlwaysVisible() { // Netflix plays in immersive fullscreen mode, so taskbar will be gone at some point } diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/apps/YouTubeEnterPipTest.kt b/libs/WindowManager/Shell/tests/flicker/pip/src/com/android/wm/shell/flicker/pip/apps/YouTubeEnterPipTest.kt index c370d91034fd..d8afc25caf71 100644 --- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/apps/YouTubeEnterPipTest.kt +++ b/libs/WindowManager/Shell/tests/flicker/pip/src/com/android/wm/shell/flicker/pip/apps/YouTubeEnterPipTest.kt @@ -70,14 +70,10 @@ open class YouTubeEnterPipTest(flicker: LegacyFlickerTest) : AppsEnterPipTransit } override val defaultTeardown: FlickerBuilder.() -> Unit = { - teardown { - standardAppHelper.exit(wmHelper) - } + teardown { standardAppHelper.exit(wmHelper) } } - override val thisTransition: FlickerBuilder.() -> Unit = { - transitions { tapl.goHome() } - } + override val thisTransition: FlickerBuilder.() -> Unit = { transitions { tapl.goHome() } } @Postsubmit @Test diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/common/ClosePipTransition.kt b/libs/WindowManager/Shell/tests/flicker/pip/src/com/android/wm/shell/flicker/pip/common/ClosePipTransition.kt index 751f2bc0807f..751f2bc0807f 100644 --- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/common/ClosePipTransition.kt +++ b/libs/WindowManager/Shell/tests/flicker/pip/src/com/android/wm/shell/flicker/pip/common/ClosePipTransition.kt diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/common/EnterPipTransition.kt b/libs/WindowManager/Shell/tests/flicker/pip/src/com/android/wm/shell/flicker/pip/common/EnterPipTransition.kt index 9c129e47efba..9c129e47efba 100644 --- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/common/EnterPipTransition.kt +++ b/libs/WindowManager/Shell/tests/flicker/pip/src/com/android/wm/shell/flicker/pip/common/EnterPipTransition.kt diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/common/ExitPipToAppTransition.kt b/libs/WindowManager/Shell/tests/flicker/pip/src/com/android/wm/shell/flicker/pip/common/ExitPipToAppTransition.kt index 9450bdd2d894..9450bdd2d894 100644 --- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/common/ExitPipToAppTransition.kt +++ b/libs/WindowManager/Shell/tests/flicker/pip/src/com/android/wm/shell/flicker/pip/common/ExitPipToAppTransition.kt diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/common/MovePipShelfHeightTransition.kt b/libs/WindowManager/Shell/tests/flicker/pip/src/com/android/wm/shell/flicker/pip/common/MovePipShelfHeightTransition.kt index 7e42bc11a9c1..7e42bc11a9c1 100644 --- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/common/MovePipShelfHeightTransition.kt +++ b/libs/WindowManager/Shell/tests/flicker/pip/src/com/android/wm/shell/flicker/pip/common/MovePipShelfHeightTransition.kt diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/common/PipTransition.kt b/libs/WindowManager/Shell/tests/flicker/pip/src/com/android/wm/shell/flicker/pip/common/PipTransition.kt index 7b7f1d7b5a82..7b7f1d7b5a82 100644 --- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/common/PipTransition.kt +++ b/libs/WindowManager/Shell/tests/flicker/pip/src/com/android/wm/shell/flicker/pip/common/PipTransition.kt diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/tv/PipAppHelperTv.kt b/libs/WindowManager/Shell/tests/flicker/pip/src/com/android/wm/shell/flicker/pip/tv/PipAppHelperTv.kt index c6cbcd052fe0..c6cbcd052fe0 100644 --- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/tv/PipAppHelperTv.kt +++ b/libs/WindowManager/Shell/tests/flicker/pip/src/com/android/wm/shell/flicker/pip/tv/PipAppHelperTv.kt diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/tv/PipTestBase.kt b/libs/WindowManager/Shell/tests/flicker/pip/src/com/android/wm/shell/flicker/pip/tv/PipTestBase.kt index 2cb18f948f0e..2cb18f948f0e 100644 --- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/tv/PipTestBase.kt +++ b/libs/WindowManager/Shell/tests/flicker/pip/src/com/android/wm/shell/flicker/pip/tv/PipTestBase.kt diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/tv/TvPipBasicTest.kt b/libs/WindowManager/Shell/tests/flicker/pip/src/com/android/wm/shell/flicker/pip/tv/TvPipBasicTest.kt index 8a073abf032c..8a073abf032c 100644 --- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/tv/TvPipBasicTest.kt +++ b/libs/WindowManager/Shell/tests/flicker/pip/src/com/android/wm/shell/flicker/pip/tv/TvPipBasicTest.kt diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/tv/TvPipMenuTests.kt b/libs/WindowManager/Shell/tests/flicker/pip/src/com/android/wm/shell/flicker/pip/tv/TvPipMenuTests.kt index d4cd6da4acb1..d4cd6da4acb1 100644 --- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/tv/TvPipMenuTests.kt +++ b/libs/WindowManager/Shell/tests/flicker/pip/src/com/android/wm/shell/flicker/pip/tv/TvPipMenuTests.kt diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/tv/TvPipNotificationTests.kt b/libs/WindowManager/Shell/tests/flicker/pip/src/com/android/wm/shell/flicker/pip/tv/TvPipNotificationTests.kt index 4402e2153e9b..4402e2153e9b 100644 --- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/tv/TvPipNotificationTests.kt +++ b/libs/WindowManager/Shell/tests/flicker/pip/src/com/android/wm/shell/flicker/pip/tv/TvPipNotificationTests.kt diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/tv/TvPipTestBase.kt b/libs/WindowManager/Shell/tests/flicker/pip/src/com/android/wm/shell/flicker/pip/tv/TvPipTestBase.kt index 47bff8de377e..47bff8de377e 100644 --- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/tv/TvPipTestBase.kt +++ b/libs/WindowManager/Shell/tests/flicker/pip/src/com/android/wm/shell/flicker/pip/tv/TvPipTestBase.kt diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/tv/TvUtils.kt b/libs/WindowManager/Shell/tests/flicker/pip/src/com/android/wm/shell/flicker/pip/tv/TvUtils.kt index 4aee61ade10e..4aee61ade10e 100644 --- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/tv/TvUtils.kt +++ b/libs/WindowManager/Shell/tests/flicker/pip/src/com/android/wm/shell/flicker/pip/tv/TvUtils.kt diff --git a/libs/WindowManager/Shell/tests/flicker/pip/trace_config/trace_config.textproto b/libs/WindowManager/Shell/tests/flicker/pip/trace_config/trace_config.textproto new file mode 100644 index 000000000000..406ada97a07d --- /dev/null +++ b/libs/WindowManager/Shell/tests/flicker/pip/trace_config/trace_config.textproto @@ -0,0 +1,75 @@ +# 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. + +# proto-message: TraceConfig + +# Enable periodic flushing of the trace buffer into the output file. +write_into_file: true + +# Writes the userspace buffer into the file every 1s. +file_write_period_ms: 2500 + +# See b/126487238 - we need to guarantee ordering of events. +flush_period_ms: 30000 + +# The trace buffers needs to be big enough to hold |file_write_period_ms| of +# trace data. The trace buffer sizing depends on the number of trace categories +# enabled and the device activity. + +# RSS events +buffers: { + size_kb: 63488 + fill_policy: RING_BUFFER +} + +data_sources { + config { + name: "linux.process_stats" + target_buffer: 0 + # polled per-process memory counters and process/thread names. + # If you don't want the polled counters, remove the "process_stats_config" + # section, but keep the data source itself as it still provides on-demand + # thread/process naming for ftrace data below. + process_stats_config { + scan_all_processes_on_start: true + } + } +} + +data_sources: { + config { + name: "linux.ftrace" + ftrace_config { + ftrace_events: "ftrace/print" + ftrace_events: "task/task_newtask" + ftrace_events: "task/task_rename" + atrace_categories: "ss" + atrace_categories: "wm" + atrace_categories: "am" + atrace_categories: "aidl" + atrace_categories: "input" + atrace_categories: "binder_driver" + atrace_categories: "sched_process_exit" + atrace_apps: "com.android.server.wm.flicker.testapp" + atrace_apps: "com.android.systemui" + atrace_apps: "com.android.wm.shell.flicker" + atrace_apps: "com.android.wm.shell.flicker.other" + atrace_apps: "com.android.wm.shell.flicker.bubbles" + atrace_apps: "com.android.wm.shell.flicker.pip" + atrace_apps: "com.android.wm.shell.flicker.splitscreen" + atrace_apps: "com.google.android.apps.nexuslauncher" + } + } +} + diff --git a/libs/WindowManager/Shell/tests/flicker/service/Android.bp b/libs/WindowManager/Shell/tests/flicker/service/Android.bp new file mode 100644 index 000000000000..9b8cd94d56b2 --- /dev/null +++ b/libs/WindowManager/Shell/tests/flicker/service/Android.bp @@ -0,0 +1,67 @@ +// +// Copyright (C) 2020 The Android Open Source Project +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// + +package { + // See: http://go/android-license-faq + // A large-scale-change added 'default_applicable_licenses' to import + // all of the 'license_kinds' from "frameworks_base_license" + // to get the below license kinds: + // SPDX-license-identifier-Apache-2.0 + default_applicable_licenses: ["frameworks_base_license"], +} + +filegroup { + name: "WMShellFlickerServicePlatinumTests-src", + srcs: [ + "src/**/platinum/*.kt", + "src/**/scenarios/*.kt", + "src/**/common/*.kt", + ], +} + +java_library { + name: "wm-shell-flicker-platinum-tests", + platform_apis: true, + optimize: { + enabled: false, + }, + srcs: [ + ":WMShellFlickerServicePlatinumTests-src", + ], + static_libs: [ + "wm-shell-flicker-utils", + ], +} + +android_test { + name: "WMShellFlickerServiceTests", + defaults: ["WMShellFlickerTestsDefault"], + manifest: "AndroidManifest.xml", + package_name: "com.android.wm.shell.flicker.service", + instrumentation_target_package: "com.android.wm.shell.flicker.service", + srcs: ["src/**/*.kt"], + static_libs: ["WMShellFlickerTestsBase"], +} + +android_test { + name: "WMShellFlickerServicePlatinumTests", + defaults: ["WMShellFlickerTestsDefault"], + manifest: "AndroidManifest.xml", + package_name: "com.android.wm.shell.flicker.service", + instrumentation_target_package: "com.android.wm.shell.flicker.service", + srcs: [":WMShellFlickerServicePlatinumTests-src"], + static_libs: ["WMShellFlickerTestsBase"], +} diff --git a/libs/WindowManager/Shell/tests/flicker/service/AndroidManifest.xml b/libs/WindowManager/Shell/tests/flicker/service/AndroidManifest.xml new file mode 100644 index 000000000000..d54b6941d975 --- /dev/null +++ b/libs/WindowManager/Shell/tests/flicker/service/AndroidManifest.xml @@ -0,0 +1,77 @@ +<!-- + ~ Copyright (C) 2023 The Android Open Source Project + ~ + ~ Licensed under the Apache License, Version 2.0 (the "License"); + ~ you may not use this file except in compliance with the License. + ~ You may obtain a copy of the License at + ~ + ~ http://www.apache.org/licenses/LICENSE-2.0 + ~ + ~ Unless required by applicable law or agreed to in writing, software + ~ distributed under the License is distributed on an "AS IS" BASIS, + ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + ~ See the License for the specific language governing permissions and + ~ limitations under the License. + --> + +<manifest xmlns:android="http://schemas.android.com/apk/res/android" + xmlns:tools="http://schemas.android.com/tools" + package="com.android.wm.shell.flicker.service"> + + <uses-sdk android:minSdkVersion="29" android:targetSdkVersion="29"/> + <!-- Read and write traces from external storage --> + <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" /> + <uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" /> + <!-- Allow the test to write directly to /sdcard/ --> + <uses-permission android:name="android.permission.MANAGE_EXTERNAL_STORAGE" /> + <!-- Write secure settings --> + <uses-permission android:name="android.permission.WRITE_SECURE_SETTINGS" /> + <!-- Capture screen contents --> + <uses-permission android:name="android.permission.ACCESS_SURFACE_FLINGER" /> + <!-- Enable / Disable tracing !--> + <uses-permission android:name="android.permission.DUMP" /> + <!-- Run layers trace --> + <uses-permission android:name="android.permission.HARDWARE_TEST"/> + <!-- Capture screen recording --> + <uses-permission android:name="android.permission.CAPTURE_VIDEO_OUTPUT"/> + <!-- Workaround grant runtime permission exception from b/152733071 --> + <uses-permission android:name="android.permission.PACKAGE_USAGE_STATS"/> + <uses-permission android:name="android.permission.READ_LOGS"/> + <!-- Force-stop test apps --> + <uses-permission android:name="android.permission.FORCE_STOP_PACKAGES"/> + <!-- Control test app's media session --> + <uses-permission android:name="android.permission.MEDIA_CONTENT_CONTROL"/> + <!-- ATM.removeRootTasksWithActivityTypes() --> + <uses-permission android:name="android.permission.MANAGE_ACTIVITY_TASKS" /> + <!-- Enable bubble notification--> + <uses-permission android:name="android.permission.STATUS_BAR_SERVICE" /> + <!-- Allow the test to connect to perfetto trace processor --> + <uses-permission android:name="android.permission.INTERNET"/> + + <!-- Allow the test to write directly to /sdcard/ and connect to trace processor --> + <application android:requestLegacyExternalStorage="true" + android:networkSecurityConfig="@xml/network_security_config" + android:largeHeap="true"> + <uses-library android:name="android.test.runner"/> + + <service android:name=".NotificationListener" + android:exported="true" + android:label="WMShellTestsNotificationListenerService" + android:permission="android.permission.BIND_NOTIFICATION_LISTENER_SERVICE"> + <intent-filter> + <action android:name="android.service.notification.NotificationListenerService" /> + </intent-filter> + </service> + + <!-- (b/197936012) Remove startup provider due to test timeout issue --> + <provider + android:name="androidx.startup.InitializationProvider" + android:authorities="${applicationId}.androidx-startup" + tools:node="remove" /> + </application> + + <instrumentation android:name="androidx.test.runner.AndroidJUnitRunner" + android:targetPackage="com.android.wm.shell.flicker.service" + android:label="WindowManager Flicker Service Tests"> + </instrumentation> +</manifest> diff --git a/libs/WindowManager/Shell/tests/flicker/service/AndroidTestTemplate.xml b/libs/WindowManager/Shell/tests/flicker/service/AndroidTestTemplate.xml new file mode 100644 index 000000000000..1df11369a049 --- /dev/null +++ b/libs/WindowManager/Shell/tests/flicker/service/AndroidTestTemplate.xml @@ -0,0 +1,109 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- + ~ Copyright (C) 2023 The Android Open Source Project + ~ + ~ Licensed under the Apache License, Version 2.0 (the "License"); + ~ you may not use this file except in compliance with the License. + ~ You may obtain a copy of the License at + ~ + ~ http://www.apache.org/licenses/LICENSE-2.0 + ~ + ~ Unless required by applicable law or agreed to in writing, software + ~ distributed under the License is distributed on an "AS IS" BASIS, + ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + ~ See the License for the specific language governing permissions and + ~ limitations under the License. + --> +<configuration description="Runs WindowManager Shell Flicker Tests {MODULE}"> + <option name="test-tag" value="FlickerTests"/> + <!-- Needed for storing the perfetto trace files in the sdcard/test_results--> + <option name="isolated-storage" value="false"/> + + <target_preparer class="com.android.tradefed.targetprep.DeviceSetup"> + <!-- keeps the screen on during tests --> + <option name="screen-always-on" value="on"/> + <!-- prevents the phone from restarting --> + <option name="force-skip-system-props" value="true"/> + <!-- set WM tracing verbose level to all --> + <option name="run-command" value="cmd window tracing level all"/> + <!-- set WM tracing to frame (avoid incomplete states) --> + <option name="run-command" value="cmd window tracing frame"/> + <!-- disable betterbug as it's log collection dialogues cause flakes in e2e tests --> + <option name="run-command" value="pm disable com.google.android.internal.betterbug"/> + <!-- ensure lock screen mode is swipe --> + <option name="run-command" value="locksettings set-disabled false"/> + <!-- restart launcher to activate TAPL --> + <option name="run-command" + value="setprop ro.test_harness 1 ; am force-stop com.google.android.apps.nexuslauncher"/> + <!-- Increase trace size: 20mb for WM and 80mb for SF --> + <option name="run-command" value="cmd window tracing size 20480"/> + <option name="run-command" value="su root service call SurfaceFlinger 1029 i32 81920"/> + </target_preparer> + <target_preparer class="com.android.tradefed.targetprep.RunCommandTargetPreparer"> + <option name="test-user-token" value="%TEST_USER%"/> + <option name="run-command" value="rm -rf /data/user/%TEST_USER%/files/*"/> + <option name="run-command" value="settings put secure show_ime_with_hard_keyboard 1"/> + <option name="run-command" value="settings put system show_touches 1"/> + <option name="run-command" value="settings put system pointer_location 1"/> + <option name="teardown-command" + value="settings delete secure show_ime_with_hard_keyboard"/> + <option name="teardown-command" value="settings delete system show_touches"/> + <option name="teardown-command" value="settings delete system pointer_location"/> + <option name="teardown-command" + value="cmd overlay enable com.android.internal.systemui.navbar.gestural"/> + </target_preparer> + <target_preparer class="com.android.tradefed.targetprep.suite.SuiteApkInstaller"> + <option name="cleanup-apks" value="true"/> + <option name="test-file-name" value="{MODULE}.apk"/> + <option name="test-file-name" value="FlickerTestApp.apk"/> + </target_preparer> + <!-- Enable mocking GPS location by the test app --> + <target_preparer class="com.android.tradefed.targetprep.RunCommandTargetPreparer"> + <option name="run-command" + value="appops set com.android.wm.shell.flicker.pip.apps android:mock_location allow"/> + <option name="teardown-command" + value="appops set com.android.wm.shell.flicker.pip.apps android:mock_location deny"/> + </target_preparer> + + <!-- Needed for pushing the trace config file --> + <target_preparer class="com.android.tradefed.targetprep.RootTargetPreparer"/> + <target_preparer class="com.android.tradefed.targetprep.PushFilePreparer"> + <option name="push-file" + key="trace_config.textproto" + value="/data/misc/perfetto-traces/trace_config.textproto" + /> + <!--Install the content provider automatically when we push some file in sdcard folder.--> + <!--Needed to avoid the installation during the test suite.--> + <option name="push-file" key="trace_config.textproto" value="/sdcard/sample.textproto"/> + </target_preparer> + <test class="com.android.tradefed.testtype.AndroidJUnitTest"> + <option name="package" value="{PACKAGE}"/> + <option name="shell-timeout" value="6600s"/> + <option name="test-timeout" value="6000s"/> + <option name="hidden-api-checks" value="false"/> + <option name="device-listeners" value="android.device.collectors.PerfettoListener"/> + <!-- PerfettoListener related arguments --> + <option name="instrumentation-arg" key="perfetto_config_text_proto" value="true"/> + <option name="instrumentation-arg" + key="perfetto_config_file" + value="trace_config.textproto" + /> + <option name="instrumentation-arg" key="per_run" value="true"/> + </test> + <!-- Needed for pulling the collected trace config on to the host --> + <metrics_collector class="com.android.tradefed.device.metric.FilePullerLogCollector"> + <option name="pull-pattern-keys" value="perfetto_file_path"/> + <option name="directory-keys" + value="/data/user/0/com.android.wm.shell.flicker/files"/> + <option name="directory-keys" + value="/data/user/0/com.android.wm.shell.flicker.bubbles/files"/> + <option name="directory-keys" + value="/data/user/0/com.android.wm.shell.flicker.pip/files"/> + <option name="directory-keys" + value="/data/user/0/com.android.wm.shell.flicker.splitscreen/files"/> + <option name="directory-keys" + value="/data/user/0/com.android.wm.shell.flicker.service/files"/> + <option name="collect-on-run-ended-only" value="true"/> + <option name="clean-up" value="true"/> + </metrics_collector> +</configuration> diff --git a/libs/WindowManager/Shell/tests/flicker/manifests/AndroidManifestService.xml b/libs/WindowManager/Shell/tests/flicker/service/res/xml/network_security_config.xml index c7aca1a72696..4bd9ca049f55 100644 --- a/libs/WindowManager/Shell/tests/flicker/manifests/AndroidManifestService.xml +++ b/libs/WindowManager/Shell/tests/flicker/service/res/xml/network_security_config.xml @@ -1,3 +1,4 @@ +<?xml version="1.0" encoding="utf-8"?> <!-- ~ Copyright (C) 2023 The Android Open Source Project ~ @@ -14,11 +15,8 @@ ~ limitations under the License. --> -<manifest xmlns:android="http://schemas.android.com/apk/res/android" - package="com.android.wm.shell.flicker.service"> - - <instrumentation android:name="androidx.test.runner.AndroidJUnitRunner" - android:targetPackage="com.android.wm.shell.flicker.service" - android:label="WindowManager Flicker Service Tests"> - </instrumentation> -</manifest> +<network-security-config> + <domain-config cleartextTrafficPermitted="true"> + <domain includeSubdomains="true">localhost</domain> + </domain-config> +</network-security-config> diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/service/common/Utils.kt b/libs/WindowManager/Shell/tests/flicker/service/src/com/android/wm/shell/flicker/service/common/Utils.kt index 5f157856aa36..4bd79546b96d 100644 --- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/service/common/Utils.kt +++ b/libs/WindowManager/Shell/tests/flicker/service/src/com/android/wm/shell/flicker/service/common/Utils.kt @@ -36,9 +36,7 @@ object Utils { fun testSetupRule(navigationMode: NavBar, rotation: Rotation): RuleChain { return RuleChain.outerRule(ArtifactSaverRule()) .around(UnlockScreenRule()) - .around( - NavigationModeRule(navigationMode.value, false) - ) + .around(NavigationModeRule(navigationMode.value, false)) .around( LaunchAppRule(MessagingAppHelper(instrumentation), clearCacheAfterParsing = false) ) diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/service/splitscreen/OWNERS b/libs/WindowManager/Shell/tests/flicker/service/src/com/android/wm/shell/flicker/service/splitscreen/OWNERS index 3ab6a1ee061d..3ab6a1ee061d 100644 --- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/service/splitscreen/OWNERS +++ b/libs/WindowManager/Shell/tests/flicker/service/src/com/android/wm/shell/flicker/service/splitscreen/OWNERS diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/service/splitscreen/flicker/CopyContentInSplitGesturalNavLandscape.kt b/libs/WindowManager/Shell/tests/flicker/service/src/com/android/wm/shell/flicker/service/splitscreen/flicker/CopyContentInSplitGesturalNavLandscape.kt index a5c512267508..a5c512267508 100644 --- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/service/splitscreen/flicker/CopyContentInSplitGesturalNavLandscape.kt +++ b/libs/WindowManager/Shell/tests/flicker/service/src/com/android/wm/shell/flicker/service/splitscreen/flicker/CopyContentInSplitGesturalNavLandscape.kt diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/service/splitscreen/flicker/CopyContentInSplitGesturalNavPortrait.kt b/libs/WindowManager/Shell/tests/flicker/service/src/com/android/wm/shell/flicker/service/splitscreen/flicker/CopyContentInSplitGesturalNavPortrait.kt index 092fb6720e57..092fb6720e57 100644 --- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/service/splitscreen/flicker/CopyContentInSplitGesturalNavPortrait.kt +++ b/libs/WindowManager/Shell/tests/flicker/service/src/com/android/wm/shell/flicker/service/splitscreen/flicker/CopyContentInSplitGesturalNavPortrait.kt diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/service/splitscreen/flicker/DismissSplitScreenByDividerGesturalNavLandscape.kt b/libs/WindowManager/Shell/tests/flicker/service/src/com/android/wm/shell/flicker/service/splitscreen/flicker/DismissSplitScreenByDividerGesturalNavLandscape.kt index 69499b9b488b..69499b9b488b 100644 --- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/service/splitscreen/flicker/DismissSplitScreenByDividerGesturalNavLandscape.kt +++ b/libs/WindowManager/Shell/tests/flicker/service/src/com/android/wm/shell/flicker/service/splitscreen/flicker/DismissSplitScreenByDividerGesturalNavLandscape.kt diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/service/splitscreen/flicker/DismissSplitScreenByDividerGesturalNavPortrait.kt b/libs/WindowManager/Shell/tests/flicker/service/src/com/android/wm/shell/flicker/service/splitscreen/flicker/DismissSplitScreenByDividerGesturalNavPortrait.kt index bd627f4babaa..bd627f4babaa 100644 --- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/service/splitscreen/flicker/DismissSplitScreenByDividerGesturalNavPortrait.kt +++ b/libs/WindowManager/Shell/tests/flicker/service/src/com/android/wm/shell/flicker/service/splitscreen/flicker/DismissSplitScreenByDividerGesturalNavPortrait.kt diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/service/splitscreen/flicker/DismissSplitScreenByGoHomeGesturalNavLandscape.kt b/libs/WindowManager/Shell/tests/flicker/service/src/com/android/wm/shell/flicker/service/splitscreen/flicker/DismissSplitScreenByGoHomeGesturalNavLandscape.kt index a8f4d0a24c7e..a8f4d0a24c7e 100644 --- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/service/splitscreen/flicker/DismissSplitScreenByGoHomeGesturalNavLandscape.kt +++ b/libs/WindowManager/Shell/tests/flicker/service/src/com/android/wm/shell/flicker/service/splitscreen/flicker/DismissSplitScreenByGoHomeGesturalNavLandscape.kt diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/service/splitscreen/flicker/DismissSplitScreenByGoHomeGesturalNavPortrait.kt b/libs/WindowManager/Shell/tests/flicker/service/src/com/android/wm/shell/flicker/service/splitscreen/flicker/DismissSplitScreenByGoHomeGesturalNavPortrait.kt index cee9bbfb4aa4..cee9bbfb4aa4 100644 --- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/service/splitscreen/flicker/DismissSplitScreenByGoHomeGesturalNavPortrait.kt +++ b/libs/WindowManager/Shell/tests/flicker/service/src/com/android/wm/shell/flicker/service/splitscreen/flicker/DismissSplitScreenByGoHomeGesturalNavPortrait.kt diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/service/splitscreen/flicker/DragDividerToResizeGesturalNavLandscape.kt b/libs/WindowManager/Shell/tests/flicker/service/src/com/android/wm/shell/flicker/service/splitscreen/flicker/DragDividerToResizeGesturalNavLandscape.kt index c1b3aade11cd..c1b3aade11cd 100644 --- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/service/splitscreen/flicker/DragDividerToResizeGesturalNavLandscape.kt +++ b/libs/WindowManager/Shell/tests/flicker/service/src/com/android/wm/shell/flicker/service/splitscreen/flicker/DragDividerToResizeGesturalNavLandscape.kt diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/service/splitscreen/flicker/DragDividerToResizeGesturalNavPortrait.kt b/libs/WindowManager/Shell/tests/flicker/service/src/com/android/wm/shell/flicker/service/splitscreen/flicker/DragDividerToResizeGesturalNavPortrait.kt index c6e2e854ab89..c6e2e854ab89 100644 --- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/service/splitscreen/flicker/DragDividerToResizeGesturalNavPortrait.kt +++ b/libs/WindowManager/Shell/tests/flicker/service/src/com/android/wm/shell/flicker/service/splitscreen/flicker/DragDividerToResizeGesturalNavPortrait.kt diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/service/splitscreen/flicker/EnterSplitScreenByDragFromAllAppsGesturalNavLandscape.kt b/libs/WindowManager/Shell/tests/flicker/service/src/com/android/wm/shell/flicker/service/splitscreen/flicker/EnterSplitScreenByDragFromAllAppsGesturalNavLandscape.kt index 169b5cfa3462..169b5cfa3462 100644 --- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/service/splitscreen/flicker/EnterSplitScreenByDragFromAllAppsGesturalNavLandscape.kt +++ b/libs/WindowManager/Shell/tests/flicker/service/src/com/android/wm/shell/flicker/service/splitscreen/flicker/EnterSplitScreenByDragFromAllAppsGesturalNavLandscape.kt diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/service/splitscreen/flicker/EnterSplitScreenByDragFromAllAppsGesturalNavPortrait.kt b/libs/WindowManager/Shell/tests/flicker/service/src/com/android/wm/shell/flicker/service/splitscreen/flicker/EnterSplitScreenByDragFromAllAppsGesturalNavPortrait.kt index 412c011a3f17..412c011a3f17 100644 --- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/service/splitscreen/flicker/EnterSplitScreenByDragFromAllAppsGesturalNavPortrait.kt +++ b/libs/WindowManager/Shell/tests/flicker/service/src/com/android/wm/shell/flicker/service/splitscreen/flicker/EnterSplitScreenByDragFromAllAppsGesturalNavPortrait.kt diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/service/splitscreen/flicker/EnterSplitScreenByDragFromNotificationGesturalNavLandscape.kt b/libs/WindowManager/Shell/tests/flicker/service/src/com/android/wm/shell/flicker/service/splitscreen/flicker/EnterSplitScreenByDragFromNotificationGesturalNavLandscape.kt index 6e4cf9f55cfd..6e4cf9f55cfd 100644 --- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/service/splitscreen/flicker/EnterSplitScreenByDragFromNotificationGesturalNavLandscape.kt +++ b/libs/WindowManager/Shell/tests/flicker/service/src/com/android/wm/shell/flicker/service/splitscreen/flicker/EnterSplitScreenByDragFromNotificationGesturalNavLandscape.kt diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/service/splitscreen/flicker/EnterSplitScreenByDragFromNotificationGesturalNavPortrait.kt b/libs/WindowManager/Shell/tests/flicker/service/src/com/android/wm/shell/flicker/service/splitscreen/flicker/EnterSplitScreenByDragFromNotificationGesturalNavPortrait.kt index cc2870213e8d..cc2870213e8d 100644 --- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/service/splitscreen/flicker/EnterSplitScreenByDragFromNotificationGesturalNavPortrait.kt +++ b/libs/WindowManager/Shell/tests/flicker/service/src/com/android/wm/shell/flicker/service/splitscreen/flicker/EnterSplitScreenByDragFromNotificationGesturalNavPortrait.kt diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/service/splitscreen/flicker/EnterSplitScreenByDragFromShortcutGesturalNavLandscape.kt b/libs/WindowManager/Shell/tests/flicker/service/src/com/android/wm/shell/flicker/service/splitscreen/flicker/EnterSplitScreenByDragFromShortcutGesturalNavLandscape.kt index 736604f02377..736604f02377 100644 --- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/service/splitscreen/flicker/EnterSplitScreenByDragFromShortcutGesturalNavLandscape.kt +++ b/libs/WindowManager/Shell/tests/flicker/service/src/com/android/wm/shell/flicker/service/splitscreen/flicker/EnterSplitScreenByDragFromShortcutGesturalNavLandscape.kt diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/service/splitscreen/flicker/EnterSplitScreenByDragFromShortcutGesturalNavPortrait.kt b/libs/WindowManager/Shell/tests/flicker/service/src/com/android/wm/shell/flicker/service/splitscreen/flicker/EnterSplitScreenByDragFromShortcutGesturalNavPortrait.kt index 8df8dfaab071..8df8dfaab071 100644 --- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/service/splitscreen/flicker/EnterSplitScreenByDragFromShortcutGesturalNavPortrait.kt +++ b/libs/WindowManager/Shell/tests/flicker/service/src/com/android/wm/shell/flicker/service/splitscreen/flicker/EnterSplitScreenByDragFromShortcutGesturalNavPortrait.kt diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/service/splitscreen/flicker/EnterSplitScreenByDragFromTaskbarGesturalNavLandscape.kt b/libs/WindowManager/Shell/tests/flicker/service/src/com/android/wm/shell/flicker/service/splitscreen/flicker/EnterSplitScreenByDragFromTaskbarGesturalNavLandscape.kt index 378f055ef830..378f055ef830 100644 --- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/service/splitscreen/flicker/EnterSplitScreenByDragFromTaskbarGesturalNavLandscape.kt +++ b/libs/WindowManager/Shell/tests/flicker/service/src/com/android/wm/shell/flicker/service/splitscreen/flicker/EnterSplitScreenByDragFromTaskbarGesturalNavLandscape.kt diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/service/splitscreen/flicker/EnterSplitScreenByDragFromTaskbarGesturalNavPortrait.kt b/libs/WindowManager/Shell/tests/flicker/service/src/com/android/wm/shell/flicker/service/splitscreen/flicker/EnterSplitScreenByDragFromTaskbarGesturalNavPortrait.kt index b33d26288d33..b33d26288d33 100644 --- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/service/splitscreen/flicker/EnterSplitScreenByDragFromTaskbarGesturalNavPortrait.kt +++ b/libs/WindowManager/Shell/tests/flicker/service/src/com/android/wm/shell/flicker/service/splitscreen/flicker/EnterSplitScreenByDragFromTaskbarGesturalNavPortrait.kt diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/service/splitscreen/flicker/EnterSplitScreenFromOverviewGesturalNavLandscape.kt b/libs/WindowManager/Shell/tests/flicker/service/src/com/android/wm/shell/flicker/service/splitscreen/flicker/EnterSplitScreenFromOverviewGesturalNavLandscape.kt index b1d3858b9dbb..b1d3858b9dbb 100644 --- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/service/splitscreen/flicker/EnterSplitScreenFromOverviewGesturalNavLandscape.kt +++ b/libs/WindowManager/Shell/tests/flicker/service/src/com/android/wm/shell/flicker/service/splitscreen/flicker/EnterSplitScreenFromOverviewGesturalNavLandscape.kt diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/service/splitscreen/flicker/EnterSplitScreenFromOverviewGesturalNavPortrait.kt b/libs/WindowManager/Shell/tests/flicker/service/src/com/android/wm/shell/flicker/service/splitscreen/flicker/EnterSplitScreenFromOverviewGesturalNavPortrait.kt index 6d824c74c1fe..6d824c74c1fe 100644 --- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/service/splitscreen/flicker/EnterSplitScreenFromOverviewGesturalNavPortrait.kt +++ b/libs/WindowManager/Shell/tests/flicker/service/src/com/android/wm/shell/flicker/service/splitscreen/flicker/EnterSplitScreenFromOverviewGesturalNavPortrait.kt diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/service/splitscreen/flicker/SwitchAppByDoubleTapDividerGesturalNavLandscape.kt b/libs/WindowManager/Shell/tests/flicker/service/src/com/android/wm/shell/flicker/service/splitscreen/flicker/SwitchAppByDoubleTapDividerGesturalNavLandscape.kt index f1d3d0cf2716..f1d3d0cf2716 100644 --- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/service/splitscreen/flicker/SwitchAppByDoubleTapDividerGesturalNavLandscape.kt +++ b/libs/WindowManager/Shell/tests/flicker/service/src/com/android/wm/shell/flicker/service/splitscreen/flicker/SwitchAppByDoubleTapDividerGesturalNavLandscape.kt diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/service/splitscreen/flicker/SwitchAppByDoubleTapDividerGesturalNavPortrait.kt b/libs/WindowManager/Shell/tests/flicker/service/src/com/android/wm/shell/flicker/service/splitscreen/flicker/SwitchAppByDoubleTapDividerGesturalNavPortrait.kt index a867bac8c0eb..a867bac8c0eb 100644 --- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/service/splitscreen/flicker/SwitchAppByDoubleTapDividerGesturalNavPortrait.kt +++ b/libs/WindowManager/Shell/tests/flicker/service/src/com/android/wm/shell/flicker/service/splitscreen/flicker/SwitchAppByDoubleTapDividerGesturalNavPortrait.kt diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/service/splitscreen/flicker/SwitchBackToSplitFromAnotherAppGesturalNavLandscape.kt b/libs/WindowManager/Shell/tests/flicker/service/src/com/android/wm/shell/flicker/service/splitscreen/flicker/SwitchBackToSplitFromAnotherAppGesturalNavLandscape.kt index 76247ba10037..76247ba10037 100644 --- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/service/splitscreen/flicker/SwitchBackToSplitFromAnotherAppGesturalNavLandscape.kt +++ b/libs/WindowManager/Shell/tests/flicker/service/src/com/android/wm/shell/flicker/service/splitscreen/flicker/SwitchBackToSplitFromAnotherAppGesturalNavLandscape.kt diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/service/splitscreen/flicker/SwitchBackToSplitFromAnotherAppGesturalNavPortrait.kt b/libs/WindowManager/Shell/tests/flicker/service/src/com/android/wm/shell/flicker/service/splitscreen/flicker/SwitchBackToSplitFromAnotherAppGesturalNavPortrait.kt index e179da81e4db..e179da81e4db 100644 --- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/service/splitscreen/flicker/SwitchBackToSplitFromAnotherAppGesturalNavPortrait.kt +++ b/libs/WindowManager/Shell/tests/flicker/service/src/com/android/wm/shell/flicker/service/splitscreen/flicker/SwitchBackToSplitFromAnotherAppGesturalNavPortrait.kt diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/service/splitscreen/flicker/SwitchBackToSplitFromHomeGesturalNavLandscape.kt b/libs/WindowManager/Shell/tests/flicker/service/src/com/android/wm/shell/flicker/service/splitscreen/flicker/SwitchBackToSplitFromHomeGesturalNavLandscape.kt index 20f554f7d154..20f554f7d154 100644 --- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/service/splitscreen/flicker/SwitchBackToSplitFromHomeGesturalNavLandscape.kt +++ b/libs/WindowManager/Shell/tests/flicker/service/src/com/android/wm/shell/flicker/service/splitscreen/flicker/SwitchBackToSplitFromHomeGesturalNavLandscape.kt diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/service/splitscreen/flicker/SwitchBackToSplitFromHomeGesturalNavPortrait.kt b/libs/WindowManager/Shell/tests/flicker/service/src/com/android/wm/shell/flicker/service/splitscreen/flicker/SwitchBackToSplitFromHomeGesturalNavPortrait.kt index f7776ee3244a..f7776ee3244a 100644 --- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/service/splitscreen/flicker/SwitchBackToSplitFromHomeGesturalNavPortrait.kt +++ b/libs/WindowManager/Shell/tests/flicker/service/src/com/android/wm/shell/flicker/service/splitscreen/flicker/SwitchBackToSplitFromHomeGesturalNavPortrait.kt diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/service/splitscreen/flicker/SwitchBackToSplitFromRecentGesturalNavLandscape.kt b/libs/WindowManager/Shell/tests/flicker/service/src/com/android/wm/shell/flicker/service/splitscreen/flicker/SwitchBackToSplitFromRecentGesturalNavLandscape.kt index 4ff0b4362e60..4ff0b4362e60 100644 --- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/service/splitscreen/flicker/SwitchBackToSplitFromRecentGesturalNavLandscape.kt +++ b/libs/WindowManager/Shell/tests/flicker/service/src/com/android/wm/shell/flicker/service/splitscreen/flicker/SwitchBackToSplitFromRecentGesturalNavLandscape.kt diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/service/splitscreen/flicker/SwitchBackToSplitFromRecentGesturalNavPortrait.kt b/libs/WindowManager/Shell/tests/flicker/service/src/com/android/wm/shell/flicker/service/splitscreen/flicker/SwitchBackToSplitFromRecentGesturalNavPortrait.kt index 930f31d1f348..930f31d1f348 100644 --- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/service/splitscreen/flicker/SwitchBackToSplitFromRecentGesturalNavPortrait.kt +++ b/libs/WindowManager/Shell/tests/flicker/service/src/com/android/wm/shell/flicker/service/splitscreen/flicker/SwitchBackToSplitFromRecentGesturalNavPortrait.kt diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/service/splitscreen/flicker/SwitchBetweenSplitPairsGesturalNavLandscape.kt b/libs/WindowManager/Shell/tests/flicker/service/src/com/android/wm/shell/flicker/service/splitscreen/flicker/SwitchBetweenSplitPairsGesturalNavLandscape.kt index 3da61e5e310c..3da61e5e310c 100644 --- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/service/splitscreen/flicker/SwitchBetweenSplitPairsGesturalNavLandscape.kt +++ b/libs/WindowManager/Shell/tests/flicker/service/src/com/android/wm/shell/flicker/service/splitscreen/flicker/SwitchBetweenSplitPairsGesturalNavLandscape.kt diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/service/splitscreen/flicker/SwitchBetweenSplitPairsGesturalNavPortrait.kt b/libs/WindowManager/Shell/tests/flicker/service/src/com/android/wm/shell/flicker/service/splitscreen/flicker/SwitchBetweenSplitPairsGesturalNavPortrait.kt index 627ae1843314..627ae1843314 100644 --- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/service/splitscreen/flicker/SwitchBetweenSplitPairsGesturalNavPortrait.kt +++ b/libs/WindowManager/Shell/tests/flicker/service/src/com/android/wm/shell/flicker/service/splitscreen/flicker/SwitchBetweenSplitPairsGesturalNavPortrait.kt diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/service/splitscreen/flicker/UnlockKeyguardToSplitScreenGesturalNavLandscape.kt b/libs/WindowManager/Shell/tests/flicker/service/src/com/android/wm/shell/flicker/service/splitscreen/flicker/UnlockKeyguardToSplitScreenGesturalNavLandscape.kt index c744103d49ba..c744103d49ba 100644 --- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/service/splitscreen/flicker/UnlockKeyguardToSplitScreenGesturalNavLandscape.kt +++ b/libs/WindowManager/Shell/tests/flicker/service/src/com/android/wm/shell/flicker/service/splitscreen/flicker/UnlockKeyguardToSplitScreenGesturalNavLandscape.kt diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/service/splitscreen/flicker/UnlockKeyguardToSplitScreenGesturalNavPortrait.kt b/libs/WindowManager/Shell/tests/flicker/service/src/com/android/wm/shell/flicker/service/splitscreen/flicker/UnlockKeyguardToSplitScreenGesturalNavPortrait.kt index 11a4e02c5e37..11a4e02c5e37 100644 --- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/service/splitscreen/flicker/UnlockKeyguardToSplitScreenGesturalNavPortrait.kt +++ b/libs/WindowManager/Shell/tests/flicker/service/src/com/android/wm/shell/flicker/service/splitscreen/flicker/UnlockKeyguardToSplitScreenGesturalNavPortrait.kt diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/service/splitscreen/platinum/CopyContentInSplitGesturalNavLandscape.kt b/libs/WindowManager/Shell/tests/flicker/service/src/com/android/wm/shell/flicker/service/splitscreen/platinum/CopyContentInSplitGesturalNavLandscape.kt index e37d806c7a14..e37d806c7a14 100644 --- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/service/splitscreen/platinum/CopyContentInSplitGesturalNavLandscape.kt +++ b/libs/WindowManager/Shell/tests/flicker/service/src/com/android/wm/shell/flicker/service/splitscreen/platinum/CopyContentInSplitGesturalNavLandscape.kt diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/service/splitscreen/platinum/CopyContentInSplitGesturalNavPortrait.kt b/libs/WindowManager/Shell/tests/flicker/service/src/com/android/wm/shell/flicker/service/splitscreen/platinum/CopyContentInSplitGesturalNavPortrait.kt index 2a50912e0a5c..2a50912e0a5c 100644 --- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/service/splitscreen/platinum/CopyContentInSplitGesturalNavPortrait.kt +++ b/libs/WindowManager/Shell/tests/flicker/service/src/com/android/wm/shell/flicker/service/splitscreen/platinum/CopyContentInSplitGesturalNavPortrait.kt diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/service/splitscreen/platinum/DismissSplitScreenByDividerGesturalNavLandscape.kt b/libs/WindowManager/Shell/tests/flicker/service/src/com/android/wm/shell/flicker/service/splitscreen/platinum/DismissSplitScreenByDividerGesturalNavLandscape.kt index d5da1a8b558c..d5da1a8b558c 100644 --- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/service/splitscreen/platinum/DismissSplitScreenByDividerGesturalNavLandscape.kt +++ b/libs/WindowManager/Shell/tests/flicker/service/src/com/android/wm/shell/flicker/service/splitscreen/platinum/DismissSplitScreenByDividerGesturalNavLandscape.kt diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/service/splitscreen/platinum/DismissSplitScreenByDividerGesturalNavPortrait.kt b/libs/WindowManager/Shell/tests/flicker/service/src/com/android/wm/shell/flicker/service/splitscreen/platinum/DismissSplitScreenByDividerGesturalNavPortrait.kt index 7fdcb9be62ee..7fdcb9be62ee 100644 --- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/service/splitscreen/platinum/DismissSplitScreenByDividerGesturalNavPortrait.kt +++ b/libs/WindowManager/Shell/tests/flicker/service/src/com/android/wm/shell/flicker/service/splitscreen/platinum/DismissSplitScreenByDividerGesturalNavPortrait.kt diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/service/splitscreen/platinum/DismissSplitScreenByGoHomeGesturalNavLandscape.kt b/libs/WindowManager/Shell/tests/flicker/service/src/com/android/wm/shell/flicker/service/splitscreen/platinum/DismissSplitScreenByGoHomeGesturalNavLandscape.kt index 308e954b86c1..308e954b86c1 100644 --- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/service/splitscreen/platinum/DismissSplitScreenByGoHomeGesturalNavLandscape.kt +++ b/libs/WindowManager/Shell/tests/flicker/service/src/com/android/wm/shell/flicker/service/splitscreen/platinum/DismissSplitScreenByGoHomeGesturalNavLandscape.kt diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/service/splitscreen/platinum/DismissSplitScreenByGoHomeGesturalNavPortrait.kt b/libs/WindowManager/Shell/tests/flicker/service/src/com/android/wm/shell/flicker/service/splitscreen/platinum/DismissSplitScreenByGoHomeGesturalNavPortrait.kt index 39e75bd25a71..39e75bd25a71 100644 --- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/service/splitscreen/platinum/DismissSplitScreenByGoHomeGesturalNavPortrait.kt +++ b/libs/WindowManager/Shell/tests/flicker/service/src/com/android/wm/shell/flicker/service/splitscreen/platinum/DismissSplitScreenByGoHomeGesturalNavPortrait.kt diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/service/splitscreen/platinum/DragDividerToResizeGesturalNavLandscape.kt b/libs/WindowManager/Shell/tests/flicker/service/src/com/android/wm/shell/flicker/service/splitscreen/platinum/DragDividerToResizeGesturalNavLandscape.kt index e18da17175c0..e18da17175c0 100644 --- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/service/splitscreen/platinum/DragDividerToResizeGesturalNavLandscape.kt +++ b/libs/WindowManager/Shell/tests/flicker/service/src/com/android/wm/shell/flicker/service/splitscreen/platinum/DragDividerToResizeGesturalNavLandscape.kt diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/service/splitscreen/platinum/DragDividerToResizeGesturalNavPortrait.kt b/libs/WindowManager/Shell/tests/flicker/service/src/com/android/wm/shell/flicker/service/splitscreen/platinum/DragDividerToResizeGesturalNavPortrait.kt index 00d60e756ffa..00d60e756ffa 100644 --- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/service/splitscreen/platinum/DragDividerToResizeGesturalNavPortrait.kt +++ b/libs/WindowManager/Shell/tests/flicker/service/src/com/android/wm/shell/flicker/service/splitscreen/platinum/DragDividerToResizeGesturalNavPortrait.kt diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/service/splitscreen/platinum/EnterSplitScreenByDragFromAllAppsGesturalNavLandscape.kt b/libs/WindowManager/Shell/tests/flicker/service/src/com/android/wm/shell/flicker/service/splitscreen/platinum/EnterSplitScreenByDragFromAllAppsGesturalNavLandscape.kt index d7efbc8c0fd4..d7efbc8c0fd4 100644 --- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/service/splitscreen/platinum/EnterSplitScreenByDragFromAllAppsGesturalNavLandscape.kt +++ b/libs/WindowManager/Shell/tests/flicker/service/src/com/android/wm/shell/flicker/service/splitscreen/platinum/EnterSplitScreenByDragFromAllAppsGesturalNavLandscape.kt diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/service/splitscreen/platinum/EnterSplitScreenByDragFromAllAppsGesturalNavPortrait.kt b/libs/WindowManager/Shell/tests/flicker/service/src/com/android/wm/shell/flicker/service/splitscreen/platinum/EnterSplitScreenByDragFromAllAppsGesturalNavPortrait.kt index 4eece3f62d10..4eece3f62d10 100644 --- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/service/splitscreen/platinum/EnterSplitScreenByDragFromAllAppsGesturalNavPortrait.kt +++ b/libs/WindowManager/Shell/tests/flicker/service/src/com/android/wm/shell/flicker/service/splitscreen/platinum/EnterSplitScreenByDragFromAllAppsGesturalNavPortrait.kt diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/service/splitscreen/platinum/EnterSplitScreenByDragFromNotificationGesturalNavLandscape.kt b/libs/WindowManager/Shell/tests/flicker/service/src/com/android/wm/shell/flicker/service/splitscreen/platinum/EnterSplitScreenByDragFromNotificationGesturalNavLandscape.kt index d96b056d8753..d96b056d8753 100644 --- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/service/splitscreen/platinum/EnterSplitScreenByDragFromNotificationGesturalNavLandscape.kt +++ b/libs/WindowManager/Shell/tests/flicker/service/src/com/android/wm/shell/flicker/service/splitscreen/platinum/EnterSplitScreenByDragFromNotificationGesturalNavLandscape.kt diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/service/splitscreen/platinum/EnterSplitScreenByDragFromNotificationGesturalNavPortrait.kt b/libs/WindowManager/Shell/tests/flicker/service/src/com/android/wm/shell/flicker/service/splitscreen/platinum/EnterSplitScreenByDragFromNotificationGesturalNavPortrait.kt index 809b690e0861..809b690e0861 100644 --- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/service/splitscreen/platinum/EnterSplitScreenByDragFromNotificationGesturalNavPortrait.kt +++ b/libs/WindowManager/Shell/tests/flicker/service/src/com/android/wm/shell/flicker/service/splitscreen/platinum/EnterSplitScreenByDragFromNotificationGesturalNavPortrait.kt diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/service/splitscreen/platinum/EnterSplitScreenByDragFromShortcutGesturalNavLandscape.kt b/libs/WindowManager/Shell/tests/flicker/service/src/com/android/wm/shell/flicker/service/splitscreen/platinum/EnterSplitScreenByDragFromShortcutGesturalNavLandscape.kt index bbdf2d728494..bbdf2d728494 100644 --- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/service/splitscreen/platinum/EnterSplitScreenByDragFromShortcutGesturalNavLandscape.kt +++ b/libs/WindowManager/Shell/tests/flicker/service/src/com/android/wm/shell/flicker/service/splitscreen/platinum/EnterSplitScreenByDragFromShortcutGesturalNavLandscape.kt diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/service/splitscreen/platinum/EnterSplitScreenByDragFromShortcutGesturalNavPortrait.kt b/libs/WindowManager/Shell/tests/flicker/service/src/com/android/wm/shell/flicker/service/splitscreen/platinum/EnterSplitScreenByDragFromShortcutGesturalNavPortrait.kt index 5c29fd8fe57e..5c29fd8fe57e 100644 --- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/service/splitscreen/platinum/EnterSplitScreenByDragFromShortcutGesturalNavPortrait.kt +++ b/libs/WindowManager/Shell/tests/flicker/service/src/com/android/wm/shell/flicker/service/splitscreen/platinum/EnterSplitScreenByDragFromShortcutGesturalNavPortrait.kt diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/service/splitscreen/platinum/EnterSplitScreenByDragFromTaskbarGesturalNavLandscape.kt b/libs/WindowManager/Shell/tests/flicker/service/src/com/android/wm/shell/flicker/service/splitscreen/platinum/EnterSplitScreenByDragFromTaskbarGesturalNavLandscape.kt index a7398ebf56e8..a7398ebf56e8 100644 --- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/service/splitscreen/platinum/EnterSplitScreenByDragFromTaskbarGesturalNavLandscape.kt +++ b/libs/WindowManager/Shell/tests/flicker/service/src/com/android/wm/shell/flicker/service/splitscreen/platinum/EnterSplitScreenByDragFromTaskbarGesturalNavLandscape.kt diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/service/splitscreen/platinum/EnterSplitScreenByDragFromTaskbarGesturalNavPortrait.kt b/libs/WindowManager/Shell/tests/flicker/service/src/com/android/wm/shell/flicker/service/splitscreen/platinum/EnterSplitScreenByDragFromTaskbarGesturalNavPortrait.kt index eae88ad4ad09..eae88ad4ad09 100644 --- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/service/splitscreen/platinum/EnterSplitScreenByDragFromTaskbarGesturalNavPortrait.kt +++ b/libs/WindowManager/Shell/tests/flicker/service/src/com/android/wm/shell/flicker/service/splitscreen/platinum/EnterSplitScreenByDragFromTaskbarGesturalNavPortrait.kt diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/service/splitscreen/platinum/EnterSplitScreenFromOverviewGesturalNavLandscape.kt b/libs/WindowManager/Shell/tests/flicker/service/src/com/android/wm/shell/flicker/service/splitscreen/platinum/EnterSplitScreenFromOverviewGesturalNavLandscape.kt index 7e8ee04a28fa..7e8ee04a28fa 100644 --- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/service/splitscreen/platinum/EnterSplitScreenFromOverviewGesturalNavLandscape.kt +++ b/libs/WindowManager/Shell/tests/flicker/service/src/com/android/wm/shell/flicker/service/splitscreen/platinum/EnterSplitScreenFromOverviewGesturalNavLandscape.kt diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/service/splitscreen/platinum/EnterSplitScreenFromOverviewGesturalNavPortrait.kt b/libs/WindowManager/Shell/tests/flicker/service/src/com/android/wm/shell/flicker/service/splitscreen/platinum/EnterSplitScreenFromOverviewGesturalNavPortrait.kt index 9295c330b879..9295c330b879 100644 --- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/service/splitscreen/platinum/EnterSplitScreenFromOverviewGesturalNavPortrait.kt +++ b/libs/WindowManager/Shell/tests/flicker/service/src/com/android/wm/shell/flicker/service/splitscreen/platinum/EnterSplitScreenFromOverviewGesturalNavPortrait.kt diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/service/splitscreen/platinum/SwitchAppByDoubleTapDividerGesturalNavLandscape.kt b/libs/WindowManager/Shell/tests/flicker/service/src/com/android/wm/shell/flicker/service/splitscreen/platinum/SwitchAppByDoubleTapDividerGesturalNavLandscape.kt index 4b59e9fbd866..4b59e9fbd866 100644 --- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/service/splitscreen/platinum/SwitchAppByDoubleTapDividerGesturalNavLandscape.kt +++ b/libs/WindowManager/Shell/tests/flicker/service/src/com/android/wm/shell/flicker/service/splitscreen/platinum/SwitchAppByDoubleTapDividerGesturalNavLandscape.kt diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/service/splitscreen/platinum/SwitchAppByDoubleTapDividerGesturalNavPortrait.kt b/libs/WindowManager/Shell/tests/flicker/service/src/com/android/wm/shell/flicker/service/splitscreen/platinum/SwitchAppByDoubleTapDividerGesturalNavPortrait.kt index 5ff36d4aabbb..5ff36d4aabbb 100644 --- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/service/splitscreen/platinum/SwitchAppByDoubleTapDividerGesturalNavPortrait.kt +++ b/libs/WindowManager/Shell/tests/flicker/service/src/com/android/wm/shell/flicker/service/splitscreen/platinum/SwitchAppByDoubleTapDividerGesturalNavPortrait.kt diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/service/splitscreen/platinum/SwitchBackToSplitFromAnotherAppGesturalNavLandscape.kt b/libs/WindowManager/Shell/tests/flicker/service/src/com/android/wm/shell/flicker/service/splitscreen/platinum/SwitchBackToSplitFromAnotherAppGesturalNavLandscape.kt index c0cb7219437b..c0cb7219437b 100644 --- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/service/splitscreen/platinum/SwitchBackToSplitFromAnotherAppGesturalNavLandscape.kt +++ b/libs/WindowManager/Shell/tests/flicker/service/src/com/android/wm/shell/flicker/service/splitscreen/platinum/SwitchBackToSplitFromAnotherAppGesturalNavLandscape.kt diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/service/splitscreen/platinum/SwitchBackToSplitFromAnotherAppGesturalNavPortrait.kt b/libs/WindowManager/Shell/tests/flicker/service/src/com/android/wm/shell/flicker/service/splitscreen/platinum/SwitchBackToSplitFromAnotherAppGesturalNavPortrait.kt index 8c140884aa50..8c140884aa50 100644 --- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/service/splitscreen/platinum/SwitchBackToSplitFromAnotherAppGesturalNavPortrait.kt +++ b/libs/WindowManager/Shell/tests/flicker/service/src/com/android/wm/shell/flicker/service/splitscreen/platinum/SwitchBackToSplitFromAnotherAppGesturalNavPortrait.kt diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/service/splitscreen/platinum/SwitchBackToSplitFromHomeGesturalNavLandscape.kt b/libs/WindowManager/Shell/tests/flicker/service/src/com/android/wm/shell/flicker/service/splitscreen/platinum/SwitchBackToSplitFromHomeGesturalNavLandscape.kt index 7b6614b81c11..7b6614b81c11 100644 --- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/service/splitscreen/platinum/SwitchBackToSplitFromHomeGesturalNavLandscape.kt +++ b/libs/WindowManager/Shell/tests/flicker/service/src/com/android/wm/shell/flicker/service/splitscreen/platinum/SwitchBackToSplitFromHomeGesturalNavLandscape.kt diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/service/splitscreen/platinum/SwitchBackToSplitFromHomeGesturalNavPortrait.kt b/libs/WindowManager/Shell/tests/flicker/service/src/com/android/wm/shell/flicker/service/splitscreen/platinum/SwitchBackToSplitFromHomeGesturalNavPortrait.kt index 5df5be9daa8b..5df5be9daa8b 100644 --- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/service/splitscreen/platinum/SwitchBackToSplitFromHomeGesturalNavPortrait.kt +++ b/libs/WindowManager/Shell/tests/flicker/service/src/com/android/wm/shell/flicker/service/splitscreen/platinum/SwitchBackToSplitFromHomeGesturalNavPortrait.kt diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/service/splitscreen/platinum/SwitchBackToSplitFromRecentGesturalNavLandscape.kt b/libs/WindowManager/Shell/tests/flicker/service/src/com/android/wm/shell/flicker/service/splitscreen/platinum/SwitchBackToSplitFromRecentGesturalNavLandscape.kt index 9d63003bf2a1..9d63003bf2a1 100644 --- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/service/splitscreen/platinum/SwitchBackToSplitFromRecentGesturalNavLandscape.kt +++ b/libs/WindowManager/Shell/tests/flicker/service/src/com/android/wm/shell/flicker/service/splitscreen/platinum/SwitchBackToSplitFromRecentGesturalNavLandscape.kt diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/service/splitscreen/platinum/SwitchBackToSplitFromRecentGesturalNavPortrait.kt b/libs/WindowManager/Shell/tests/flicker/service/src/com/android/wm/shell/flicker/service/splitscreen/platinum/SwitchBackToSplitFromRecentGesturalNavPortrait.kt index 9fa04b208ad1..9fa04b208ad1 100644 --- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/service/splitscreen/platinum/SwitchBackToSplitFromRecentGesturalNavPortrait.kt +++ b/libs/WindowManager/Shell/tests/flicker/service/src/com/android/wm/shell/flicker/service/splitscreen/platinum/SwitchBackToSplitFromRecentGesturalNavPortrait.kt diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/service/splitscreen/platinum/SwitchBetweenSplitPairsGesturalNavLandscape.kt b/libs/WindowManager/Shell/tests/flicker/service/src/com/android/wm/shell/flicker/service/splitscreen/platinum/SwitchBetweenSplitPairsGesturalNavLandscape.kt index 9386aa2b2cf0..9386aa2b2cf0 100644 --- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/service/splitscreen/platinum/SwitchBetweenSplitPairsGesturalNavLandscape.kt +++ b/libs/WindowManager/Shell/tests/flicker/service/src/com/android/wm/shell/flicker/service/splitscreen/platinum/SwitchBetweenSplitPairsGesturalNavLandscape.kt diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/service/splitscreen/platinum/SwitchBetweenSplitPairsGesturalNavPortrait.kt b/libs/WindowManager/Shell/tests/flicker/service/src/com/android/wm/shell/flicker/service/splitscreen/platinum/SwitchBetweenSplitPairsGesturalNavPortrait.kt index 5ef21672bfe0..5ef21672bfe0 100644 --- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/service/splitscreen/platinum/SwitchBetweenSplitPairsGesturalNavPortrait.kt +++ b/libs/WindowManager/Shell/tests/flicker/service/src/com/android/wm/shell/flicker/service/splitscreen/platinum/SwitchBetweenSplitPairsGesturalNavPortrait.kt diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/service/splitscreen/platinum/UnlockKeyguardToSplitScreenGesturalNavLandscape.kt b/libs/WindowManager/Shell/tests/flicker/service/src/com/android/wm/shell/flicker/service/splitscreen/platinum/UnlockKeyguardToSplitScreenGesturalNavLandscape.kt index 9caab9b5182a..9caab9b5182a 100644 --- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/service/splitscreen/platinum/UnlockKeyguardToSplitScreenGesturalNavLandscape.kt +++ b/libs/WindowManager/Shell/tests/flicker/service/src/com/android/wm/shell/flicker/service/splitscreen/platinum/UnlockKeyguardToSplitScreenGesturalNavLandscape.kt diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/service/splitscreen/platinum/UnlockKeyguardToSplitScreenGesturalNavPortrait.kt b/libs/WindowManager/Shell/tests/flicker/service/src/com/android/wm/shell/flicker/service/splitscreen/platinum/UnlockKeyguardToSplitScreenGesturalNavPortrait.kt index bf484e5cef98..bf484e5cef98 100644 --- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/service/splitscreen/platinum/UnlockKeyguardToSplitScreenGesturalNavPortrait.kt +++ b/libs/WindowManager/Shell/tests/flicker/service/src/com/android/wm/shell/flicker/service/splitscreen/platinum/UnlockKeyguardToSplitScreenGesturalNavPortrait.kt diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/service/splitscreen/scenarios/CopyContentInSplit.kt b/libs/WindowManager/Shell/tests/flicker/service/src/com/android/wm/shell/flicker/service/splitscreen/scenarios/CopyContentInSplit.kt index 80ab24ddf9ef..80ab24ddf9ef 100644 --- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/service/splitscreen/scenarios/CopyContentInSplit.kt +++ b/libs/WindowManager/Shell/tests/flicker/service/src/com/android/wm/shell/flicker/service/splitscreen/scenarios/CopyContentInSplit.kt diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/service/splitscreen/scenarios/DismissSplitScreenByDivider.kt b/libs/WindowManager/Shell/tests/flicker/service/src/com/android/wm/shell/flicker/service/splitscreen/scenarios/DismissSplitScreenByDivider.kt index 4c391047e853..4c391047e853 100644 --- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/service/splitscreen/scenarios/DismissSplitScreenByDivider.kt +++ b/libs/WindowManager/Shell/tests/flicker/service/src/com/android/wm/shell/flicker/service/splitscreen/scenarios/DismissSplitScreenByDivider.kt diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/service/splitscreen/scenarios/DismissSplitScreenByGoHome.kt b/libs/WindowManager/Shell/tests/flicker/service/src/com/android/wm/shell/flicker/service/splitscreen/scenarios/DismissSplitScreenByGoHome.kt index f6d1afc05a5a..f6d1afc05a5a 100644 --- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/service/splitscreen/scenarios/DismissSplitScreenByGoHome.kt +++ b/libs/WindowManager/Shell/tests/flicker/service/src/com/android/wm/shell/flicker/service/splitscreen/scenarios/DismissSplitScreenByGoHome.kt diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/service/splitscreen/scenarios/DragDividerToResize.kt b/libs/WindowManager/Shell/tests/flicker/service/src/com/android/wm/shell/flicker/service/splitscreen/scenarios/DragDividerToResize.kt index db5a32a382fb..db5a32a382fb 100644 --- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/service/splitscreen/scenarios/DragDividerToResize.kt +++ b/libs/WindowManager/Shell/tests/flicker/service/src/com/android/wm/shell/flicker/service/splitscreen/scenarios/DragDividerToResize.kt diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/service/splitscreen/scenarios/EnterSplitScreenByDragFromAllApps.kt b/libs/WindowManager/Shell/tests/flicker/service/src/com/android/wm/shell/flicker/service/splitscreen/scenarios/EnterSplitScreenByDragFromAllApps.kt index d7b306c3be23..d7b306c3be23 100644 --- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/service/splitscreen/scenarios/EnterSplitScreenByDragFromAllApps.kt +++ b/libs/WindowManager/Shell/tests/flicker/service/src/com/android/wm/shell/flicker/service/splitscreen/scenarios/EnterSplitScreenByDragFromAllApps.kt diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/service/splitscreen/scenarios/EnterSplitScreenByDragFromNotification.kt b/libs/WindowManager/Shell/tests/flicker/service/src/com/android/wm/shell/flicker/service/splitscreen/scenarios/EnterSplitScreenByDragFromNotification.kt index cc982d1ba860..cc982d1ba860 100644 --- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/service/splitscreen/scenarios/EnterSplitScreenByDragFromNotification.kt +++ b/libs/WindowManager/Shell/tests/flicker/service/src/com/android/wm/shell/flicker/service/splitscreen/scenarios/EnterSplitScreenByDragFromNotification.kt diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/service/splitscreen/scenarios/EnterSplitScreenByDragFromShortcut.kt b/libs/WindowManager/Shell/tests/flicker/service/src/com/android/wm/shell/flicker/service/splitscreen/scenarios/EnterSplitScreenByDragFromShortcut.kt index fa12bb869467..fa12bb869467 100644 --- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/service/splitscreen/scenarios/EnterSplitScreenByDragFromShortcut.kt +++ b/libs/WindowManager/Shell/tests/flicker/service/src/com/android/wm/shell/flicker/service/splitscreen/scenarios/EnterSplitScreenByDragFromShortcut.kt diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/service/splitscreen/scenarios/EnterSplitScreenByDragFromTaskbar.kt b/libs/WindowManager/Shell/tests/flicker/service/src/com/android/wm/shell/flicker/service/splitscreen/scenarios/EnterSplitScreenByDragFromTaskbar.kt index 2592fd40d902..2592fd40d902 100644 --- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/service/splitscreen/scenarios/EnterSplitScreenByDragFromTaskbar.kt +++ b/libs/WindowManager/Shell/tests/flicker/service/src/com/android/wm/shell/flicker/service/splitscreen/scenarios/EnterSplitScreenByDragFromTaskbar.kt diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/service/splitscreen/scenarios/EnterSplitScreenFromOverview.kt b/libs/WindowManager/Shell/tests/flicker/service/src/com/android/wm/shell/flicker/service/splitscreen/scenarios/EnterSplitScreenFromOverview.kt index 983653b9b5ca..983653b9b5ca 100644 --- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/service/splitscreen/scenarios/EnterSplitScreenFromOverview.kt +++ b/libs/WindowManager/Shell/tests/flicker/service/src/com/android/wm/shell/flicker/service/splitscreen/scenarios/EnterSplitScreenFromOverview.kt diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/service/splitscreen/scenarios/SwitchAppByDoubleTapDivider.kt b/libs/WindowManager/Shell/tests/flicker/service/src/com/android/wm/shell/flicker/service/splitscreen/scenarios/SwitchAppByDoubleTapDivider.kt index 068171d2e129..068171d2e129 100644 --- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/service/splitscreen/scenarios/SwitchAppByDoubleTapDivider.kt +++ b/libs/WindowManager/Shell/tests/flicker/service/src/com/android/wm/shell/flicker/service/splitscreen/scenarios/SwitchAppByDoubleTapDivider.kt diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/service/splitscreen/scenarios/SwitchBackToSplitFromAnotherApp.kt b/libs/WindowManager/Shell/tests/flicker/service/src/com/android/wm/shell/flicker/service/splitscreen/scenarios/SwitchBackToSplitFromAnotherApp.kt index 64b75c5fd967..64b75c5fd967 100644 --- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/service/splitscreen/scenarios/SwitchBackToSplitFromAnotherApp.kt +++ b/libs/WindowManager/Shell/tests/flicker/service/src/com/android/wm/shell/flicker/service/splitscreen/scenarios/SwitchBackToSplitFromAnotherApp.kt diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/service/splitscreen/scenarios/SwitchBackToSplitFromHome.kt b/libs/WindowManager/Shell/tests/flicker/service/src/com/android/wm/shell/flicker/service/splitscreen/scenarios/SwitchBackToSplitFromHome.kt index 179501089168..179501089168 100644 --- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/service/splitscreen/scenarios/SwitchBackToSplitFromHome.kt +++ b/libs/WindowManager/Shell/tests/flicker/service/src/com/android/wm/shell/flicker/service/splitscreen/scenarios/SwitchBackToSplitFromHome.kt diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/service/splitscreen/scenarios/SwitchBackToSplitFromRecent.kt b/libs/WindowManager/Shell/tests/flicker/service/src/com/android/wm/shell/flicker/service/splitscreen/scenarios/SwitchBackToSplitFromRecent.kt index 7065846dc653..7065846dc653 100644 --- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/service/splitscreen/scenarios/SwitchBackToSplitFromRecent.kt +++ b/libs/WindowManager/Shell/tests/flicker/service/src/com/android/wm/shell/flicker/service/splitscreen/scenarios/SwitchBackToSplitFromRecent.kt diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/service/splitscreen/scenarios/SwitchBetweenSplitPairs.kt b/libs/WindowManager/Shell/tests/flicker/service/src/com/android/wm/shell/flicker/service/splitscreen/scenarios/SwitchBetweenSplitPairs.kt index 251cb50de017..251cb50de017 100644 --- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/service/splitscreen/scenarios/SwitchBetweenSplitPairs.kt +++ b/libs/WindowManager/Shell/tests/flicker/service/src/com/android/wm/shell/flicker/service/splitscreen/scenarios/SwitchBetweenSplitPairs.kt diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/service/splitscreen/scenarios/UnlockKeyguardToSplitScreen.kt b/libs/WindowManager/Shell/tests/flicker/service/src/com/android/wm/shell/flicker/service/splitscreen/scenarios/UnlockKeyguardToSplitScreen.kt index a9933bbe09fc..a9933bbe09fc 100644 --- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/service/splitscreen/scenarios/UnlockKeyguardToSplitScreen.kt +++ b/libs/WindowManager/Shell/tests/flicker/service/src/com/android/wm/shell/flicker/service/splitscreen/scenarios/UnlockKeyguardToSplitScreen.kt diff --git a/libs/WindowManager/Shell/tests/flicker/service/trace_config/trace_config.textproto b/libs/WindowManager/Shell/tests/flicker/service/trace_config/trace_config.textproto new file mode 100644 index 000000000000..406ada97a07d --- /dev/null +++ b/libs/WindowManager/Shell/tests/flicker/service/trace_config/trace_config.textproto @@ -0,0 +1,75 @@ +# 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. + +# proto-message: TraceConfig + +# Enable periodic flushing of the trace buffer into the output file. +write_into_file: true + +# Writes the userspace buffer into the file every 1s. +file_write_period_ms: 2500 + +# See b/126487238 - we need to guarantee ordering of events. +flush_period_ms: 30000 + +# The trace buffers needs to be big enough to hold |file_write_period_ms| of +# trace data. The trace buffer sizing depends on the number of trace categories +# enabled and the device activity. + +# RSS events +buffers: { + size_kb: 63488 + fill_policy: RING_BUFFER +} + +data_sources { + config { + name: "linux.process_stats" + target_buffer: 0 + # polled per-process memory counters and process/thread names. + # If you don't want the polled counters, remove the "process_stats_config" + # section, but keep the data source itself as it still provides on-demand + # thread/process naming for ftrace data below. + process_stats_config { + scan_all_processes_on_start: true + } + } +} + +data_sources: { + config { + name: "linux.ftrace" + ftrace_config { + ftrace_events: "ftrace/print" + ftrace_events: "task/task_newtask" + ftrace_events: "task/task_rename" + atrace_categories: "ss" + atrace_categories: "wm" + atrace_categories: "am" + atrace_categories: "aidl" + atrace_categories: "input" + atrace_categories: "binder_driver" + atrace_categories: "sched_process_exit" + atrace_apps: "com.android.server.wm.flicker.testapp" + atrace_apps: "com.android.systemui" + atrace_apps: "com.android.wm.shell.flicker" + atrace_apps: "com.android.wm.shell.flicker.other" + atrace_apps: "com.android.wm.shell.flicker.bubbles" + atrace_apps: "com.android.wm.shell.flicker.pip" + atrace_apps: "com.android.wm.shell.flicker.splitscreen" + atrace_apps: "com.google.android.apps.nexuslauncher" + } + } +} + diff --git a/libs/WindowManager/Shell/tests/flicker/splitscreen/Android.bp b/libs/WindowManager/Shell/tests/flicker/splitscreen/Android.bp new file mode 100644 index 000000000000..4629c5318366 --- /dev/null +++ b/libs/WindowManager/Shell/tests/flicker/splitscreen/Android.bp @@ -0,0 +1,77 @@ +// +// Copyright (C) 2020 The Android Open Source Project +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// + +package { + // See: http://go/android-license-faq + // A large-scale-change added 'default_applicable_licenses' to import + // all of the 'license_kinds' from "frameworks_base_license" + // to get the below license kinds: + // SPDX-license-identifier-Apache-2.0 + default_applicable_licenses: ["frameworks_base_license"], +} + +filegroup { + name: "WMShellFlickerTestsSplitScreenBase-src", + srcs: [ + "src/**/benchmark/*.kt", + ], +} + +filegroup { + name: "WMShellFlickerTestsSplitScreenGroup1-src", + srcs: [ + "src/**/A*.kt", + "src/**/B*.kt", + "src/**/C*.kt", + "src/**/D*.kt", + "src/**/E*.kt", + ], +} + +filegroup { + name: "WMShellFlickerTestsSplitScreenGroup2-src", + srcs: [ + "src/**/*.kt", + ], +} + +android_test { + name: "WMShellFlickerTestsSplitScreenGroup1", + defaults: ["WMShellFlickerTestsDefault"], + manifest: "AndroidManifest.xml", + package_name: "com.android.wm.shell.flicker.splitscreen", + instrumentation_target_package: "com.android.wm.shell.flicker.splitscreen", + srcs: [ + ":WMShellFlickerTestsSplitScreenBase-src", + ":WMShellFlickerTestsSplitScreenGroup1-src", + ], + static_libs: ["WMShellFlickerTestsBase"], +} + +android_test { + name: "WMShellFlickerTestsSplitScreenGroup2", + manifest: "AndroidManifest.xml", + package_name: "com.android.wm.shell.flicker.splitscreen", + instrumentation_target_package: "com.android.wm.shell.flicker.splitscreen", + srcs: [ + ":WMShellFlickerTestsSplitScreenBase-src", + ":WMShellFlickerTestsSplitScreenGroup2-src", + ], + exclude_srcs: [ + ":WMShellFlickerTestsSplitScreenGroup1-src", + ], + static_libs: ["WMShellFlickerTestsBase"], +} diff --git a/libs/WindowManager/Shell/tests/flicker/splitscreen/AndroidManifest.xml b/libs/WindowManager/Shell/tests/flicker/splitscreen/AndroidManifest.xml new file mode 100644 index 000000000000..9ff2161daa51 --- /dev/null +++ b/libs/WindowManager/Shell/tests/flicker/splitscreen/AndroidManifest.xml @@ -0,0 +1,77 @@ +<!-- + ~ Copyright (C) 2023 The Android Open Source Project + ~ + ~ Licensed under the Apache License, Version 2.0 (the "License"); + ~ you may not use this file except in compliance with the License. + ~ You may obtain a copy of the License at + ~ + ~ http://www.apache.org/licenses/LICENSE-2.0 + ~ + ~ Unless required by applicable law or agreed to in writing, software + ~ distributed under the License is distributed on an "AS IS" BASIS, + ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + ~ See the License for the specific language governing permissions and + ~ limitations under the License. + --> + +<manifest xmlns:android="http://schemas.android.com/apk/res/android" + xmlns:tools="http://schemas.android.com/tools" + package="com.android.wm.shell.flicker.splitscreen"> + + <uses-sdk android:minSdkVersion="29" android:targetSdkVersion="29"/> + <!-- Read and write traces from external storage --> + <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" /> + <uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" /> + <!-- Allow the test to write directly to /sdcard/ --> + <uses-permission android:name="android.permission.MANAGE_EXTERNAL_STORAGE" /> + <!-- Write secure settings --> + <uses-permission android:name="android.permission.WRITE_SECURE_SETTINGS" /> + <!-- Capture screen contents --> + <uses-permission android:name="android.permission.ACCESS_SURFACE_FLINGER" /> + <!-- Enable / Disable tracing !--> + <uses-permission android:name="android.permission.DUMP" /> + <!-- Run layers trace --> + <uses-permission android:name="android.permission.HARDWARE_TEST"/> + <!-- Capture screen recording --> + <uses-permission android:name="android.permission.CAPTURE_VIDEO_OUTPUT"/> + <!-- Workaround grant runtime permission exception from b/152733071 --> + <uses-permission android:name="android.permission.PACKAGE_USAGE_STATS"/> + <uses-permission android:name="android.permission.READ_LOGS"/> + <!-- Force-stop test apps --> + <uses-permission android:name="android.permission.FORCE_STOP_PACKAGES"/> + <!-- Control test app's media session --> + <uses-permission android:name="android.permission.MEDIA_CONTENT_CONTROL"/> + <!-- ATM.removeRootTasksWithActivityTypes() --> + <uses-permission android:name="android.permission.MANAGE_ACTIVITY_TASKS" /> + <!-- Enable bubble notification--> + <uses-permission android:name="android.permission.STATUS_BAR_SERVICE" /> + <!-- Allow the test to connect to perfetto trace processor --> + <uses-permission android:name="android.permission.INTERNET"/> + + <!-- Allow the test to write directly to /sdcard/ and connect to trace processor --> + <application android:requestLegacyExternalStorage="true" + android:networkSecurityConfig="@xml/network_security_config" + android:largeHeap="true"> + <uses-library android:name="android.test.runner"/> + + <service android:name=".NotificationListener" + android:exported="true" + android:label="WMShellTestsNotificationListenerService" + android:permission="android.permission.BIND_NOTIFICATION_LISTENER_SERVICE"> + <intent-filter> + <action android:name="android.service.notification.NotificationListenerService" /> + </intent-filter> + </service> + + <!-- (b/197936012) Remove startup provider due to test timeout issue --> + <provider + android:name="androidx.startup.InitializationProvider" + android:authorities="${applicationId}.androidx-startup" + tools:node="remove" /> + </application> + + <instrumentation android:name="androidx.test.runner.AndroidJUnitRunner" + android:targetPackage="com.android.wm.shell.flicker.splitscreen" + android:label="WindowManager Flicker Tests"> + </instrumentation> +</manifest> diff --git a/libs/WindowManager/Shell/tests/flicker/splitscreen/AndroidTestTemplate.xml b/libs/WindowManager/Shell/tests/flicker/splitscreen/AndroidTestTemplate.xml new file mode 100644 index 000000000000..1df11369a049 --- /dev/null +++ b/libs/WindowManager/Shell/tests/flicker/splitscreen/AndroidTestTemplate.xml @@ -0,0 +1,109 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- + ~ Copyright (C) 2023 The Android Open Source Project + ~ + ~ Licensed under the Apache License, Version 2.0 (the "License"); + ~ you may not use this file except in compliance with the License. + ~ You may obtain a copy of the License at + ~ + ~ http://www.apache.org/licenses/LICENSE-2.0 + ~ + ~ Unless required by applicable law or agreed to in writing, software + ~ distributed under the License is distributed on an "AS IS" BASIS, + ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + ~ See the License for the specific language governing permissions and + ~ limitations under the License. + --> +<configuration description="Runs WindowManager Shell Flicker Tests {MODULE}"> + <option name="test-tag" value="FlickerTests"/> + <!-- Needed for storing the perfetto trace files in the sdcard/test_results--> + <option name="isolated-storage" value="false"/> + + <target_preparer class="com.android.tradefed.targetprep.DeviceSetup"> + <!-- keeps the screen on during tests --> + <option name="screen-always-on" value="on"/> + <!-- prevents the phone from restarting --> + <option name="force-skip-system-props" value="true"/> + <!-- set WM tracing verbose level to all --> + <option name="run-command" value="cmd window tracing level all"/> + <!-- set WM tracing to frame (avoid incomplete states) --> + <option name="run-command" value="cmd window tracing frame"/> + <!-- disable betterbug as it's log collection dialogues cause flakes in e2e tests --> + <option name="run-command" value="pm disable com.google.android.internal.betterbug"/> + <!-- ensure lock screen mode is swipe --> + <option name="run-command" value="locksettings set-disabled false"/> + <!-- restart launcher to activate TAPL --> + <option name="run-command" + value="setprop ro.test_harness 1 ; am force-stop com.google.android.apps.nexuslauncher"/> + <!-- Increase trace size: 20mb for WM and 80mb for SF --> + <option name="run-command" value="cmd window tracing size 20480"/> + <option name="run-command" value="su root service call SurfaceFlinger 1029 i32 81920"/> + </target_preparer> + <target_preparer class="com.android.tradefed.targetprep.RunCommandTargetPreparer"> + <option name="test-user-token" value="%TEST_USER%"/> + <option name="run-command" value="rm -rf /data/user/%TEST_USER%/files/*"/> + <option name="run-command" value="settings put secure show_ime_with_hard_keyboard 1"/> + <option name="run-command" value="settings put system show_touches 1"/> + <option name="run-command" value="settings put system pointer_location 1"/> + <option name="teardown-command" + value="settings delete secure show_ime_with_hard_keyboard"/> + <option name="teardown-command" value="settings delete system show_touches"/> + <option name="teardown-command" value="settings delete system pointer_location"/> + <option name="teardown-command" + value="cmd overlay enable com.android.internal.systemui.navbar.gestural"/> + </target_preparer> + <target_preparer class="com.android.tradefed.targetprep.suite.SuiteApkInstaller"> + <option name="cleanup-apks" value="true"/> + <option name="test-file-name" value="{MODULE}.apk"/> + <option name="test-file-name" value="FlickerTestApp.apk"/> + </target_preparer> + <!-- Enable mocking GPS location by the test app --> + <target_preparer class="com.android.tradefed.targetprep.RunCommandTargetPreparer"> + <option name="run-command" + value="appops set com.android.wm.shell.flicker.pip.apps android:mock_location allow"/> + <option name="teardown-command" + value="appops set com.android.wm.shell.flicker.pip.apps android:mock_location deny"/> + </target_preparer> + + <!-- Needed for pushing the trace config file --> + <target_preparer class="com.android.tradefed.targetprep.RootTargetPreparer"/> + <target_preparer class="com.android.tradefed.targetprep.PushFilePreparer"> + <option name="push-file" + key="trace_config.textproto" + value="/data/misc/perfetto-traces/trace_config.textproto" + /> + <!--Install the content provider automatically when we push some file in sdcard folder.--> + <!--Needed to avoid the installation during the test suite.--> + <option name="push-file" key="trace_config.textproto" value="/sdcard/sample.textproto"/> + </target_preparer> + <test class="com.android.tradefed.testtype.AndroidJUnitTest"> + <option name="package" value="{PACKAGE}"/> + <option name="shell-timeout" value="6600s"/> + <option name="test-timeout" value="6000s"/> + <option name="hidden-api-checks" value="false"/> + <option name="device-listeners" value="android.device.collectors.PerfettoListener"/> + <!-- PerfettoListener related arguments --> + <option name="instrumentation-arg" key="perfetto_config_text_proto" value="true"/> + <option name="instrumentation-arg" + key="perfetto_config_file" + value="trace_config.textproto" + /> + <option name="instrumentation-arg" key="per_run" value="true"/> + </test> + <!-- Needed for pulling the collected trace config on to the host --> + <metrics_collector class="com.android.tradefed.device.metric.FilePullerLogCollector"> + <option name="pull-pattern-keys" value="perfetto_file_path"/> + <option name="directory-keys" + value="/data/user/0/com.android.wm.shell.flicker/files"/> + <option name="directory-keys" + value="/data/user/0/com.android.wm.shell.flicker.bubbles/files"/> + <option name="directory-keys" + value="/data/user/0/com.android.wm.shell.flicker.pip/files"/> + <option name="directory-keys" + value="/data/user/0/com.android.wm.shell.flicker.splitscreen/files"/> + <option name="directory-keys" + value="/data/user/0/com.android.wm.shell.flicker.service/files"/> + <option name="collect-on-run-ended-only" value="true"/> + <option name="clean-up" value="true"/> + </metrics_collector> +</configuration> diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/splitscreen/OWNERS b/libs/WindowManager/Shell/tests/flicker/splitscreen/OWNERS index 3ab6a1ee061d..3ab6a1ee061d 100644 --- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/splitscreen/OWNERS +++ b/libs/WindowManager/Shell/tests/flicker/splitscreen/OWNERS diff --git a/libs/WindowManager/Shell/tests/flicker/manifests/AndroidManifestSplitScreen.xml b/libs/WindowManager/Shell/tests/flicker/splitscreen/res/xml/network_security_config.xml index 887d8db3042f..4bd9ca049f55 100644 --- a/libs/WindowManager/Shell/tests/flicker/manifests/AndroidManifestSplitScreen.xml +++ b/libs/WindowManager/Shell/tests/flicker/splitscreen/res/xml/network_security_config.xml @@ -1,3 +1,4 @@ +<?xml version="1.0" encoding="utf-8"?> <!-- ~ Copyright (C) 2023 The Android Open Source Project ~ @@ -14,11 +15,8 @@ ~ limitations under the License. --> -<manifest xmlns:android="http://schemas.android.com/apk/res/android" - package="com.android.wm.shell.flicker.splitscreen"> - - <instrumentation android:name="androidx.test.runner.AndroidJUnitRunner" - android:targetPackage="com.android.wm.shell.flicker.splitscreen" - android:label="WindowManager Flicker Tests"> - </instrumentation> -</manifest> +<network-security-config> + <domain-config cleartextTrafficPermitted="true"> + <domain includeSubdomains="true">localhost</domain> + </domain-config> +</network-security-config> diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/splitscreen/CopyContentInSplit.kt b/libs/WindowManager/Shell/tests/flicker/splitscreen/src/com/android/wm/shell/flicker/splitscreen/CopyContentInSplit.kt index 6b971699d212..6b971699d212 100644 --- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/splitscreen/CopyContentInSplit.kt +++ b/libs/WindowManager/Shell/tests/flicker/splitscreen/src/com/android/wm/shell/flicker/splitscreen/CopyContentInSplit.kt diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/splitscreen/DismissSplitScreenByDivider.kt b/libs/WindowManager/Shell/tests/flicker/splitscreen/src/com/android/wm/shell/flicker/splitscreen/DismissSplitScreenByDivider.kt index 51588569a8aa..51588569a8aa 100644 --- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/splitscreen/DismissSplitScreenByDivider.kt +++ b/libs/WindowManager/Shell/tests/flicker/splitscreen/src/com/android/wm/shell/flicker/splitscreen/DismissSplitScreenByDivider.kt diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/splitscreen/DismissSplitScreenByGoHome.kt b/libs/WindowManager/Shell/tests/flicker/splitscreen/src/com/android/wm/shell/flicker/splitscreen/DismissSplitScreenByGoHome.kt index fc6c2b3d7ce7..fc6c2b3d7ce7 100644 --- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/splitscreen/DismissSplitScreenByGoHome.kt +++ b/libs/WindowManager/Shell/tests/flicker/splitscreen/src/com/android/wm/shell/flicker/splitscreen/DismissSplitScreenByGoHome.kt diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/splitscreen/DragDividerToResize.kt b/libs/WindowManager/Shell/tests/flicker/splitscreen/src/com/android/wm/shell/flicker/splitscreen/DragDividerToResize.kt index 8b1689a9d816..8b1689a9d816 100644 --- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/splitscreen/DragDividerToResize.kt +++ b/libs/WindowManager/Shell/tests/flicker/splitscreen/src/com/android/wm/shell/flicker/splitscreen/DragDividerToResize.kt diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/splitscreen/EnterSplitScreenByDragFromAllApps.kt b/libs/WindowManager/Shell/tests/flicker/splitscreen/src/com/android/wm/shell/flicker/splitscreen/EnterSplitScreenByDragFromAllApps.kt index 99613f39060d..99613f39060d 100644 --- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/splitscreen/EnterSplitScreenByDragFromAllApps.kt +++ b/libs/WindowManager/Shell/tests/flicker/splitscreen/src/com/android/wm/shell/flicker/splitscreen/EnterSplitScreenByDragFromAllApps.kt diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/splitscreen/EnterSplitScreenByDragFromNotification.kt b/libs/WindowManager/Shell/tests/flicker/splitscreen/src/com/android/wm/shell/flicker/splitscreen/EnterSplitScreenByDragFromNotification.kt index 756a7fa4ba98..756a7fa4ba98 100644 --- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/splitscreen/EnterSplitScreenByDragFromNotification.kt +++ b/libs/WindowManager/Shell/tests/flicker/splitscreen/src/com/android/wm/shell/flicker/splitscreen/EnterSplitScreenByDragFromNotification.kt diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/splitscreen/EnterSplitScreenByDragFromShortcut.kt b/libs/WindowManager/Shell/tests/flicker/splitscreen/src/com/android/wm/shell/flicker/splitscreen/EnterSplitScreenByDragFromShortcut.kt index 121b46acdb66..121b46acdb66 100644 --- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/splitscreen/EnterSplitScreenByDragFromShortcut.kt +++ b/libs/WindowManager/Shell/tests/flicker/splitscreen/src/com/android/wm/shell/flicker/splitscreen/EnterSplitScreenByDragFromShortcut.kt diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/splitscreen/EnterSplitScreenByDragFromTaskbar.kt b/libs/WindowManager/Shell/tests/flicker/splitscreen/src/com/android/wm/shell/flicker/splitscreen/EnterSplitScreenByDragFromTaskbar.kt index 99deb9279271..99deb9279271 100644 --- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/splitscreen/EnterSplitScreenByDragFromTaskbar.kt +++ b/libs/WindowManager/Shell/tests/flicker/splitscreen/src/com/android/wm/shell/flicker/splitscreen/EnterSplitScreenByDragFromTaskbar.kt diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/splitscreen/EnterSplitScreenFromOverview.kt b/libs/WindowManager/Shell/tests/flicker/splitscreen/src/com/android/wm/shell/flicker/splitscreen/EnterSplitScreenFromOverview.kt index 212a4e3649dc..212a4e3649dc 100644 --- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/splitscreen/EnterSplitScreenFromOverview.kt +++ b/libs/WindowManager/Shell/tests/flicker/splitscreen/src/com/android/wm/shell/flicker/splitscreen/EnterSplitScreenFromOverview.kt diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/splitscreen/SwitchAppByDoubleTapDivider.kt b/libs/WindowManager/Shell/tests/flicker/splitscreen/src/com/android/wm/shell/flicker/splitscreen/SwitchAppByDoubleTapDivider.kt index fac97c8cc8c4..fac97c8cc8c4 100644 --- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/splitscreen/SwitchAppByDoubleTapDivider.kt +++ b/libs/WindowManager/Shell/tests/flicker/splitscreen/src/com/android/wm/shell/flicker/splitscreen/SwitchAppByDoubleTapDivider.kt diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/splitscreen/SwitchBackToSplitFromAnotherApp.kt b/libs/WindowManager/Shell/tests/flicker/splitscreen/src/com/android/wm/shell/flicker/splitscreen/SwitchBackToSplitFromAnotherApp.kt index 284c32ea110d..284c32ea110d 100644 --- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/splitscreen/SwitchBackToSplitFromAnotherApp.kt +++ b/libs/WindowManager/Shell/tests/flicker/splitscreen/src/com/android/wm/shell/flicker/splitscreen/SwitchBackToSplitFromAnotherApp.kt diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/splitscreen/SwitchBackToSplitFromHome.kt b/libs/WindowManager/Shell/tests/flicker/splitscreen/src/com/android/wm/shell/flicker/splitscreen/SwitchBackToSplitFromHome.kt index 9e6448f0bec9..9e6448f0bec9 100644 --- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/splitscreen/SwitchBackToSplitFromHome.kt +++ b/libs/WindowManager/Shell/tests/flicker/splitscreen/src/com/android/wm/shell/flicker/splitscreen/SwitchBackToSplitFromHome.kt diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/splitscreen/SwitchBackToSplitFromRecent.kt b/libs/WindowManager/Shell/tests/flicker/splitscreen/src/com/android/wm/shell/flicker/splitscreen/SwitchBackToSplitFromRecent.kt index 8e28712cd993..8e28712cd993 100644 --- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/splitscreen/SwitchBackToSplitFromRecent.kt +++ b/libs/WindowManager/Shell/tests/flicker/splitscreen/src/com/android/wm/shell/flicker/splitscreen/SwitchBackToSplitFromRecent.kt diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/splitscreen/SwitchBetweenSplitPairs.kt b/libs/WindowManager/Shell/tests/flicker/splitscreen/src/com/android/wm/shell/flicker/splitscreen/SwitchBetweenSplitPairs.kt index fb0193b1830d..fb0193b1830d 100644 --- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/splitscreen/SwitchBetweenSplitPairs.kt +++ b/libs/WindowManager/Shell/tests/flicker/splitscreen/src/com/android/wm/shell/flicker/splitscreen/SwitchBetweenSplitPairs.kt diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/splitscreen/SwitchBetweenSplitPairsNoPip.kt b/libs/WindowManager/Shell/tests/flicker/splitscreen/src/com/android/wm/shell/flicker/splitscreen/SwitchBetweenSplitPairsNoPip.kt index 13875362a1c8..715a533a7bab 100644 --- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/splitscreen/SwitchBetweenSplitPairsNoPip.kt +++ b/libs/WindowManager/Shell/tests/flicker/splitscreen/src/com/android/wm/shell/flicker/splitscreen/SwitchBetweenSplitPairsNoPip.kt @@ -62,10 +62,22 @@ class SwitchBetweenSplitPairsNoPip(override val flicker: LegacyFlickerTest) : get() = { setup { tapl.goHome() - SplitScreenUtils.enterSplit(wmHelper, tapl, device, primaryApp, - secondaryApp, flicker.scenario.startRotation) - SplitScreenUtils.enterSplit(wmHelper, tapl, device, thirdApp, pipApp, - flicker.scenario.startRotation) + SplitScreenUtils.enterSplit( + wmHelper, + tapl, + device, + primaryApp, + secondaryApp, + flicker.scenario.startRotation + ) + SplitScreenUtils.enterSplit( + wmHelper, + tapl, + device, + thirdApp, + pipApp, + flicker.scenario.startRotation + ) pipApp.enableAutoEnterForPipActivity() SplitScreenUtils.waitForSplitComplete(wmHelper, thirdApp, pipApp) } diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/splitscreen/UnlockKeyguardToSplitScreen.kt b/libs/WindowManager/Shell/tests/flicker/splitscreen/src/com/android/wm/shell/flicker/splitscreen/UnlockKeyguardToSplitScreen.kt index f3145c97a6f1..f3145c97a6f1 100644 --- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/splitscreen/UnlockKeyguardToSplitScreen.kt +++ b/libs/WindowManager/Shell/tests/flicker/splitscreen/src/com/android/wm/shell/flicker/splitscreen/UnlockKeyguardToSplitScreen.kt diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/splitscreen/benchmark/CopyContentInSplitBenchmark.kt b/libs/WindowManager/Shell/tests/flicker/splitscreen/src/com/android/wm/shell/flicker/splitscreen/benchmark/CopyContentInSplitBenchmark.kt index 3b9e53f9ce04..df1c9a2ec089 100644 --- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/splitscreen/benchmark/CopyContentInSplitBenchmark.kt +++ b/libs/WindowManager/Shell/tests/flicker/splitscreen/src/com/android/wm/shell/flicker/splitscreen/benchmark/CopyContentInSplitBenchmark.kt @@ -39,8 +39,16 @@ abstract class CopyContentInSplitBenchmark(override val flicker: LegacyFlickerTe protected val popupWindowLayer = ComponentNameMatcher("", "PopupWindow:") protected val thisTransition: FlickerBuilder.() -> Unit get() = { - setup { SplitScreenUtils.enterSplit(wmHelper, tapl, device, primaryApp, - textEditApp, flicker.scenario.startRotation) } + setup { + SplitScreenUtils.enterSplit( + wmHelper, + tapl, + device, + primaryApp, + textEditApp, + flicker.scenario.startRotation + ) + } transitions { SplitScreenUtils.copyContentInSplit( instrumentation, diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/splitscreen/benchmark/DismissSplitScreenByDividerBenchmark.kt b/libs/WindowManager/Shell/tests/flicker/splitscreen/src/com/android/wm/shell/flicker/splitscreen/benchmark/DismissSplitScreenByDividerBenchmark.kt index 5fdde3ad23d2..d01eab060263 100644 --- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/splitscreen/benchmark/DismissSplitScreenByDividerBenchmark.kt +++ b/libs/WindowManager/Shell/tests/flicker/splitscreen/src/com/android/wm/shell/flicker/splitscreen/benchmark/DismissSplitScreenByDividerBenchmark.kt @@ -35,8 +35,16 @@ abstract class DismissSplitScreenByDividerBenchmark(override val flicker: Legacy SplitScreenBase(flicker) { protected val thisTransition: FlickerBuilder.() -> Unit get() = { - setup { SplitScreenUtils.enterSplit(wmHelper, tapl, device, primaryApp, - secondaryApp, flicker.scenario.startRotation) } + setup { + SplitScreenUtils.enterSplit( + wmHelper, + tapl, + device, + primaryApp, + secondaryApp, + flicker.scenario.startRotation + ) + } transitions { if (tapl.isTablet) { SplitScreenUtils.dragDividerToDismissSplit( diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/splitscreen/benchmark/DismissSplitScreenByGoHomeBenchmark.kt b/libs/WindowManager/Shell/tests/flicker/splitscreen/src/com/android/wm/shell/flicker/splitscreen/benchmark/DismissSplitScreenByGoHomeBenchmark.kt index b7f6bfe7efd6..e36bd33bd1fd 100644 --- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/splitscreen/benchmark/DismissSplitScreenByGoHomeBenchmark.kt +++ b/libs/WindowManager/Shell/tests/flicker/splitscreen/src/com/android/wm/shell/flicker/splitscreen/benchmark/DismissSplitScreenByGoHomeBenchmark.kt @@ -36,8 +36,14 @@ abstract class DismissSplitScreenByGoHomeBenchmark(override val flicker: LegacyF protected val thisTransition: FlickerBuilder.() -> Unit get() = { setup { - SplitScreenUtils.enterSplit(wmHelper, tapl, device, primaryApp, secondaryApp, - flicker.scenario.startRotation) + SplitScreenUtils.enterSplit( + wmHelper, + tapl, + device, + primaryApp, + secondaryApp, + flicker.scenario.startRotation + ) } transitions { tapl.goHome() diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/splitscreen/benchmark/DragDividerToResizeBenchmark.kt b/libs/WindowManager/Shell/tests/flicker/splitscreen/src/com/android/wm/shell/flicker/splitscreen/benchmark/DragDividerToResizeBenchmark.kt index bb2a7aabed1b..050d389e978c 100644 --- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/splitscreen/benchmark/DragDividerToResizeBenchmark.kt +++ b/libs/WindowManager/Shell/tests/flicker/splitscreen/src/com/android/wm/shell/flicker/splitscreen/benchmark/DragDividerToResizeBenchmark.kt @@ -37,8 +37,16 @@ abstract class DragDividerToResizeBenchmark(override val flicker: LegacyFlickerT SplitScreenBase(flicker) { protected val thisTransition: FlickerBuilder.() -> Unit get() = { - setup { SplitScreenUtils.enterSplit(wmHelper, tapl, device, primaryApp, - secondaryApp, flicker.scenario.startRotation) } + setup { + SplitScreenUtils.enterSplit( + wmHelper, + tapl, + device, + primaryApp, + secondaryApp, + flicker.scenario.startRotation + ) + } transitions { SplitScreenUtils.dragDividerToResizeAndWait(device, wmHelper) } } diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/splitscreen/benchmark/EnterSplitScreenByDragFromAllAppsBenchmark.kt b/libs/WindowManager/Shell/tests/flicker/splitscreen/src/com/android/wm/shell/flicker/splitscreen/benchmark/EnterSplitScreenByDragFromAllAppsBenchmark.kt index 394864ad9d4d..394864ad9d4d 100644 --- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/splitscreen/benchmark/EnterSplitScreenByDragFromAllAppsBenchmark.kt +++ b/libs/WindowManager/Shell/tests/flicker/splitscreen/src/com/android/wm/shell/flicker/splitscreen/benchmark/EnterSplitScreenByDragFromAllAppsBenchmark.kt diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/splitscreen/benchmark/EnterSplitScreenByDragFromNotificationBenchmark.kt b/libs/WindowManager/Shell/tests/flicker/splitscreen/src/com/android/wm/shell/flicker/splitscreen/benchmark/EnterSplitScreenByDragFromNotificationBenchmark.kt index cd3fbab1497b..cd3fbab1497b 100644 --- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/splitscreen/benchmark/EnterSplitScreenByDragFromNotificationBenchmark.kt +++ b/libs/WindowManager/Shell/tests/flicker/splitscreen/src/com/android/wm/shell/flicker/splitscreen/benchmark/EnterSplitScreenByDragFromNotificationBenchmark.kt diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/splitscreen/benchmark/EnterSplitScreenByDragFromShortcutBenchmark.kt b/libs/WindowManager/Shell/tests/flicker/splitscreen/src/com/android/wm/shell/flicker/splitscreen/benchmark/EnterSplitScreenByDragFromShortcutBenchmark.kt index 3b3be84f9841..3b3be84f9841 100644 --- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/splitscreen/benchmark/EnterSplitScreenByDragFromShortcutBenchmark.kt +++ b/libs/WindowManager/Shell/tests/flicker/splitscreen/src/com/android/wm/shell/flicker/splitscreen/benchmark/EnterSplitScreenByDragFromShortcutBenchmark.kt diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/splitscreen/benchmark/EnterSplitScreenByDragFromTaskbarBenchmark.kt b/libs/WindowManager/Shell/tests/flicker/splitscreen/src/com/android/wm/shell/flicker/splitscreen/benchmark/EnterSplitScreenByDragFromTaskbarBenchmark.kt index eff355987cc0..eff355987cc0 100644 --- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/splitscreen/benchmark/EnterSplitScreenByDragFromTaskbarBenchmark.kt +++ b/libs/WindowManager/Shell/tests/flicker/splitscreen/src/com/android/wm/shell/flicker/splitscreen/benchmark/EnterSplitScreenByDragFromTaskbarBenchmark.kt diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/splitscreen/benchmark/EnterSplitScreenFromOverviewBenchmark.kt b/libs/WindowManager/Shell/tests/flicker/splitscreen/src/com/android/wm/shell/flicker/splitscreen/benchmark/EnterSplitScreenFromOverviewBenchmark.kt index 5e5e7d7fc3c9..5e5e7d7fc3c9 100644 --- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/splitscreen/benchmark/EnterSplitScreenFromOverviewBenchmark.kt +++ b/libs/WindowManager/Shell/tests/flicker/splitscreen/src/com/android/wm/shell/flicker/splitscreen/benchmark/EnterSplitScreenFromOverviewBenchmark.kt diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/splitscreen/benchmark/SplitScreenBase.kt b/libs/WindowManager/Shell/tests/flicker/splitscreen/src/com/android/wm/shell/flicker/splitscreen/benchmark/SplitScreenBase.kt index a0e437c25aa7..a0e437c25aa7 100644 --- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/splitscreen/benchmark/SplitScreenBase.kt +++ b/libs/WindowManager/Shell/tests/flicker/splitscreen/src/com/android/wm/shell/flicker/splitscreen/benchmark/SplitScreenBase.kt diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/splitscreen/benchmark/SwitchAppByDoubleTapDividerBenchmark.kt b/libs/WindowManager/Shell/tests/flicker/splitscreen/src/com/android/wm/shell/flicker/splitscreen/benchmark/SwitchAppByDoubleTapDividerBenchmark.kt index 46b0bd226daf..e39c3c93d79a 100644 --- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/splitscreen/benchmark/SwitchAppByDoubleTapDividerBenchmark.kt +++ b/libs/WindowManager/Shell/tests/flicker/splitscreen/src/com/android/wm/shell/flicker/splitscreen/benchmark/SwitchAppByDoubleTapDividerBenchmark.kt @@ -39,8 +39,16 @@ abstract class SwitchAppByDoubleTapDividerBenchmark(override val flicker: Legacy SplitScreenBase(flicker) { protected val thisTransition: FlickerBuilder.() -> Unit get() = { - setup { SplitScreenUtils.enterSplit(wmHelper, tapl, device, primaryApp, - secondaryApp, flicker.scenario.startRotation) } + setup { + SplitScreenUtils.enterSplit( + wmHelper, + tapl, + device, + primaryApp, + secondaryApp, + flicker.scenario.startRotation + ) + } transitions { SplitScreenUtils.doubleTapDividerToSwitch(device) wmHelper.StateSyncBuilder().withAppTransitionIdle().waitForAndVerify() diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/splitscreen/benchmark/SwitchBackToSplitFromAnotherAppBenchmark.kt b/libs/WindowManager/Shell/tests/flicker/splitscreen/src/com/android/wm/shell/flicker/splitscreen/benchmark/SwitchBackToSplitFromAnotherAppBenchmark.kt index baf76932c7ac..32284ba41aee 100644 --- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/splitscreen/benchmark/SwitchBackToSplitFromAnotherAppBenchmark.kt +++ b/libs/WindowManager/Shell/tests/flicker/splitscreen/src/com/android/wm/shell/flicker/splitscreen/benchmark/SwitchBackToSplitFromAnotherAppBenchmark.kt @@ -39,8 +39,14 @@ abstract class SwitchBackToSplitFromAnotherAppBenchmark(override val flicker: Le protected val thisTransition: FlickerBuilder.() -> Unit get() = { setup { - SplitScreenUtils.enterSplit(wmHelper, tapl, device, primaryApp, - secondaryApp, flicker.scenario.startRotation) + SplitScreenUtils.enterSplit( + wmHelper, + tapl, + device, + primaryApp, + secondaryApp, + flicker.scenario.startRotation + ) thirdApp.launchViaIntent(wmHelper) wmHelper.StateSyncBuilder().withWindowSurfaceAppeared(thirdApp).waitForAndVerify() diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/splitscreen/benchmark/SwitchBackToSplitFromHomeBenchmark.kt b/libs/WindowManager/Shell/tests/flicker/splitscreen/src/com/android/wm/shell/flicker/splitscreen/benchmark/SwitchBackToSplitFromHomeBenchmark.kt index 33b55f1a57d8..a926ec903f58 100644 --- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/splitscreen/benchmark/SwitchBackToSplitFromHomeBenchmark.kt +++ b/libs/WindowManager/Shell/tests/flicker/splitscreen/src/com/android/wm/shell/flicker/splitscreen/benchmark/SwitchBackToSplitFromHomeBenchmark.kt @@ -37,8 +37,14 @@ abstract class SwitchBackToSplitFromHomeBenchmark(override val flicker: LegacyFl protected val thisTransition: FlickerBuilder.() -> Unit get() = { setup { - SplitScreenUtils.enterSplit(wmHelper, tapl, device, primaryApp, - secondaryApp, flicker.scenario.startRotation) + SplitScreenUtils.enterSplit( + wmHelper, + tapl, + device, + primaryApp, + secondaryApp, + flicker.scenario.startRotation + ) tapl.goHome() wmHelper.StateSyncBuilder().withHomeActivityVisible().waitForAndVerify() diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/splitscreen/benchmark/SwitchBackToSplitFromRecentBenchmark.kt b/libs/WindowManager/Shell/tests/flicker/splitscreen/src/com/android/wm/shell/flicker/splitscreen/benchmark/SwitchBackToSplitFromRecentBenchmark.kt index b79dfb5f0665..d2e1d5294aa1 100644 --- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/splitscreen/benchmark/SwitchBackToSplitFromRecentBenchmark.kt +++ b/libs/WindowManager/Shell/tests/flicker/splitscreen/src/com/android/wm/shell/flicker/splitscreen/benchmark/SwitchBackToSplitFromRecentBenchmark.kt @@ -37,8 +37,14 @@ abstract class SwitchBackToSplitFromRecentBenchmark(override val flicker: Legacy protected val thisTransition: FlickerBuilder.() -> Unit get() = { setup { - SplitScreenUtils.enterSplit(wmHelper, tapl, device, primaryApp, - secondaryApp, flicker.scenario.startRotation) + SplitScreenUtils.enterSplit( + wmHelper, + tapl, + device, + primaryApp, + secondaryApp, + flicker.scenario.startRotation + ) tapl.goHome() wmHelper.StateSyncBuilder().withHomeActivityVisible().waitForAndVerify() diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/splitscreen/benchmark/SwitchBetweenSplitPairsBenchmark.kt b/libs/WindowManager/Shell/tests/flicker/splitscreen/src/com/android/wm/shell/flicker/splitscreen/benchmark/SwitchBetweenSplitPairsBenchmark.kt index 0204d754585a..9d6b25174c13 100644 --- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/splitscreen/benchmark/SwitchBetweenSplitPairsBenchmark.kt +++ b/libs/WindowManager/Shell/tests/flicker/splitscreen/src/com/android/wm/shell/flicker/splitscreen/benchmark/SwitchBetweenSplitPairsBenchmark.kt @@ -39,10 +39,22 @@ abstract class SwitchBetweenSplitPairsBenchmark(override val flicker: LegacyFlic protected val thisTransition: FlickerBuilder.() -> Unit get() = { setup { - SplitScreenUtils.enterSplit(wmHelper, tapl, device, primaryApp, - secondaryApp, flicker.scenario.startRotation) - SplitScreenUtils.enterSplit(wmHelper, tapl, device, thirdApp, fourthApp, - flicker.scenario.startRotation) + SplitScreenUtils.enterSplit( + wmHelper, + tapl, + device, + primaryApp, + secondaryApp, + flicker.scenario.startRotation + ) + SplitScreenUtils.enterSplit( + wmHelper, + tapl, + device, + thirdApp, + fourthApp, + flicker.scenario.startRotation + ) SplitScreenUtils.waitForSplitComplete(wmHelper, thirdApp, fourthApp) } transitions { diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/splitscreen/benchmark/UnlockKeyguardToSplitScreenBenchmark.kt b/libs/WindowManager/Shell/tests/flicker/splitscreen/src/com/android/wm/shell/flicker/splitscreen/benchmark/UnlockKeyguardToSplitScreenBenchmark.kt index e71834de7123..e71834de7123 100644 --- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/splitscreen/benchmark/UnlockKeyguardToSplitScreenBenchmark.kt +++ b/libs/WindowManager/Shell/tests/flicker/splitscreen/src/com/android/wm/shell/flicker/splitscreen/benchmark/UnlockKeyguardToSplitScreenBenchmark.kt diff --git a/libs/WindowManager/Shell/tests/flicker/splitscreen/trace_config/trace_config.textproto b/libs/WindowManager/Shell/tests/flicker/splitscreen/trace_config/trace_config.textproto new file mode 100644 index 000000000000..406ada97a07d --- /dev/null +++ b/libs/WindowManager/Shell/tests/flicker/splitscreen/trace_config/trace_config.textproto @@ -0,0 +1,75 @@ +# 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. + +# proto-message: TraceConfig + +# Enable periodic flushing of the trace buffer into the output file. +write_into_file: true + +# Writes the userspace buffer into the file every 1s. +file_write_period_ms: 2500 + +# See b/126487238 - we need to guarantee ordering of events. +flush_period_ms: 30000 + +# The trace buffers needs to be big enough to hold |file_write_period_ms| of +# trace data. The trace buffer sizing depends on the number of trace categories +# enabled and the device activity. + +# RSS events +buffers: { + size_kb: 63488 + fill_policy: RING_BUFFER +} + +data_sources { + config { + name: "linux.process_stats" + target_buffer: 0 + # polled per-process memory counters and process/thread names. + # If you don't want the polled counters, remove the "process_stats_config" + # section, but keep the data source itself as it still provides on-demand + # thread/process naming for ftrace data below. + process_stats_config { + scan_all_processes_on_start: true + } + } +} + +data_sources: { + config { + name: "linux.ftrace" + ftrace_config { + ftrace_events: "ftrace/print" + ftrace_events: "task/task_newtask" + ftrace_events: "task/task_rename" + atrace_categories: "ss" + atrace_categories: "wm" + atrace_categories: "am" + atrace_categories: "aidl" + atrace_categories: "input" + atrace_categories: "binder_driver" + atrace_categories: "sched_process_exit" + atrace_apps: "com.android.server.wm.flicker.testapp" + atrace_apps: "com.android.systemui" + atrace_apps: "com.android.wm.shell.flicker" + atrace_apps: "com.android.wm.shell.flicker.other" + atrace_apps: "com.android.wm.shell.flicker.bubbles" + atrace_apps: "com.android.wm.shell.flicker.pip" + atrace_apps: "com.android.wm.shell.flicker.splitscreen" + atrace_apps: "com.google.android.apps.nexuslauncher" + } + } +} + diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/BaseTest.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/BaseTest.kt index 735fbfb341f5..568650d71872 100644 --- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/BaseTest.kt +++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/BaseTest.kt @@ -1,5 +1,5 @@ /* - * Copyright (C) 2022 The Android Open Source Project + * Copyright (C) 2023 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/utils/SplitScreenUtils.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/utils/SplitScreenUtils.kt index 6b3cfaf33c05..c31b9e2c22c7 100644 --- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/utils/SplitScreenUtils.kt +++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/utils/SplitScreenUtils.kt @@ -24,6 +24,7 @@ import android.tools.common.traces.component.ComponentNameMatcher import android.tools.common.traces.component.IComponentMatcher import android.tools.common.traces.component.IComponentNameMatcher import android.tools.device.apphelpers.StandardAppHelper +import android.tools.device.flicker.rules.ChangeDisplayOrientationRule import android.tools.device.traces.parsers.WindowManagerStateHelper import android.tools.device.traces.parsers.toFlickerComponent import android.view.InputDevice @@ -42,7 +43,6 @@ import com.android.server.wm.flicker.helpers.SimpleAppHelper import com.android.server.wm.flicker.testapp.ActivityOptions import com.android.server.wm.flicker.testapp.ActivityOptions.SplitScreen.Primary import org.junit.Assert.assertNotNull -import android.tools.device.flicker.rules.ChangeDisplayOrientationRule object SplitScreenUtils { private const val TIMEOUT_MS = 3_000L @@ -153,15 +153,10 @@ object SplitScreenUtils { } else { val rotationCheckEnabled = tapl.getExpectedRotationCheckEnabled() tapl.setExpectedRotationCheckEnabled(false) // disable rotation check to enter overview - val home = tapl.workspace - .switchToOverview() + val home = tapl.workspace.switchToOverview() tapl.setExpectedRotationCheckEnabled(rotationCheckEnabled) // restore rotation checks ChangeDisplayOrientationRule.setRotation(rotation) - home.currentTask - .tapMenu() - .tapSplitMenuItem() - .currentTask - .open() + home.currentTask.tapMenu().tapSplitMenuItem().currentTask.open() } SystemClock.sleep(TIMEOUT_MS) } diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/activityembedding/ActivityEmbeddingAnimationRunnerTests.java b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/activityembedding/ActivityEmbeddingAnimationRunnerTests.java index 02c9d306f4bf..2ac72affbb0c 100644 --- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/activityembedding/ActivityEmbeddingAnimationRunnerTests.java +++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/activityembedding/ActivityEmbeddingAnimationRunnerTests.java @@ -98,4 +98,21 @@ public class ActivityEmbeddingAnimationRunnerTests extends ActivityEmbeddingAnim // The animation should be empty when it is behind starting window. assertEquals(0, animator.getDuration()); } + + @Test + public void testInvalidCustomAnimation() { + final TransitionInfo info = new TransitionInfoBuilder(TRANSIT_OPEN, 0) + .addChange(createChange(FLAG_IN_TASK_WITH_EMBEDDED_ACTIVITY)) + .build(); + info.setAnimationOptions(TransitionInfo.AnimationOptions + .makeCustomAnimOptions("packageName", 0 /* enterResId */, 0 /* exitResId */, + 0 /* backgroundColor */, false /* overrideTaskTransition */)); + final Animator animator = mAnimRunner.createAnimator( + info, mStartTransaction, mFinishTransaction, + () -> mFinishCallback.onTransitionFinished(null /* wct */), + new ArrayList<>()); + + // An invalid custom animation is equivalent to jump-cut. + assertEquals(0, animator.getDuration()); + } } diff --git a/libs/hwui/Android.bp b/libs/hwui/Android.bp index ff1eedb8eacb..da728f90e8e0 100644 --- a/libs/hwui/Android.bp +++ b/libs/hwui/Android.bp @@ -144,6 +144,7 @@ cc_defaults { "libsync", "libui", "aconfig_text_flags_c_lib", + "server_configurable_flags", ], static_libs: [ "libEGL_blobCache", diff --git a/libs/hwui/DamageAccumulator.cpp b/libs/hwui/DamageAccumulator.cpp index a8d170d00ef7..fd276419f5e5 100644 --- a/libs/hwui/DamageAccumulator.cpp +++ b/libs/hwui/DamageAccumulator.cpp @@ -242,6 +242,47 @@ void DamageAccumulator::applyRenderNodeTransform(DirtyStack* frame) { } } +SkRect DamageAccumulator::computeClipAndTransform(const SkRect& bounds, Matrix4* outMatrix) const { + const DirtyStack* frame = mHead; + Matrix4 transform; + SkRect pretransformResult = bounds; + while (true) { + SkRect currentBounds = pretransformResult; + pretransformResult.setEmpty(); + switch (frame->type) { + case TransformRenderNode: { + const RenderProperties& props = frame->renderNode->properties(); + // Perform clipping + if (props.getClipDamageToBounds() && !currentBounds.isEmpty()) { + if (!currentBounds.intersect( + SkRect::MakeIWH(props.getWidth(), props.getHeight()))) { + currentBounds.setEmpty(); + } + } + + // apply all transforms + mapRect(props, currentBounds, &pretransformResult); + frame->renderNode->applyViewPropertyTransforms(transform); + } break; + case TransformMatrix4: + mapRect(frame->matrix4, currentBounds, &pretransformResult); + transform.multiply(*frame->matrix4); + break; + default: + pretransformResult = currentBounds; + break; + } + if (frame->prev == frame) break; + frame = frame->prev; + } + SkRect result; + Matrix4 globalToLocal; + globalToLocal.loadInverse(transform); + mapRect(&globalToLocal, pretransformResult, &result); + *outMatrix = transform; + return result; +} + void DamageAccumulator::dirty(float left, float top, float right, float bottom) { mHead->pendingDirty.join({left, top, right, bottom}); } diff --git a/libs/hwui/DamageAccumulator.h b/libs/hwui/DamageAccumulator.h index c4249af392d3..30bf7063a627 100644 --- a/libs/hwui/DamageAccumulator.h +++ b/libs/hwui/DamageAccumulator.h @@ -61,6 +61,8 @@ public: void computeCurrentTransform(Matrix4* outMatrix) const; + SkRect computeClipAndTransform(const SkRect& bounds, Matrix4* outMatrix) const; + void finish(SkRect* totalDirty); struct StretchResult { diff --git a/libs/hwui/Properties.cpp b/libs/hwui/Properties.cpp index 5e5eb4a51b35..ad600d0bab93 100644 --- a/libs/hwui/Properties.cpp +++ b/libs/hwui/Properties.cpp @@ -20,15 +20,26 @@ #ifdef __ANDROID__ #include "HWUIProperties.sysprop.h" #endif -#include "src/core/SkTraceEventCommon.h" +#include <android-base/properties.h> +#include <cutils/compiler.h> +#include <log/log.h> #include <algorithm> #include <cstdlib> #include <optional> -#include <android-base/properties.h> -#include <cutils/compiler.h> -#include <log/log.h> +#include "src/core/SkTraceEventCommon.h" + +#ifdef __ANDROID__ +#include <com_android_graphics_hwui_flags.h> +namespace hwui_flags = com::android::graphics::hwui::flags; +#else +namespace hwui_flags { +constexpr bool clip_surfaceviews() { + return false; +} +} // namespace hwui_flags +#endif namespace android { namespace uirenderer { @@ -92,6 +103,8 @@ bool Properties::isSystemOrPersistent = false; float Properties::maxHdrHeadroomOn8bit = 5.f; // TODO: Refine this number +bool Properties::clipSurfaceViews = false; + StretchEffectBehavior Properties::stretchEffectBehavior = StretchEffectBehavior::ShaderHWUI; DrawingEnabled Properties::drawingEnabled = DrawingEnabled::NotInitialized; @@ -159,6 +172,9 @@ bool Properties::load() { // call isDrawingEnabled to force loading of the property isDrawingEnabled(); + clipSurfaceViews = + base::GetBoolProperty("debug.hwui.clip_surfaceviews", hwui_flags::clip_surfaceviews()); + return (prevDebugLayersUpdates != debugLayersUpdates) || (prevDebugOverdraw != debugOverdraw); } diff --git a/libs/hwui/Properties.h b/libs/hwui/Properties.h index bb477449fff0..bca57e9e4678 100644 --- a/libs/hwui/Properties.h +++ b/libs/hwui/Properties.h @@ -325,6 +325,8 @@ public: static float maxHdrHeadroomOn8bit; + static bool clipSurfaceViews; + static StretchEffectBehavior getStretchEffectBehavior() { return stretchEffectBehavior; } diff --git a/libs/hwui/hwui/Paint.h b/libs/hwui/hwui/Paint.h index caffdfc907f7..ef4dce57bf46 100644 --- a/libs/hwui/hwui/Paint.h +++ b/libs/hwui/hwui/Paint.h @@ -17,19 +17,19 @@ #ifndef ANDROID_GRAPHICS_PAINT_H_ #define ANDROID_GRAPHICS_PAINT_H_ -#include "Typeface.h" - -#include <cutils/compiler.h> - #include <SkFont.h> #include <SkPaint.h> #include <SkSamplingOptions.h> -#include <string> - -#include <minikin/FontFamily.h> +#include <cutils/compiler.h> #include <minikin/FamilyVariant.h> +#include <minikin/FontFamily.h> +#include <minikin/FontFeature.h> #include <minikin/Hyphenator.h> +#include <string> + +#include "Typeface.h" + namespace android { class BlurDrawLooper; @@ -82,11 +82,15 @@ public: float getWordSpacing() const { return mWordSpacing; } - void setFontFeatureSettings(const std::string& fontFeatureSettings) { - mFontFeatureSettings = fontFeatureSettings; + void setFontFeatureSettings(std::string_view fontFeatures) { + mFontFeatureSettings = minikin::FontFeature::parse(fontFeatures); } - std::string getFontFeatureSettings() const { return mFontFeatureSettings; } + void resetFontFeatures() { mFontFeatureSettings.clear(); } + + const std::vector<minikin::FontFeature>& getFontFeatureSettings() const { + return mFontFeatureSettings; + } void setMinikinLocaleListId(uint32_t minikinLocaleListId) { mMinikinLocaleListId = minikinLocaleListId; @@ -170,7 +174,7 @@ private: float mLetterSpacing = 0; float mWordSpacing = 0; - std::string mFontFeatureSettings; + std::vector<minikin::FontFeature> mFontFeatureSettings; uint32_t mMinikinLocaleListId; std::optional<minikin::FamilyVariant> mFamilyVariant; uint32_t mHyphenEdit = 0; diff --git a/libs/hwui/jni/Paint.cpp b/libs/hwui/jni/Paint.cpp index 8c71d6fc7860..d84b73d1a1ca 100644 --- a/libs/hwui/jni/Paint.cpp +++ b/libs/hwui/jni/Paint.cpp @@ -33,6 +33,7 @@ #include <cassert> #include <cstring> #include <memory> +#include <string_view> #include <vector> #include "ColorFilter.h" @@ -690,10 +691,11 @@ namespace PaintGlue { jstring settings) { Paint* paint = reinterpret_cast<Paint*>(paintHandle); if (!settings) { - paint->setFontFeatureSettings(std::string()); + paint->resetFontFeatures(); } else { ScopedUtfChars settingsChars(env, settings); - paint->setFontFeatureSettings(std::string(settingsChars.c_str(), settingsChars.size())); + paint->setFontFeatureSettings( + std::string_view(settingsChars.c_str(), settingsChars.size())); } } diff --git a/libs/hwui/jni/android_graphics_RenderNode.cpp b/libs/hwui/jni/android_graphics_RenderNode.cpp index 2a218a25913d..a1b05c186ec0 100644 --- a/libs/hwui/jni/android_graphics_RenderNode.cpp +++ b/libs/hwui/jni/android_graphics_RenderNode.cpp @@ -568,6 +568,7 @@ static void android_view_RenderNode_forceEndAnimators(JNIEnv* env, jobject clazz struct { jclass clazz; jmethodID callPositionChanged; + jmethodID callPositionChanged2; jmethodID callApplyStretch; jmethodID callPositionLost; } gPositionListener; @@ -589,14 +590,25 @@ static void android_view_RenderNode_requestPositionUpdates(JNIEnv* env, jobject, virtual void onPositionUpdated(RenderNode& node, const TreeInfo& info) override { if (CC_UNLIKELY(!mListener || !info.updateWindowPositions)) return; - Matrix4 transform; - info.damageAccumulator->computeCurrentTransform(&transform); const RenderProperties& props = node.properties(); + const bool enableClip = Properties::clipSurfaceViews; - uirenderer::Rect bounds(props.getWidth(), props.getHeight()); + Matrix4 transform; + SkIRect clipBounds; + if (enableClip) { + uirenderer::Rect initialClipBounds; + props.getClippingRectForFlags(props.getClippingFlags(), &initialClipBounds); + clipBounds = + info.damageAccumulator + ->computeClipAndTransform(initialClipBounds.toSkRect(), &transform) + .roundOut(); + } else { + info.damageAccumulator->computeCurrentTransform(&transform); + } bool useStretchShader = Properties::getStretchEffectBehavior() != StretchEffectBehavior::UniformScale; // Compute the transform bounds first before calculating the stretch + uirenderer::Rect bounds(props.getWidth(), props.getHeight()); transform.mapRect(bounds); bool hasStretch = useStretchShader && info.stretchEffectCount; @@ -614,10 +626,11 @@ static void android_view_RenderNode_requestPositionUpdates(JNIEnv* env, jobject, bounds.roundOut(); } - if (mPreviousPosition == bounds) { + if (mPreviousPosition == bounds && mPreviousClip == clipBounds) { return; } mPreviousPosition = bounds; + mPreviousClip = clipBounds; ATRACE_NAME("Update SurfaceView position"); @@ -629,11 +642,23 @@ static void android_view_RenderNode_requestPositionUpdates(JNIEnv* env, jobject, // In particular if the app removes a view from the view tree before // this callback is dispatched, then we lose the position // information for this frame. - jboolean keepListening = env->CallStaticBooleanMethod( - gPositionListener.clazz, gPositionListener.callPositionChanged, mListener, - static_cast<jlong>(info.canvasContext.getFrameNumber()), - static_cast<jint>(bounds.left), static_cast<jint>(bounds.top), - static_cast<jint>(bounds.right), static_cast<jint>(bounds.bottom)); + jboolean keepListening; + if (!enableClip) { + keepListening = env->CallStaticBooleanMethod( + gPositionListener.clazz, gPositionListener.callPositionChanged, mListener, + static_cast<jlong>(info.canvasContext.getFrameNumber()), + static_cast<jint>(bounds.left), static_cast<jint>(bounds.top), + static_cast<jint>(bounds.right), static_cast<jint>(bounds.bottom)); + } else { + keepListening = env->CallStaticBooleanMethod( + gPositionListener.clazz, gPositionListener.callPositionChanged2, mListener, + static_cast<jlong>(info.canvasContext.getFrameNumber()), + static_cast<jint>(bounds.left), static_cast<jint>(bounds.top), + static_cast<jint>(bounds.right), static_cast<jint>(bounds.bottom), + static_cast<jint>(clipBounds.fLeft), static_cast<jint>(clipBounds.fTop), + static_cast<jint>(clipBounds.fRight), + static_cast<jint>(clipBounds.fBottom)); + } if (!keepListening) { env->DeleteGlobalRef(mListener); mListener = nullptr; @@ -738,6 +763,7 @@ static void android_view_RenderNode_requestPositionUpdates(JNIEnv* env, jobject, JavaVM* mVm; jobject mListener; uirenderer::Rect mPreviousPosition; + uirenderer::Rect mPreviousClip; }; RenderNode* renderNode = reinterpret_cast<RenderNode*>(renderNodePtr); @@ -866,6 +892,8 @@ int register_android_view_RenderNode(JNIEnv* env) { gPositionListener.clazz = MakeGlobalRefOrDie(env, clazz); gPositionListener.callPositionChanged = GetStaticMethodIDOrDie( env, clazz, "callPositionChanged", "(Ljava/lang/ref/WeakReference;JIIII)Z"); + gPositionListener.callPositionChanged2 = GetStaticMethodIDOrDie( + env, clazz, "callPositionChanged2", "(Ljava/lang/ref/WeakReference;JIIIIIIII)Z"); gPositionListener.callApplyStretch = GetStaticMethodIDOrDie( env, clazz, "callApplyStretch", "(Ljava/lang/ref/WeakReference;JFFFFFFFFFF)Z"); gPositionListener.callPositionLost = GetStaticMethodIDOrDie( diff --git a/libs/hwui/tests/common/TestUtils.cpp b/libs/hwui/tests/common/TestUtils.cpp index a4890ede8faa..ad963dd913cf 100644 --- a/libs/hwui/tests/common/TestUtils.cpp +++ b/libs/hwui/tests/common/TestUtils.cpp @@ -19,6 +19,8 @@ #include "DeferredLayerUpdater.h" #include "hwui/Paint.h" +#include <hwui/MinikinSkia.h> +#include <hwui/Typeface.h> #include <minikin/Layout.h> #include <pipeline/skia/SkiaOpenGLPipeline.h> #include <pipeline/skia/SkiaVulkanPipeline.h> @@ -179,5 +181,13 @@ SkRect TestUtils::getLocalClipBounds(const SkCanvas* canvas) { return outlineInLocalCoord; } +SkFont TestUtils::defaultFont() { + const std::shared_ptr<minikin::MinikinFont>& minikinFont = + Typeface::resolveDefault(nullptr)->fFontCollection->getFamilyAt(0)->getFont(0)->baseTypeface(); + SkTypeface* skTypeface = reinterpret_cast<const MinikinFontSkia*>(minikinFont.get())->GetSkTypeface(); + LOG_ALWAYS_FATAL_IF(skTypeface == nullptr); + return SkFont(sk_ref_sp(skTypeface)); +} + } /* namespace uirenderer */ } /* namespace android */ diff --git a/libs/hwui/tests/common/TestUtils.h b/libs/hwui/tests/common/TestUtils.h index ffc664c2e1bc..0ede902b1b95 100644 --- a/libs/hwui/tests/common/TestUtils.h +++ b/libs/hwui/tests/common/TestUtils.h @@ -30,6 +30,7 @@ #include <SkBitmap.h> #include <SkColor.h> +#include <SkFont.h> #include <SkImageInfo.h> #include <SkRefCnt.h> @@ -353,6 +354,8 @@ public: static CallCounts& countsForFunctor(int functor) { return sMockFunctorCounts[functor]; } + static SkFont defaultFont(); + private: static std::unordered_map<int, CallCounts> sMockFunctorCounts; diff --git a/libs/hwui/tests/common/scenes/ListViewAnimation.cpp b/libs/hwui/tests/common/scenes/ListViewAnimation.cpp index 4a5d9468cd88..97d4c8214cde 100644 --- a/libs/hwui/tests/common/scenes/ListViewAnimation.cpp +++ b/libs/hwui/tests/common/scenes/ListViewAnimation.cpp @@ -57,7 +57,7 @@ class ListViewAnimation : public TestListViewSceneBase { 128 * 3; paint.setColor(bgDark ? Color::White : Color::Grey_700); - SkFont font; + SkFont font = TestUtils::defaultFont(); font.setSize(size / 2); char charToShow = 'A' + (rand() % 26); const SkPoint pos = {SkIntToScalar(size / 2), diff --git a/libs/hwui/tests/common/scenes/StretchyListViewAnimation.cpp b/libs/hwui/tests/common/scenes/StretchyListViewAnimation.cpp index bb95490c1d39..159541c11c64 100644 --- a/libs/hwui/tests/common/scenes/StretchyListViewAnimation.cpp +++ b/libs/hwui/tests/common/scenes/StretchyListViewAnimation.cpp @@ -102,7 +102,7 @@ private: 128 * 3; paint.setColor(bgDark ? Color::White : Color::Grey_700); - SkFont font; + SkFont font = TestUtils::defaultFont(); font.setSize(size / 2); char charToShow = 'A' + (rand() % 26); const SkPoint pos = {SkIntToScalar(size / 2), diff --git a/media/java/android/media/MediaRoute2Info.java b/media/java/android/media/MediaRoute2Info.java index 937151b1aff4..8ad35876989d 100644 --- a/media/java/android/media/MediaRoute2Info.java +++ b/media/java/android/media/MediaRoute2Info.java @@ -19,6 +19,7 @@ package android.media; import static android.media.MediaRouter2Utils.toUniqueId; import static com.android.media.flags.Flags.FLAG_ENABLE_AUDIO_POLICIES_DEVICE_AND_BLUETOOTH_CONTROLLER; +import static com.android.media.flags.Flags.FLAG_ENABLE_NEW_MEDIA_ROUTE_2_INFO_TYPES; import android.annotation.FlaggedApi; import android.annotation.IntDef; @@ -306,6 +307,7 @@ public final class MediaRoute2Info implements Parcelable { * * @see #getType */ + @FlaggedApi(FLAG_ENABLE_NEW_MEDIA_ROUTE_2_INFO_TYPES) public static final int TYPE_REMOTE_TABLET = 1004; /** @@ -316,6 +318,7 @@ public final class MediaRoute2Info implements Parcelable { * * @see #getType */ + @FlaggedApi(FLAG_ENABLE_NEW_MEDIA_ROUTE_2_INFO_TYPES) public static final int TYPE_REMOTE_TABLET_DOCKED = 1005; /** @@ -326,6 +329,7 @@ public final class MediaRoute2Info implements Parcelable { * * @see #getType */ + @FlaggedApi(FLAG_ENABLE_NEW_MEDIA_ROUTE_2_INFO_TYPES) public static final int TYPE_REMOTE_COMPUTER = 1006; /** @@ -336,6 +340,7 @@ public final class MediaRoute2Info implements Parcelable { * * @see #getType */ + @FlaggedApi(FLAG_ENABLE_NEW_MEDIA_ROUTE_2_INFO_TYPES) public static final int TYPE_REMOTE_GAME_CONSOLE = 1007; /** @@ -346,6 +351,7 @@ public final class MediaRoute2Info implements Parcelable { * * @see #getType */ + @FlaggedApi(FLAG_ENABLE_NEW_MEDIA_ROUTE_2_INFO_TYPES) public static final int TYPE_REMOTE_CAR = 1008; /** @@ -356,6 +362,7 @@ public final class MediaRoute2Info implements Parcelable { * * @see #getType */ + @FlaggedApi(FLAG_ENABLE_NEW_MEDIA_ROUTE_2_INFO_TYPES) public static final int TYPE_REMOTE_SMARTWATCH = 1009; /** @@ -366,6 +373,7 @@ public final class MediaRoute2Info implements Parcelable { * * @see #getType */ + @FlaggedApi(FLAG_ENABLE_NEW_MEDIA_ROUTE_2_INFO_TYPES) public static final int TYPE_REMOTE_SMARTPHONE = 1010; /** diff --git a/media/java/android/media/flags/media_better_together.aconfig b/media/java/android/media/flags/media_better_together.aconfig index 386534b80925..dd1df475d95b 100644 --- a/media/java/android/media/flags/media_better_together.aconfig +++ b/media/java/android/media/flags/media_better_together.aconfig @@ -15,29 +15,36 @@ flag { } flag { - namespace: "media_solutions" name: "enable_audio_policies_device_and_bluetooth_controller" + namespace: "media_solutions" description: "Use Audio Policies implementation for device and Bluetooth route controllers." bug: "280576228" } flag { - namespace: "media_solutions" name: "disable_screen_off_broadcast_receiver" + namespace: "media_solutions" description: "Disables the broadcast receiver that prevents scanning when the screen is off." bug: "304234628" } flag { - namespace: "media_solutions" name: "fallback_to_default_handling_when_media_session_has_fixed_volume_handling" + namespace: "media_solutions" description: "Fallbacks to the default handling for volume adjustment when media session has fixed volume handling and its app is in the foreground and setting a media controller." bug: "293743975" } flag { - namespace: "media_solutions" name: "enable_waiting_state_for_system_session_creation_request" + namespace: "media_solutions" description: "Introduces a waiting state for the session creation request and prevents it from early failing when the selectedRoute from the bluetooth stack doesn't match the pending request route id." bug: "307723189" } + +flag { + name: "enable_new_media_route_2_info_types" + namespace: "media_solutions" + description: "Enables the following type constants in MediaRoute2Info: CAR, COMPUTER, GAME_CONSOLE, SMARTPHONE, SMARTWATCH, TABLET, TABLET_DOCKED. Note that this doesn't gate any behavior. It only guards some API int symbols." + bug: "301713440" +} diff --git a/media/java/android/media/tv/flags/media_tv.aconfig b/media/java/android/media/tv/flags/media_tv.aconfig new file mode 100644 index 000000000000..a73d1ff72a17 --- /dev/null +++ b/media/java/android/media/tv/flags/media_tv.aconfig @@ -0,0 +1,8 @@ +package: "android.media.tv.flags" + +flag { + name: "broadcast_visibility_types" + namespace: "media_tv" + description: "Constants for standardizing broadcast visibility types." + bug: "222402395" +}
\ No newline at end of file diff --git a/media/jni/Android.bp b/media/jni/Android.bp index ed1072cf409f..6031ef70535d 100644 --- a/media/jni/Android.bp +++ b/media/jni/Android.bp @@ -81,6 +81,7 @@ cc_library_shared { "libhidlallocatorutils", "libhidlbase", "libsonivox", + "server_configurable_flags", "android.hardware.cas@1.0", "android.hardware.cas.native@1.0", "android.hardware.drm@1.3", @@ -99,6 +100,7 @@ cc_library_shared { static_libs: [ "libgrallocusage", "libmedia_midiiowrapper", + "android.media.playback.flags-aconfig-cc", ], include_dirs: [ diff --git a/media/jni/android_media_MediaMetadataRetriever.cpp b/media/jni/android_media_MediaMetadataRetriever.cpp index 14587589372b..2a10fa7957bf 100644 --- a/media/jni/android_media_MediaMetadataRetriever.cpp +++ b/media/jni/android_media_MediaMetadataRetriever.cpp @@ -35,7 +35,9 @@ #include "android_media_MediaDataSource.h" #include "android_media_Streams.h" #include "android_util_Binder.h" +#include <com_android_media_playback_flags.h> +namespace playback_flags = com::android::media::playback::flags; using namespace android; struct fields_t { @@ -374,9 +376,12 @@ static jobject android_media_MediaMetadataRetriever_getFrameAtTime( jniThrowException(env, "java/lang/IllegalStateException", "No retriever available"); return NULL; } - // For getFrameAtTime family of calls, default to ANDROID_BITMAP_FORMAT_RGB_565 - // to keep the behavior consistent with older releases - AndroidBitmapFormat colorFormat = getColorFormat(env, params, ANDROID_BITMAP_FORMAT_RGB_565); + + AndroidBitmapFormat defaultColorFormat = + playback_flags::mediametadataretriever_default_rgba8888() + ? ANDROID_BITMAP_FORMAT_RGBA_8888 + : ANDROID_BITMAP_FORMAT_RGB_565; + AndroidBitmapFormat colorFormat = getColorFormat(env, params, defaultColorFormat); // Call native method to retrieve a video frame VideoFrame *videoFrame = NULL; diff --git a/media/jni/playback_flags.aconfig b/media/jni/playback_flags.aconfig new file mode 100644 index 000000000000..2bb0ec5375fd --- /dev/null +++ b/media/jni/playback_flags.aconfig @@ -0,0 +1,8 @@ +package: "com.android.media.playback.flags" + +flag { + name: "mediametadataretriever_default_rgba8888" + namespace: "media_solutions" + description: "Change MediaMetadataRetriever to use RGBA8888 for bitmap handling by default." + bug: "298965955" +} diff --git a/media/tests/MediaFrameworkTest/Android.bp b/media/tests/MediaFrameworkTest/Android.bp index bdd7afeb2f65..7a329bccf940 100644 --- a/media/tests/MediaFrameworkTest/Android.bp +++ b/media/tests/MediaFrameworkTest/Android.bp @@ -20,6 +20,8 @@ android_test { "androidx.test.ext.junit", "androidx.test.rules", "android-ex-camera2", + "android.media.playback.flags-aconfig-java", + "flag-junit", "testables", "testng", "truth", diff --git a/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/unit/MediaMetadataRetrieverTest.java b/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/unit/MediaMetadataRetrieverTest.java index f70d2d1f8ae7..e3d389737bb0 100644 --- a/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/unit/MediaMetadataRetrieverTest.java +++ b/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/unit/MediaMetadataRetrieverTest.java @@ -16,19 +16,27 @@ package com.android.mediaframeworktest.unit; +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertNotNull; import static org.junit.Assert.assertTrue; import android.graphics.Bitmap; import android.media.MediaMetadataRetriever; +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.test.suitebuilder.annotation.LargeTest; import android.test.suitebuilder.annotation.MediumTest; import android.util.Log; import androidx.test.runner.AndroidJUnit4; +import com.android.media.playback.flags.Flags; import com.android.mediaframeworktest.MediaNames; import com.android.mediaframeworktest.MediaProfileReader; +import org.junit.Rule; import org.junit.Test; import org.junit.runner.RunWith; @@ -40,6 +48,9 @@ public class MediaMetadataRetrieverTest { private static final String TAG = "MediaMetadataRetrieverTest"; + @Rule + public final CheckFlagsRule mCheckFlagsRule = DeviceFlagsValueProvider.createCheckFlagsRule(); + // Test album art extraction. @MediumTest @Test @@ -284,6 +295,34 @@ public class MediaMetadataRetrieverTest { assertTrue(!hasFailed); } + /** Test the thumbnail is generated when the default is set to RGBA8888 */ + @MediumTest + // TODO(b/305160754) Remove the following annotation and use SetFlagsRule.enableFlags + @RequiresFlagsEnabled(Flags.FLAG_MEDIAMETADATARETRIEVER_DEFAULT_RGBA8888) + @Test + public void testGetFrameAtTimeWithRGBA8888Flag_Set() throws IOException { + try (MediaMetadataRetriever retriever = new MediaMetadataRetriever()) { + retriever.setDataSource(MediaNames.TEST_PATH_1); + Bitmap bitmap = retriever.getFrameAtTime(-1); + assertNotNull(bitmap); + assertEquals(Bitmap.Config.ARGB_8888, bitmap.getConfig()); + } + } + + /** Test the thumbnail is generated when the default is not set to RGBA8888 */ + @MediumTest + // TODO(b/305160754) Remove the following annotation and use SetFlagsRule.disableFlags + @RequiresFlagsDisabled(Flags.FLAG_MEDIAMETADATARETRIEVER_DEFAULT_RGBA8888) + @Test + public void testGetFrameAtTimeWithRGBA8888Flag_Unset() throws IOException { + try (MediaMetadataRetriever retriever = new MediaMetadataRetriever()) { + retriever.setDataSource(MediaNames.TEST_PATH_1); + Bitmap bitmap = retriever.getFrameAtTime(-1); + assertNotNull(bitmap); + assertEquals(Bitmap.Config.RGB_565, bitmap.getConfig()); + } + } + // TODO: // Encode and test for the correct mix of metadata elements on a per-file basis? // We should be able to compare the actual returned metadata with the expected metadata diff --git a/packages/PackageInstaller/src/com/android/packageinstaller/InstallInstalling.java b/packages/PackageInstaller/src/com/android/packageinstaller/InstallInstalling.java index 1088acef0fb0..4992ef1e1c00 100644 --- a/packages/PackageInstaller/src/com/android/packageinstaller/InstallInstalling.java +++ b/packages/PackageInstaller/src/com/android/packageinstaller/InstallInstalling.java @@ -290,7 +290,14 @@ public class InstallInstalling extends AlertActivity { broadcastIntent, PendingIntent.FLAG_UPDATE_CURRENT | PendingIntent.FLAG_MUTABLE); - session.commit(pendingIntent.getIntentSender()); + try { + session.commit(pendingIntent.getIntentSender()); + } catch (Exception e) { + Log.e(LOG_TAG, "Cannot install package: ", e); + launchFailure(PackageInstaller.STATUS_FAILURE, + PackageManager.INSTALL_FAILED_INTERNAL_ERROR, null); + return; + } mCancelButton.setEnabled(false); setFinishOnTouchOutside(false); } else { diff --git a/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/widget/scaffold/SettingsPager.kt b/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/widget/scaffold/SettingsPager.kt index 9f7f040be7ce..aa148b022b92 100644 --- a/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/widget/scaffold/SettingsPager.kt +++ b/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/widget/scaffold/SettingsPager.kt @@ -21,7 +21,7 @@ import androidx.compose.foundation.layout.Column import androidx.compose.foundation.layout.padding import androidx.compose.foundation.pager.HorizontalPager import androidx.compose.foundation.pager.rememberPagerState -import androidx.compose.material3.PrimaryTabRow +import androidx.compose.material3.TabRow import androidx.compose.runtime.Composable import androidx.compose.runtime.rememberCoroutineScope import androidx.compose.ui.Modifier @@ -43,7 +43,7 @@ fun SettingsPager(titles: List<String>, content: @Composable (page: Int) -> Unit val coroutineScope = rememberCoroutineScope() val pagerState = rememberPagerState { titles.size } - PrimaryTabRow( + TabRow( selectedTabIndex = pagerState.currentPage, modifier = Modifier.padding(horizontal = SettingsDimension.itemPaddingEnd), containerColor = Color.Transparent, diff --git a/packages/SettingsLib/res/values/strings.xml b/packages/SettingsLib/res/values/strings.xml index 22131df60b0d..96029c813528 100644 --- a/packages/SettingsLib/res/values/strings.xml +++ b/packages/SettingsLib/res/values/strings.xml @@ -1027,6 +1027,13 @@ <!-- Settings item title to select whether to disable cache for transcoding. [CHAR LIMIT=85] --> <string name="transcode_disable_cache">Disable transcoding cache</string> + <!-- Developer settings title: widevine settings screen. [CHAR LIMIT=50] --> + <string name="widevine_settings_title">Widevine settings</string> + <!-- Developer settings title: select whether to enable Force L3 fallback. [CHAR LIMIT=50] --> + <string name="force_l3_fallback_title">Force L3 fallback</string> + <!-- Developer settings summary: select whether to enable Force L3 fallback.[CHAR LIMIT=NONE] --> + <string name="force_l3_fallback_summary">Select to force L3 fallback</string> + <!-- Services settings screen, setting option name for the user to go to the screen to view running services --> <string name="runningservices_settings_title">Running services</string> <!-- Services settings screen, setting option summary for the user to go to the screen to view running services --> diff --git a/packages/SettingsLib/src/com/android/settingslib/inputmethod/InputMethodAndSubtypeEnablerManager.java b/packages/SettingsLib/src/com/android/settingslib/inputmethod/InputMethodAndSubtypeEnablerManager.java deleted file mode 100644 index 117b48ff852d..000000000000 --- a/packages/SettingsLib/src/com/android/settingslib/inputmethod/InputMethodAndSubtypeEnablerManager.java +++ /dev/null @@ -1,264 +0,0 @@ -/* - * Copyright (C) 2017 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License - */ - -package com.android.settingslib.inputmethod; - -import android.content.Context; -import android.content.pm.PackageManager; -import android.content.res.Configuration; -import android.text.TextUtils; -import android.view.inputmethod.InputMethodInfo; -import android.view.inputmethod.InputMethodManager; -import android.view.inputmethod.InputMethodSubtype; - -import androidx.preference.Preference; -import androidx.preference.PreferenceCategory; -import androidx.preference.PreferenceFragment; -import androidx.preference.PreferenceScreen; -import androidx.preference.TwoStatePreference; - -import com.android.settingslib.R; - -import java.text.Collator; -import java.util.ArrayList; -import java.util.HashMap; -import java.util.List; - -public class InputMethodAndSubtypeEnablerManager implements Preference.OnPreferenceChangeListener { - - private final PreferenceFragment mFragment; - - private boolean mHaveHardKeyboard; - private final HashMap<String, List<Preference>> mInputMethodAndSubtypePrefsMap = - new HashMap<>(); - private final HashMap<String, TwoStatePreference> mAutoSelectionPrefsMap = new HashMap<>(); - private InputMethodManager mImm; - // TODO: Change mInputMethodInfoList to Map - private List<InputMethodInfo> mInputMethodInfoList; - private final Collator mCollator = Collator.getInstance(); - - public InputMethodAndSubtypeEnablerManager(PreferenceFragment fragment) { - mFragment = fragment; - mImm = fragment.getContext().getSystemService(InputMethodManager.class); - - mInputMethodInfoList = mImm.getInputMethodList(); - } - - public void init(PreferenceFragment fragment, String targetImi, PreferenceScreen root) { - final Configuration config = fragment.getResources().getConfiguration(); - mHaveHardKeyboard = (config.keyboard == Configuration.KEYBOARD_QWERTY); - - for (final InputMethodInfo imi : mInputMethodInfoList) { - // Add subtype preferences of this IME when it is specified or no IME is specified. - if (imi.getId().equals(targetImi) || TextUtils.isEmpty(targetImi)) { - addInputMethodSubtypePreferences(fragment, imi, root); - } - } - } - - public void refresh(Context context, PreferenceFragment fragment) { - // Refresh internal states in mInputMethodSettingValues to keep the latest - // "InputMethodInfo"s and "InputMethodSubtype"s - InputMethodSettingValuesWrapper - .getInstance(context).refreshAllInputMethodAndSubtypes(); - InputMethodAndSubtypeUtil.loadInputMethodSubtypeList(fragment, context.getContentResolver(), - mInputMethodInfoList, mInputMethodAndSubtypePrefsMap); - updateAutoSelectionPreferences(); - } - - public void save(Context context, PreferenceFragment fragment) { - InputMethodAndSubtypeUtil.saveInputMethodSubtypeList(fragment, context.getContentResolver(), - mInputMethodInfoList, mHaveHardKeyboard); - } - - @Override - public boolean onPreferenceChange(final Preference pref, final Object newValue) { - if (!(newValue instanceof Boolean)) { - return true; // Invoke default behavior. - } - final boolean isChecking = (Boolean) newValue; - for (final String imiId : mAutoSelectionPrefsMap.keySet()) { - // An auto select subtype preference is changing. - if (mAutoSelectionPrefsMap.get(imiId) == pref) { - final TwoStatePreference autoSelectionPref = (TwoStatePreference) pref; - autoSelectionPref.setChecked(isChecking); - // Enable or disable subtypes depending on the auto selection preference. - setAutoSelectionSubtypesEnabled(imiId, autoSelectionPref.isChecked()); - return false; - } - } - // A subtype preference is changing. - if (pref instanceof InputMethodSubtypePreference) { - final InputMethodSubtypePreference subtypePref = (InputMethodSubtypePreference) pref; - subtypePref.setChecked(isChecking); - if (!subtypePref.isChecked()) { - // It takes care of the case where no subtypes are explicitly enabled then the auto - // selection preference is going to be checked. - updateAutoSelectionPreferences(); - } - return false; - } - return true; // Invoke default behavior. - } - - private void addInputMethodSubtypePreferences(PreferenceFragment fragment, InputMethodInfo imi, - final PreferenceScreen root) { - Context prefContext = fragment.getPreferenceManager().getContext(); - - final int subtypeCount = imi.getSubtypeCount(); - if (subtypeCount <= 1) { - return; - } - final String imiId = imi.getId(); - final PreferenceCategory keyboardSettingsCategory = - new PreferenceCategory(prefContext); - root.addPreference(keyboardSettingsCategory); - final PackageManager pm = prefContext.getPackageManager(); - final CharSequence label = imi.loadLabel(pm); - - keyboardSettingsCategory.setTitle(label); - keyboardSettingsCategory.setKey(imiId); - // TODO: Use toggle Preference if images are ready. - final TwoStatePreference autoSelectionPref = - new SwitchWithNoTextPreference(prefContext); - mAutoSelectionPrefsMap.put(imiId, autoSelectionPref); - keyboardSettingsCategory.addPreference(autoSelectionPref); - autoSelectionPref.setOnPreferenceChangeListener(this); - - final PreferenceCategory activeInputMethodsCategory = - new PreferenceCategory(prefContext); - activeInputMethodsCategory.setTitle(R.string.active_input_method_subtypes); - root.addPreference(activeInputMethodsCategory); - - CharSequence autoSubtypeLabel = null; - final ArrayList<Preference> subtypePreferences = new ArrayList<>(); - for (int index = 0; index < subtypeCount; ++index) { - final InputMethodSubtype subtype = imi.getSubtypeAt(index); - if (subtype.overridesImplicitlyEnabledSubtype()) { - if (autoSubtypeLabel == null) { - autoSubtypeLabel = InputMethodAndSubtypeUtil.getSubtypeLocaleNameAsSentence( - subtype, prefContext, imi); - } - } else { - final Preference subtypePref = new InputMethodSubtypePreference( - prefContext, subtype, imi); - subtypePreferences.add(subtypePref); - } - } - subtypePreferences.sort((lhs, rhs) -> { - if (lhs instanceof InputMethodSubtypePreference) { - return ((InputMethodSubtypePreference) lhs).compareTo(rhs, mCollator); - } - return lhs.compareTo(rhs); - }); - for (final Preference pref : subtypePreferences) { - activeInputMethodsCategory.addPreference(pref); - pref.setOnPreferenceChangeListener(this); - InputMethodAndSubtypeUtil.removeUnnecessaryNonPersistentPreference(pref); - } - mInputMethodAndSubtypePrefsMap.put(imiId, subtypePreferences); - if (TextUtils.isEmpty(autoSubtypeLabel)) { - autoSelectionPref.setTitle( - R.string.use_system_language_to_select_input_method_subtypes); - } else { - autoSelectionPref.setTitle(autoSubtypeLabel); - } - } - - private boolean isNoSubtypesExplicitlySelected(final String imiId) { - final List<Preference> subtypePrefs = mInputMethodAndSubtypePrefsMap.get(imiId); - for (final Preference pref : subtypePrefs) { - if (pref instanceof TwoStatePreference && ((TwoStatePreference) pref).isChecked()) { - return false; - } - } - return true; - } - - private void setAutoSelectionSubtypesEnabled(final String imiId, - final boolean autoSelectionEnabled) { - final TwoStatePreference autoSelectionPref = mAutoSelectionPrefsMap.get(imiId); - if (autoSelectionPref == null) { - return; - } - autoSelectionPref.setChecked(autoSelectionEnabled); - final List<Preference> subtypePrefs = mInputMethodAndSubtypePrefsMap.get(imiId); - for (final Preference pref : subtypePrefs) { - if (pref instanceof TwoStatePreference) { - // When autoSelectionEnabled is true, all subtype prefs need to be disabled with - // implicitly checked subtypes. In case of false, all subtype prefs need to be - // enabled. - pref.setEnabled(!autoSelectionEnabled); - if (autoSelectionEnabled) { - ((TwoStatePreference) pref).setChecked(false); - } - } - } - if (autoSelectionEnabled) { - InputMethodAndSubtypeUtil.saveInputMethodSubtypeList( - mFragment, mFragment.getContext().getContentResolver(), - mInputMethodInfoList, mHaveHardKeyboard); - updateImplicitlyEnabledSubtypes(imiId); - } - } - - private void updateImplicitlyEnabledSubtypes(final String targetImiId) { - // When targetImiId is null, apply to all subtypes of all IMEs - for (final InputMethodInfo imi : mInputMethodInfoList) { - final String imiId = imi.getId(); - final TwoStatePreference autoSelectionPref = mAutoSelectionPrefsMap.get(imiId); - // No need to update implicitly enabled subtypes when the user has unchecked the - // "subtype auto selection". - if (autoSelectionPref == null || !autoSelectionPref.isChecked()) { - continue; - } - if (imiId.equals(targetImiId) || targetImiId == null) { - updateImplicitlyEnabledSubtypesOf(imi); - } - } - } - - private void updateImplicitlyEnabledSubtypesOf(final InputMethodInfo imi) { - final String imiId = imi.getId(); - final List<Preference> subtypePrefs = mInputMethodAndSubtypePrefsMap.get(imiId); - final List<InputMethodSubtype> implicitlyEnabledSubtypes = - mImm.getEnabledInputMethodSubtypeList(imi, true); - if (subtypePrefs == null || implicitlyEnabledSubtypes == null) { - return; - } - for (final Preference pref : subtypePrefs) { - if (!(pref instanceof TwoStatePreference)) { - continue; - } - final TwoStatePreference subtypePref = (TwoStatePreference) pref; - subtypePref.setChecked(false); - for (final InputMethodSubtype subtype : implicitlyEnabledSubtypes) { - final String implicitlyEnabledSubtypePrefKey = imiId + subtype.hashCode(); - if (subtypePref.getKey().equals(implicitlyEnabledSubtypePrefKey)) { - subtypePref.setChecked(true); - break; - } - } - } - } - - private void updateAutoSelectionPreferences() { - for (final String imiId : mInputMethodAndSubtypePrefsMap.keySet()) { - setAutoSelectionSubtypesEnabled(imiId, isNoSubtypesExplicitlySelected(imiId)); - } - updateImplicitlyEnabledSubtypes(null /* targetImiId */ /* check */); - } -} diff --git a/packages/SettingsProvider/src/com/android/providers/settings/DeviceConfigService.java b/packages/SettingsProvider/src/com/android/providers/settings/DeviceConfigService.java index 976ba215d349..6bc27160c0a8 100644 --- a/packages/SettingsProvider/src/com/android/providers/settings/DeviceConfigService.java +++ b/packages/SettingsProvider/src/com/android/providers/settings/DeviceConfigService.java @@ -68,7 +68,7 @@ public final class DeviceConfigService extends Binder { private static final List<String> sAconfigTextProtoFilesOnDevice = List.of( "/system/etc/aconfig_flags.pb", "/system_ext/etc/aconfig_flags.pb", - "/system_ext/etc/aconfig_flags.pb", + "/product/etc/aconfig_flags.pb", "/vendor/etc/aconfig_flags.pb"); private static final List<String> PRIVATE_NAMESPACES = List.of( diff --git a/packages/SettingsProvider/src/com/android/providers/settings/SettingsProvider.java b/packages/SettingsProvider/src/com/android/providers/settings/SettingsProvider.java index 8c8a71ccf01e..785003a355fc 100644 --- a/packages/SettingsProvider/src/com/android/providers/settings/SettingsProvider.java +++ b/packages/SettingsProvider/src/com/android/providers/settings/SettingsProvider.java @@ -3030,11 +3030,25 @@ public class SettingsProvider extends ContentProvider { } @GuardedBy("mLock") - public void ensureSettingsForUserLocked(int userId) { + @Nullable + private SettingsState getOrCreateSettingsStateLocked(int key) { + SettingsState settingsState = mSettingsStates.get(key); + if (settingsState != null) { + return settingsState; + } + + if (!ensureSettingsForUserLocked(getUserIdFromKey(key))) { + return null; + } + return mSettingsStates.get(key); + } + + @GuardedBy("mLock") + public boolean ensureSettingsForUserLocked(int userId) { // First make sure this user actually exists. if (mUserManager.getUserInfo(userId) == null) { Slog.wtf(LOG_TAG, "Requested user " + userId + " does not exist"); - return; + return false; } // Migrate the setting for this user if needed. @@ -3072,6 +3086,7 @@ public class SettingsProvider extends ContentProvider { // Upgrade the settings to the latest version. UpgradeController upgrader = new UpgradeController(userId); upgrader.upgradeIfNeededLocked(); + return true; } @GuardedBy("mLock") @@ -3149,7 +3164,7 @@ public class SettingsProvider extends ContentProvider { boolean success = false; boolean wasUnsetNonPredefinedSetting = false; - SettingsState settingsState = mSettingsStates.get(key); + SettingsState settingsState = getOrCreateSettingsStateLocked(key); if (settingsState != null) { if (!isSettingPreDefined(name, type) && !settingsState.hasSetting(name)) { wasUnsetNonPredefinedSetting = true; @@ -3184,7 +3199,7 @@ public class SettingsProvider extends ContentProvider { @GuardedBy("mLock") public boolean setConfigSettingsLocked(int key, String prefix, Map<String, String> keyValues, String packageName) { - SettingsState settingsState = mSettingsStates.get(key); + SettingsState settingsState = getOrCreateSettingsStateLocked(key); if (settingsState != null) { if (settingsState.isNewConfigBannedLocked(prefix, keyValues)) { return false; @@ -3207,7 +3222,7 @@ public class SettingsProvider extends ContentProvider { final int key = makeKey(type, userId); boolean success = false; - SettingsState settingsState = mSettingsStates.get(key); + SettingsState settingsState = getOrCreateSettingsStateLocked(key); if (settingsState != null) { success = settingsState.deleteSettingLocked(name); } @@ -3232,7 +3247,7 @@ public class SettingsProvider extends ContentProvider { final int key = makeKey(type, userId); boolean success = false; - SettingsState settingsState = mSettingsStates.get(key); + SettingsState settingsState = getOrCreateSettingsStateLocked(key); if (settingsState != null) { success = settingsState.updateSettingLocked(name, value, tag, makeDefault, packageName); @@ -3284,7 +3299,7 @@ public class SettingsProvider extends ContentProvider { public boolean resetSettingsLocked(int type, int userId, String packageName, int mode, String tag, @Nullable String prefix) { final int key = makeKey(type, userId); - SettingsState settingsState = mSettingsStates.get(key); + SettingsState settingsState = getOrCreateSettingsStateLocked(key); if (settingsState == null) { return false; } diff --git a/packages/SettingsProvider/test/src/android/provider/SettingsBackupTest.java b/packages/SettingsProvider/test/src/android/provider/SettingsBackupTest.java index 9dacadef38d5..1f171ba48343 100644 --- a/packages/SettingsProvider/test/src/android/provider/SettingsBackupTest.java +++ b/packages/SettingsProvider/test/src/android/provider/SettingsBackupTest.java @@ -691,6 +691,7 @@ public class SettingsBackupTest { newHashSet( Settings.Secure.ACCESSIBILITY_SOFT_KEYBOARD_MODE, Settings.Secure.ACCESSIBILITY_SPEAK_PASSWORD, // Deprecated since O. + Settings.Secure.ALLOW_PRIMARY_GAIA_ACCOUNT_REMOVAL_FOR_TESTS, Settings.Secure.ALLOWED_GEOLOCATION_ORIGINS, Settings.Secure.ALWAYS_ON_VPN_APP, Settings.Secure.ALWAYS_ON_VPN_LOCKDOWN, diff --git a/packages/SystemUI/Android.bp b/packages/SystemUI/Android.bp index 17cc9f8135f4..89c6ecc4630b 100644 --- a/packages/SystemUI/Android.bp +++ b/packages/SystemUI/Android.bp @@ -60,7 +60,6 @@ systemui_compose_java_defaults { // except for SystemUI-core. // Copied from compose/features/Android.bp. static_libs: [ - "CommunalLayoutLib", "PlatformComposeCore", "PlatformComposeSceneTransitionLayout", @@ -366,6 +365,7 @@ filegroup { "tests/src/com/android/systemui/qs/pipeline/shared/TileSpecTest.kt", "tests/src/com/android/systemui/qs/tiles/base/**/*.kt", "tests/src/com/android/systemui/qs/tiles/viewmodel/**/*.kt", + "tests/src/com/android/systemui/qs/tiles/impl/**/*.kt", /* Authentication */ "tests/src/com/android/systemui/authentication/data/repository/AuthenticationRepositoryTest.kt", diff --git a/packages/SystemUI/aconfig/accessibility.aconfig b/packages/SystemUI/aconfig/accessibility.aconfig index 9e06872797dc..21263a92ae26 100644 --- a/packages/SystemUI/aconfig/accessibility.aconfig +++ b/packages/SystemUI/aconfig/accessibility.aconfig @@ -6,7 +6,7 @@ flag { name: "floating_menu_animated_tuck" namespace: "accessibility" description: "Sets up animations for tucking/untucking and adjusts clipbounds." - bug: "24592044" + bug: "297556899" } flag { diff --git a/packages/SystemUI/aconfig/systemui.aconfig b/packages/SystemUI/aconfig/systemui.aconfig index c26d5f53dee9..c27491107ad5 100644 --- a/packages/SystemUI/aconfig/systemui.aconfig +++ b/packages/SystemUI/aconfig/systemui.aconfig @@ -51,3 +51,18 @@ flag { description: "Enables the scene container framework go/flexiglass." bug: "283121968" } + +flag { + name: "visual_interruptions_refactor" + namespace: "systemui" + description: "Enables the refactored version of the code to decide when notifications " + "HUN, bubble, pulse, or FSI." + bug: "261728888" +} + +flag { + name: "haptic_brightness_slider" + namespace: "systemui" + description: "Adds haptic feedback to the brightness slider." + bug: "296467915" +} diff --git a/packages/SystemUI/animation/src/com/android/systemui/animation/ActivityLaunchAnimator.kt b/packages/SystemUI/animation/src/com/android/systemui/animation/ActivityLaunchAnimator.kt index ab4db451406d..f7d9056c33dc 100644 --- a/packages/SystemUI/animation/src/com/android/systemui/animation/ActivityLaunchAnimator.kt +++ b/packages/SystemUI/animation/src/com/android/systemui/animation/ActivityLaunchAnimator.kt @@ -114,7 +114,13 @@ class ActivityLaunchAnimator( private val NAV_FADE_OUT_INTERPOLATOR = PathInterpolator(0.2f, 0f, 1f, 1f) /** The time we wait before timing out the remote animation after starting the intent. */ - private const val LAUNCH_TIMEOUT = 1000L + private const val LAUNCH_TIMEOUT = 1_000L + + /** + * The time we wait before we Log.wtf because the remote animation was neither started or + * cancelled by WM. + */ + private const val LONG_LAUNCH_TIMEOUT = 5_000L private fun createPositionXInterpolator(): Interpolator { val path = @@ -247,7 +253,7 @@ class ActivityLaunchAnimator( // If we expect an animation, post a timeout to cancel it in case the remote animation is // never started. if (willAnimate) { - runnerDelegate.postTimeout() + runnerDelegate.postTimeouts() // Hide the keyguard using the launch animation instead of the default unlock animation. if (hideKeyguardWithAnimation) { @@ -578,21 +584,41 @@ class ActivityLaunchAnimator( private var cancelled = false private var animation: LaunchAnimator.Animation? = null - // A timeout to cancel the remote animation if it is not started within X milliseconds after - // the intent was started. - // - // Note that this is important to keep this a Runnable (and not a Kotlin lambda), otherwise - // it will be automatically converted when posted and we wouldn't be able to remove it after - // posting it. + /** + * A timeout to cancel the launch animation if the remote animation is not started or + * cancelled within [LAUNCH_TIMEOUT] milliseconds after the intent was started. + * + * Note that this is important to keep this a Runnable (and not a Kotlin lambda), otherwise + * it will be automatically converted when posted and we wouldn't be able to remove it after + * posting it. + */ private var onTimeout = Runnable { onAnimationTimedOut() } + /** + * A long timeout to Log.wtf (signaling a bug in WM) when the remote animation wasn't + * started or cancelled within [LONG_LAUNCH_TIMEOUT] milliseconds after the intent was + * started. + */ + private var onLongTimeout = Runnable { + Log.wtf( + TAG, + "The remote animation was neither cancelled or started within $LONG_LAUNCH_TIMEOUT" + ) + } + @UiThread - internal fun postTimeout() { - timeoutHandler?.postDelayed(onTimeout, LAUNCH_TIMEOUT) + internal fun postTimeouts() { + if (timeoutHandler != null) { + timeoutHandler.postDelayed(onTimeout, LAUNCH_TIMEOUT) + timeoutHandler.postDelayed(onLongTimeout, LONG_LAUNCH_TIMEOUT) + } } - private fun removeTimeout() { - timeoutHandler?.removeCallbacks(onTimeout) + private fun removeTimeouts() { + if (timeoutHandler != null) { + timeoutHandler.removeCallbacks(onTimeout) + timeoutHandler.removeCallbacks(onLongTimeout) + } } @UiThread @@ -603,7 +629,7 @@ class ActivityLaunchAnimator( nonApps: Array<out RemoteAnimationTarget>?, callback: IRemoteAnimationFinishedCallback? ) { - removeTimeout() + removeTimeouts() // The animation was started too late and we already notified the controller that it // timed out. @@ -653,7 +679,6 @@ class ActivityLaunchAnimator( val window = findRootTaskIfPossible(apps) if (window == null) { Log.i(TAG, "Aborting the animation as no window is opening") - removeTimeout() iCallback?.invoke() if (DEBUG_LAUNCH_ANIMATION) { @@ -890,11 +915,13 @@ class ActivityLaunchAnimator( } private fun onAnimationTimedOut() { + // The remote animation was cancelled by WM, so we already cancelled the launch + // animation. if (cancelled) { return } - Log.wtf(TAG, "Remote animation timed out") + Log.w(TAG, "Remote animation timed out") timedOut = true if (DEBUG_LAUNCH_ANIMATION) { @@ -906,13 +933,15 @@ class ActivityLaunchAnimator( @UiThread override fun onAnimationCancelled() { + removeTimeouts() + + // The short timeout happened, so we already cancelled the launch animation. if (timedOut) { return } Log.i(TAG, "Remote animation was cancelled") cancelled = true - removeTimeout() animation?.cancel() diff --git a/packages/SystemUI/compose/features/src/com/android/systemui/communal/ui/compose/CommunalHub.kt b/packages/SystemUI/compose/features/src/com/android/systemui/communal/ui/compose/CommunalHub.kt index b8fb26406801..87a8c35388fa 100644 --- a/packages/SystemUI/compose/features/src/com/android/systemui/communal/ui/compose/CommunalHub.kt +++ b/packages/SystemUI/compose/features/src/com/android/systemui/communal/ui/compose/CommunalHub.kt @@ -4,8 +4,14 @@ import android.appwidget.AppWidgetHostView import android.os.Bundle import android.util.SizeF import androidx.compose.foundation.background +import androidx.compose.foundation.layout.Arrangement import androidx.compose.foundation.layout.Box import androidx.compose.foundation.layout.fillMaxSize +import androidx.compose.foundation.layout.height +import androidx.compose.foundation.layout.size +import androidx.compose.foundation.lazy.grid.GridCells +import androidx.compose.foundation.lazy.grid.GridItemSpan +import androidx.compose.foundation.lazy.grid.LazyHorizontalGrid import androidx.compose.material3.Card import androidx.compose.runtime.Composable import androidx.compose.runtime.collectAsState @@ -13,16 +19,12 @@ import androidx.compose.runtime.getValue import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier import androidx.compose.ui.graphics.Color -import androidx.compose.ui.res.dimensionResource -import androidx.compose.ui.res.integerResource +import androidx.compose.ui.unit.Dp +import androidx.compose.ui.unit.dp import androidx.compose.ui.viewinterop.AndroidView -import com.android.systemui.communal.layout.ui.compose.CommunalGridLayout -import com.android.systemui.communal.layout.ui.compose.config.CommunalGridLayoutCard -import com.android.systemui.communal.layout.ui.compose.config.CommunalGridLayoutConfig import com.android.systemui.communal.shared.model.CommunalContentSize import com.android.systemui.communal.ui.model.CommunalContentUiModel import com.android.systemui.communal.ui.viewmodel.CommunalViewModel -import com.android.systemui.res.R @Composable fun CommunalHub( @@ -34,68 +36,91 @@ fun CommunalHub( Box( modifier = modifier.fillMaxSize().background(Color.White), ) { - CommunalGridLayout( - modifier = Modifier.align(Alignment.CenterStart), - layoutConfig = - CommunalGridLayoutConfig( - gridColumnSize = dimensionResource(R.dimen.communal_grid_column_size), - gridGutter = dimensionResource(R.dimen.communal_grid_gutter_size), - gridHeight = dimensionResource(R.dimen.communal_grid_height), - gridColumnsPerCard = integerResource(R.integer.communal_grid_columns_per_card), - ), - communalCards = if (showTutorial) tutorialContent else widgetContent.map(::contentCard), - ) + LazyHorizontalGrid( + modifier = modifier.height(Dimensions.GridHeight).align(Alignment.CenterStart), + rows = GridCells.Fixed(CommunalContentSize.FULL.span), + horizontalArrangement = Arrangement.spacedBy(Dimensions.Spacing), + verticalArrangement = Arrangement.spacedBy(Dimensions.Spacing), + ) { + if (showTutorial) { + items( + count = tutorialContentSizes.size, + // TODO(b/308148193): a more scalable solution for unique ids. + key = { index -> "tutorial_$index" }, + span = { index -> GridItemSpan(tutorialContentSizes[index].span) }, + ) { index -> + TutorialCard( + modifier = + Modifier.size(Dimensions.CardWidth, tutorialContentSizes[index].dp()), + ) + } + } else { + items( + count = widgetContent.size, + key = { index -> widgetContent[index].id }, + span = { index -> GridItemSpan(widgetContent[index].size.span) }, + ) { index -> + val widget = widgetContent[index] + ContentCard( + modifier = Modifier.size(Dimensions.CardWidth, widget.size.dp()), + model = widget, + ) + } + } + } } } -private val tutorialContent = - listOf( - tutorialCard(CommunalGridLayoutCard.Size.FULL), - tutorialCard(CommunalGridLayoutCard.Size.THIRD), - tutorialCard(CommunalGridLayoutCard.Size.THIRD), - tutorialCard(CommunalGridLayoutCard.Size.THIRD), - tutorialCard(CommunalGridLayoutCard.Size.HALF), - tutorialCard(CommunalGridLayoutCard.Size.HALF), - tutorialCard(CommunalGridLayoutCard.Size.HALF), - tutorialCard(CommunalGridLayoutCard.Size.HALF), - ) - -private fun tutorialCard(size: CommunalGridLayoutCard.Size): CommunalGridLayoutCard { - return object : CommunalGridLayoutCard() { - override val supportedSizes = listOf(size) - - @Composable - override fun Content(modifier: Modifier, size: SizeF) { - Card(modifier = modifier, content = {}) - } - } +// A placeholder for tutorial content. +@Composable +private fun TutorialCard(modifier: Modifier = Modifier) { + Card(modifier = modifier, content = {}) } -private fun contentCard(model: CommunalContentUiModel): CommunalGridLayoutCard { - return object : CommunalGridLayoutCard() { - override val supportedSizes = listOf(convertToCardSize(model.size)) - override val priority = model.priority +@Composable +private fun ContentCard( + model: CommunalContentUiModel, + modifier: Modifier = Modifier, +) { + AndroidView( + modifier = modifier, + factory = { + model.view.apply { + if (this is AppWidgetHostView) { + val size = SizeF(Dimensions.CardWidth.value, model.size.dp().value) + updateAppWidgetSize(Bundle.EMPTY, listOf(size)) + } + } + }, + ) +} - @Composable - override fun Content(modifier: Modifier, size: SizeF) { - AndroidView( - modifier = modifier, - factory = { - model.view.apply { - if (this is AppWidgetHostView) { - updateAppWidgetSize(Bundle(), listOf(size)) - } - } - }, - ) - } +private fun CommunalContentSize.dp(): Dp { + return when (this) { + CommunalContentSize.FULL -> Dimensions.CardHeightFull + CommunalContentSize.HALF -> Dimensions.CardHeightHalf + CommunalContentSize.THIRD -> Dimensions.CardHeightThird } } -private fun convertToCardSize(size: CommunalContentSize): CommunalGridLayoutCard.Size { - return when (size) { - CommunalContentSize.FULL -> CommunalGridLayoutCard.Size.FULL - CommunalContentSize.HALF -> CommunalGridLayoutCard.Size.HALF - CommunalContentSize.THIRD -> CommunalGridLayoutCard.Size.THIRD - } +// Sizes for the tutorial placeholders. +private val tutorialContentSizes = + listOf( + CommunalContentSize.FULL, + CommunalContentSize.THIRD, + CommunalContentSize.THIRD, + CommunalContentSize.THIRD, + CommunalContentSize.HALF, + CommunalContentSize.HALF, + CommunalContentSize.HALF, + CommunalContentSize.HALF, + ) + +private object Dimensions { + val CardWidth = 464.dp + val CardHeightFull = 630.dp + val CardHeightHalf = 307.dp + val CardHeightThird = 199.dp + val GridHeight = CardHeightFull + val Spacing = 16.dp } diff --git a/packages/SystemUI/res/layout/volume_dnd_icon.xml b/packages/SystemUI/res/layout/volume_dnd_icon.xml deleted file mode 100644 index 56587b99b80b..000000000000 --- a/packages/SystemUI/res/layout/volume_dnd_icon.xml +++ /dev/null @@ -1,31 +0,0 @@ -<!-- - Copyright (C) 2018 The Android Open Source Project - - Licensed under the Apache License, Version 2.0 (the "License"); - you may not use this file except in compliance with the License. - You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - - Unless required by applicable law or agreed to in writing, software - distributed under the License is distributed on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - See the License for the specific language governing permissions and - limitations under the License. ---> -<FrameLayout - xmlns:android="http://schemas.android.com/apk/res/android" - android:id="@+id/dnd_icon" - android:layout_width="match_parent" - android:layout_height="wrap_content" - android:layout_gravity="bottom" - android:layout_marginTop="6dp" - android:layout_marginBottom="6dp"> - - <ImageView - android:layout_width="14dp" - android:layout_height="14dp" - android:layout_gravity="center" - android:src="@*android:drawable/ic_qs_dnd" - android:tint="?android:attr/textColorTertiary"/> -</FrameLayout>
\ No newline at end of file diff --git a/packages/SystemUI/shared/src/com/android/systemui/shared/recents/model/Task.java b/packages/SystemUI/shared/src/com/android/systemui/shared/recents/model/Task.java index 3605ac2bfc66..f06e3335123f 100644 --- a/packages/SystemUI/shared/src/com/android/systemui/shared/recents/model/Task.java +++ b/packages/SystemUI/shared/src/com/android/systemui/shared/recents/model/Task.java @@ -216,7 +216,6 @@ public class Task { @Nullable public Drawable icon; @Nullable public ThumbnailData thumbnail; @ViewDebug.ExportedProperty(category="recents") - @Deprecated public String title; @ViewDebug.ExportedProperty(category="recents") public String titleDescription; diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardClockSwitchController.java b/packages/SystemUI/src/com/android/keyguard/KeyguardClockSwitchController.java index 7bf3e8f140a0..54f14572cfa5 100644 --- a/packages/SystemUI/src/com/android/keyguard/KeyguardClockSwitchController.java +++ b/packages/SystemUI/src/com/android/keyguard/KeyguardClockSwitchController.java @@ -45,6 +45,8 @@ import com.android.systemui.flags.FeatureFlagsClassic; import com.android.systemui.flags.Flags; import com.android.systemui.keyguard.KeyguardUnlockAnimationController; import com.android.systemui.keyguard.domain.interactor.KeyguardInteractor; +import com.android.systemui.keyguard.ui.binder.KeyguardRootViewBinder; +import com.android.systemui.keyguard.ui.viewmodel.KeyguardRootViewModel; import com.android.systemui.log.LogBuffer; import com.android.systemui.log.core.LogLevel; import com.android.systemui.log.dagger.KeyguardClockLog; @@ -95,6 +97,7 @@ public class KeyguardClockSwitchController extends ViewController<KeyguardClockS private final ClockEventController mClockEventController; private final LogBuffer mLogBuffer; private final NotificationIconContainerAlwaysOnDisplayViewModel mAodIconsViewModel; + private final KeyguardRootViewModel mKeyguardRootViewModel; private final ConfigurationState mConfigurationState; private final ConfigurationController mConfigurationController; private final DozeParameters mDozeParameters; @@ -127,7 +130,7 @@ public class KeyguardClockSwitchController extends ViewController<KeyguardClockS private KeyguardInteractor mKeyguardInteractor; private final DelayableExecutor mUiExecutor; private boolean mCanShowDoubleLineClock = true; - private DisposableHandle mAodIconsBindJob; + private DisposableHandle mAodIconsBindHandle; @Nullable private NotificationIconContainer mAodIconContainer; @VisibleForTesting @@ -179,6 +182,7 @@ public class KeyguardClockSwitchController extends ViewController<KeyguardClockS ClockEventController clockEventController, @KeyguardClockLog LogBuffer logBuffer, NotificationIconContainerAlwaysOnDisplayViewModel aodIconsViewModel, + KeyguardRootViewModel keyguardRootViewModel, ConfigurationState configurationState, DozeParameters dozeParameters, AlwaysOnDisplayNotificationIconViewStore aodIconViewStore, @@ -199,6 +203,7 @@ public class KeyguardClockSwitchController extends ViewController<KeyguardClockS mClockEventController = clockEventController; mLogBuffer = logBuffer; mAodIconsViewModel = aodIconsViewModel; + mKeyguardRootViewModel = keyguardRootViewModel; mConfigurationState = configurationState; mDozeParameters = dozeParameters; mAodIconViewStore = aodIconViewStore; @@ -567,21 +572,32 @@ public class KeyguardClockSwitchController extends ViewController<KeyguardClockS mView.findViewById( com.android.systemui.res.R.id.left_aligned_notification_icon_container); if (NotificationIconContainerRefactor.isEnabled()) { - if (mAodIconsBindJob != null) { - mAodIconsBindJob.dispose(); + if (mAodIconsBindHandle != null) { + mAodIconsBindHandle.dispose(); } if (nic != null) { nic.setOnLockScreen(true); - mAodIconsBindJob = NotificationIconContainerViewBinder.bind( - nic, - mAodIconsViewModel, - mConfigurationState, - mConfigurationController, - mDozeParameters, - mFeatureFlags, - mScreenOffAnimationController, - mAodIconViewStore - ); + final DisposableHandle viewHandle = NotificationIconContainerViewBinder.bind( + nic, + mAodIconsViewModel, + mConfigurationState, + mConfigurationController, + mDozeParameters, + mAodIconViewStore); + final DisposableHandle visHandle = KeyguardRootViewBinder.bindAodIconVisibility( + nic, + mKeyguardRootViewModel.isNotifIconContainerVisible(), + mConfigurationState, + mFeatureFlags, + mScreenOffAnimationController); + if (visHandle == null) { + mAodIconsBindHandle = viewHandle; + } else { + mAodIconsBindHandle = () -> { + viewHandle.dispose(); + visHandle.dispose(); + }; + } mAodIconContainer = nic; } } else { diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardFingerprintListenModel.kt b/packages/SystemUI/src/com/android/keyguard/KeyguardFingerprintListenModel.kt index 4160ae1a3ca3..953cf88feccb 100644 --- a/packages/SystemUI/src/com/android/keyguard/KeyguardFingerprintListenModel.kt +++ b/packages/SystemUI/src/com/android/keyguard/KeyguardFingerprintListenModel.kt @@ -30,6 +30,7 @@ data class KeyguardFingerprintListenModel( var allowOnCurrentOccludingActivity: Boolean = false, var alternateBouncerShowing: Boolean = false, var biometricEnabledForUser: Boolean = false, + var biometricPromptShowing: Boolean = false, var bouncerIsOrWillShow: Boolean = false, var canSkipBouncer: Boolean = false, var credentialAttempted: Boolean = false, @@ -61,6 +62,7 @@ data class KeyguardFingerprintListenModel( allowOnCurrentOccludingActivity.toString(), alternateBouncerShowing.toString(), biometricEnabledForUser.toString(), + biometricPromptShowing.toString(), bouncerIsOrWillShow.toString(), canSkipBouncer.toString(), credentialAttempted.toString(), @@ -101,6 +103,7 @@ data class KeyguardFingerprintListenModel( allowOnCurrentOccludingActivity = model.allowOnCurrentOccludingActivity alternateBouncerShowing = model.alternateBouncerShowing biometricEnabledForUser = model.biometricEnabledForUser + biometricPromptShowing = model.biometricPromptShowing bouncerIsOrWillShow = model.bouncerIsOrWillShow canSkipBouncer = model.canSkipBouncer credentialAttempted = model.credentialAttempted @@ -147,6 +150,7 @@ data class KeyguardFingerprintListenModel( "allowOnCurrentOccludingActivity", "alternateBouncerShowing", "biometricAllowedForUser", + "biometricPromptShowing", "bouncerIsOrWillShow", "canSkipBouncer", "credentialAttempted", diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitor.java b/packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitor.java index f19a9ed5546f..baab637a979c 100644 --- a/packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitor.java +++ b/packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitor.java @@ -380,6 +380,7 @@ public class KeyguardUpdateMonitor implements TrustManager.TrustListener, Dumpab private boolean mOccludingAppRequestingFace; private boolean mSecureCameraLaunched; private boolean mAllowedDisplayStateWhileAwakeForFaceAuth = true; + private boolean mBiometricPromptShowing; @VisibleForTesting protected boolean mTelephonyCapable; private boolean mAllowFingerprintOnCurrentOccludingActivity; @@ -2010,9 +2011,17 @@ public class KeyguardUpdateMonitor implements TrustManager.TrustListener, Dumpab }; private final FingerprintManager.FingerprintDetectionCallback mFingerprintDetectionCallback = - (sensorId, userId, isStrongBiometric) -> { - // Trigger the fingerprint detected path so the bouncer can be shown - handleBiometricDetected(userId, FINGERPRINT, isStrongBiometric); + new FingerprintManager.FingerprintDetectionCallback() { + @Override + public void onDetectionError(int errorMsgId) { + handleFingerprintError(errorMsgId, ""); + } + + @Override + public void onFingerprintDetected(int sensorId, int userId, + boolean isStrongBiometric) { + handleBiometricDetected(userId, FINGERPRINT, isStrongBiometric); + } }; private final FaceManager.FaceDetectionCallback mFaceDetectionCallback @@ -2641,6 +2650,19 @@ public class KeyguardUpdateMonitor implements TrustManager.TrustListener, Dumpab mainExecutor.execute(() -> updateBiometricListeningState(BIOMETRIC_ACTION_UPDATE, FACE_AUTH_TRIGGERED_ENROLLMENTS_CHANGED)); } + + @Override + public void onBiometricPromptShown() { + // SysUI should give priority to the biometric prompt requesting FP instead of + // taking over the fingerprint listening state. + mBiometricPromptShowing = true; + } + + @Override + public void onBiometricPromptDismissed() { + mBiometricPromptShowing = false; + updateFingerprintListeningState(BIOMETRIC_ACTION_START); + } }); if (mConfigFaceAuthSupportedPosture != DEVICE_POSTURE_UNKNOWN) { mPostureController.addCallback(mPostureCallback); @@ -3139,7 +3161,7 @@ public class KeyguardUpdateMonitor implements TrustManager.TrustListener, Dumpab boolean shouldListen = shouldListenKeyguardState && shouldListenUserState - && shouldListenBouncerState && shouldListenUdfpsState; + && shouldListenBouncerState && shouldListenUdfpsState && !mBiometricPromptShowing; logListenerModelData( new KeyguardFingerprintListenModel( System.currentTimeMillis(), @@ -3148,6 +3170,7 @@ public class KeyguardUpdateMonitor implements TrustManager.TrustListener, Dumpab mAllowFingerprintOnCurrentOccludingActivity, mAlternateBouncerShowing, biometricEnabledForUser, + mBiometricPromptShowing, mPrimaryBouncerIsOrWillBeShowing, userCanSkipBouncer, mCredentialAttempted, diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/AuthContainerView.java b/packages/SystemUI/src/com/android/systemui/biometrics/AuthContainerView.java index 85122baa3fec..e69eced0de45 100644 --- a/packages/SystemUI/src/com/android/systemui/biometrics/AuthContainerView.java +++ b/packages/SystemUI/src/com/android/systemui/biometrics/AuthContainerView.java @@ -18,6 +18,7 @@ package com.android.systemui.biometrics; import static android.hardware.biometrics.BiometricAuthenticator.TYPE_FACE; import static android.view.WindowManager.LayoutParams.LAYOUT_IN_DISPLAY_CUTOUT_MODE_ALWAYS; + import static com.android.internal.jank.InteractionJankMonitor.CUJ_BIOMETRIC_PROMPT_TRANSITION; import android.animation.Animator; @@ -63,7 +64,6 @@ import com.android.app.animation.Interpolators; import com.android.internal.annotations.VisibleForTesting; import com.android.internal.jank.InteractionJankMonitor; import com.android.internal.widget.LockPatternUtils; -import com.android.systemui.res.R; import com.android.systemui.biometrics.AuthController.ScaleFactorProvider; import com.android.systemui.biometrics.domain.interactor.PromptCredentialInteractor; import com.android.systemui.biometrics.domain.interactor.PromptSelectorInteractor; @@ -76,8 +76,8 @@ import com.android.systemui.biometrics.ui.binder.Spaghetti; import com.android.systemui.biometrics.ui.viewmodel.CredentialViewModel; import com.android.systemui.biometrics.ui.viewmodel.PromptViewModel; import com.android.systemui.dagger.qualifiers.Background; -import com.android.systemui.flags.FeatureFlags; import com.android.systemui.keyguard.WakefulnessLifecycle; +import com.android.systemui.res.R; import com.android.systemui.statusbar.VibratorHelper; import com.android.systemui.util.concurrency.DelayableExecutor; @@ -280,7 +280,6 @@ public class AuthContainerView extends LinearLayout // TODO(b/251476085): remove Config and further decompose these properties out of view classes AuthContainerView(@NonNull Config config, - @NonNull FeatureFlags featureFlags, @NonNull CoroutineScope applicationCoroutineScope, @Nullable List<FingerprintSensorPropertiesInternal> fpProps, @Nullable List<FaceSensorPropertiesInternal> faceProps, @@ -295,7 +294,7 @@ public class AuthContainerView extends LinearLayout @NonNull Provider<CredentialViewModel> credentialViewModelProvider, @NonNull @Background DelayableExecutor bgExecutor, @NonNull VibratorHelper vibratorHelper) { - this(config, featureFlags, applicationCoroutineScope, fpProps, faceProps, + this(config, applicationCoroutineScope, fpProps, faceProps, wakefulnessLifecycle, panelInteractionDetector, userManager, lockPatternUtils, jankMonitor, promptSelectorInteractor, promptCredentialInteractor, promptViewModel, credentialViewModelProvider, new Handler(Looper.getMainLooper()), bgExecutor, @@ -304,7 +303,6 @@ public class AuthContainerView extends LinearLayout @VisibleForTesting AuthContainerView(@NonNull Config config, - @NonNull FeatureFlags featureFlags, @NonNull CoroutineScope applicationCoroutineScope, @Nullable List<FingerprintSensorPropertiesInternal> fpProps, @Nullable List<FaceSensorPropertiesInternal> faceProps, @@ -368,7 +366,7 @@ public class AuthContainerView extends LinearLayout showPrompt(config, layoutInflater, promptViewModel, Utils.findFirstSensorProperties(fpProps, mConfig.mSensorIds), Utils.findFirstSensorProperties(faceProps, mConfig.mSensorIds), - vibratorHelper, featureFlags); + vibratorHelper); // TODO: De-dupe the logic with AuthCredentialPasswordView setOnKeyListener((v, keyCode, event) -> { @@ -390,8 +388,7 @@ public class AuthContainerView extends LinearLayout @NonNull PromptViewModel viewModel, @Nullable FingerprintSensorPropertiesInternal fpProps, @Nullable FaceSensorPropertiesInternal faceProps, - @NonNull VibratorHelper vibratorHelper, - @NonNull FeatureFlags featureFlags + @NonNull VibratorHelper vibratorHelper ) { if (Utils.isBiometricAllowed(config.mPromptInfo)) { mPromptSelectorInteractorProvider.get().useBiometricsForAuthentication( @@ -407,7 +404,7 @@ public class AuthContainerView extends LinearLayout getJankListener(view, TRANSIT, BiometricViewSizeBinder.ANIMATE_MEDIUM_TO_LARGE_DURATION_MS), mBackgroundView, mBiometricCallback, mApplicationCoroutineScope, - vibratorHelper, featureFlags); + vibratorHelper); // TODO(b/251476085): migrate these dependencies if (fpProps != null && fpProps.isAnyUdfpsType()) { diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/AuthController.java b/packages/SystemUI/src/com/android/systemui/biometrics/AuthController.java index a64e862000fc..05db56f9eafb 100644 --- a/packages/SystemUI/src/com/android/systemui/biometrics/AuthController.java +++ b/packages/SystemUI/src/com/android/systemui/biometrics/AuthController.java @@ -78,7 +78,6 @@ import com.android.systemui.dagger.qualifiers.Application; import com.android.systemui.dagger.qualifiers.Background; import com.android.systemui.dagger.qualifiers.Main; import com.android.systemui.doze.DozeReceiver; -import com.android.systemui.flags.FeatureFlags; import com.android.systemui.keyguard.WakefulnessLifecycle; import com.android.systemui.keyguard.data.repository.BiometricType; import com.android.systemui.statusbar.CommandQueue; @@ -120,7 +119,6 @@ public class AuthController implements CoreStartable, CommandQueue.Callbacks, private final Handler mHandler; private final Context mContext; - private final FeatureFlags mFeatureFlags; private final Execution mExecution; private final CommandQueue mCommandQueue; private final ActivityTaskManager mActivityTaskManager; @@ -743,7 +741,6 @@ public class AuthController implements CoreStartable, CommandQueue.Callbacks, } @Inject public AuthController(Context context, - @NonNull FeatureFlags featureFlags, @Application CoroutineScope applicationCoroutineScope, Execution execution, CommandQueue commandQueue, @@ -770,7 +767,6 @@ public class AuthController implements CoreStartable, CommandQueue.Callbacks, @NonNull UdfpsUtils udfpsUtils, @NonNull VibratorHelper vibratorHelper) { mContext = context; - mFeatureFlags = featureFlags; mExecution = execution; mUserManager = userManager; mLockPatternUtils = lockPatternUtils; @@ -1316,7 +1312,7 @@ public class AuthController implements CoreStartable, CommandQueue.Callbacks, config.mRequestId = requestId; config.mSensorIds = sensorIds; config.mScaleProvider = this::getScaleFactor; - return new AuthContainerView(config, mFeatureFlags, mApplicationCoroutineScope, mFpProps, mFaceProps, + return new AuthContainerView(config, mApplicationCoroutineScope, mFpProps, mFaceProps, wakefulnessLifecycle, panelInteractionDetector, userManager, lockPatternUtils, mInteractionJankMonitor, mPromptCredentialInteractor, mPromptSelectorInteractor, viewModel, mCredentialViewModelProvider, bgExecutor, mVibratorHelper); diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/domain/interactor/SideFpsSensorInteractor.kt b/packages/SystemUI/src/com/android/systemui/biometrics/domain/interactor/SideFpsSensorInteractor.kt index f85203ea2076..0567ea2ee465 100644 --- a/packages/SystemUI/src/com/android/systemui/biometrics/domain/interactor/SideFpsSensorInteractor.kt +++ b/packages/SystemUI/src/com/android/systemui/biometrics/domain/interactor/SideFpsSensorInteractor.kt @@ -19,6 +19,7 @@ package com.android.systemui.biometrics.domain.interactor import android.content.Context import android.hardware.biometrics.SensorLocationInternal import android.view.WindowManager +import com.android.systemui.biometrics.FingerprintInteractiveToAuthProvider import com.android.systemui.biometrics.data.repository.FingerprintPropertyRepository import com.android.systemui.biometrics.domain.model.SideFpsSensorLocation import com.android.systemui.biometrics.shared.model.DisplayRotation @@ -27,17 +28,16 @@ import com.android.systemui.biometrics.shared.model.isDefaultOrientation import com.android.systemui.dagger.SysUISingleton import com.android.systemui.flags.FeatureFlagsClassic import com.android.systemui.flags.Flags +import com.android.systemui.log.SideFpsLogger import com.android.systemui.res.R +import java.util.Optional import javax.inject.Inject -import kotlinx.coroutines.ExperimentalCoroutinesApi import kotlinx.coroutines.flow.Flow import kotlinx.coroutines.flow.combine import kotlinx.coroutines.flow.filterNotNull -import kotlinx.coroutines.flow.flatMapLatest import kotlinx.coroutines.flow.flowOf import kotlinx.coroutines.flow.map -@OptIn(ExperimentalCoroutinesApi::class) @SysUISingleton class SideFpsSensorInteractor @Inject @@ -47,6 +47,8 @@ constructor( windowManager: WindowManager, displayStateInteractor: DisplayStateInteractor, featureFlags: FeatureFlagsClassic, + fingerprintInteractiveToAuthProvider: Optional<FingerprintInteractiveToAuthProvider>, + private val logger: SideFpsLogger, ) { private val sensorForCurrentDisplay = @@ -65,12 +67,18 @@ constructor( flowOf(context.resources?.getInteger(R.integer.config_restToUnlockDuration)?.toLong() ?: 0L) val isProlongedTouchRequiredForAuthentication: Flow<Boolean> = - isAvailable.flatMapLatest { sfpsAvailable -> - if (sfpsAvailable) { - // todo (b/305236201) also add the settings check here. - flowOf(featureFlags.isEnabled(Flags.REST_TO_UNLOCK)) - } else { - flowOf(false) + if ( + fingerprintInteractiveToAuthProvider.isEmpty || + !featureFlags.isEnabled(Flags.REST_TO_UNLOCK) + ) { + flowOf(false) + } else { + combine( + isAvailable, + fingerprintInteractiveToAuthProvider.get().enabledForCurrentUser + ) { sfpsAvailable, isSettingEnabled -> + logger.logStateChange(sfpsAvailable, isSettingEnabled) + sfpsAvailable && isSettingEnabled } } @@ -126,6 +134,15 @@ constructor( } } + logger.sensorLocationStateChanged( + size, + rotation, + displayWidth, + displayHeight, + sensorWidth, + isSensorVerticalInDefaultOrientation + ) + SideFpsSensorLocation( left = sensorLeft, top = sensorTop, diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/ui/binder/BiometricViewBinder.kt b/packages/SystemUI/src/com/android/systemui/biometrics/ui/binder/BiometricViewBinder.kt index ac48b6a2b11e..32d9067bd9e4 100644 --- a/packages/SystemUI/src/com/android/systemui/biometrics/ui/binder/BiometricViewBinder.kt +++ b/packages/SystemUI/src/com/android/systemui/biometrics/ui/binder/BiometricViewBinder.kt @@ -49,8 +49,6 @@ import com.android.systemui.biometrics.ui.viewmodel.FingerprintStartMode import com.android.systemui.biometrics.ui.viewmodel.PromptMessage import com.android.systemui.biometrics.ui.viewmodel.PromptSize import com.android.systemui.biometrics.ui.viewmodel.PromptViewModel -import com.android.systemui.flags.FeatureFlags -import com.android.systemui.flags.Flags.ONE_WAY_HAPTICS_API_MIGRATION import com.android.systemui.lifecycle.repeatWhenAttached import com.android.systemui.res.R import com.android.systemui.statusbar.VibratorHelper @@ -78,7 +76,6 @@ object BiometricViewBinder { legacyCallback: Spaghetti.Callback, applicationScope: CoroutineScope, vibratorHelper: VibratorHelper, - featureFlags: FeatureFlags, ): Spaghetti { val accessibilityManager = view.context.getSystemService(AccessibilityManager::class.java)!! @@ -380,13 +377,11 @@ object BiometricViewBinder { } // Play haptics - if (featureFlags.isEnabled(ONE_WAY_HAPTICS_API_MIGRATION)) { - launch { - viewModel.hapticsToPlay.collect { hapticFeedbackConstant -> - if (hapticFeedbackConstant != HapticFeedbackConstants.NO_HAPTICS) { - vibratorHelper.performHapticFeedback(view, hapticFeedbackConstant) - viewModel.clearHaptics() - } + launch { + viewModel.hapticsToPlay.collect { hapticFeedbackConstant -> + if (hapticFeedbackConstant != HapticFeedbackConstants.NO_HAPTICS) { + vibratorHelper.performHapticFeedback(view, hapticFeedbackConstant) + viewModel.clearHaptics() } } } diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/ui/viewmodel/PromptViewModel.kt b/packages/SystemUI/src/com/android/systemui/biometrics/ui/viewmodel/PromptViewModel.kt index e49b4a7bbce9..647aaf392ed8 100644 --- a/packages/SystemUI/src/com/android/systemui/biometrics/ui/viewmodel/PromptViewModel.kt +++ b/packages/SystemUI/src/com/android/systemui/biometrics/ui/viewmodel/PromptViewModel.kt @@ -29,10 +29,7 @@ import com.android.systemui.biometrics.shared.model.BiometricModality import com.android.systemui.biometrics.shared.model.DisplayRotation import com.android.systemui.biometrics.shared.model.PromptKind import com.android.systemui.dagger.qualifiers.Application -import com.android.systemui.flags.FeatureFlags -import com.android.systemui.flags.Flags.ONE_WAY_HAPTICS_API_MIGRATION import com.android.systemui.res.R -import com.android.systemui.statusbar.VibratorHelper import javax.inject.Inject import kotlinx.coroutines.Job import kotlinx.coroutines.coroutineScope @@ -52,9 +49,7 @@ class PromptViewModel constructor( displayStateInteractor: DisplayStateInteractor, promptSelectorInteractor: PromptSelectorInteractor, - private val vibrator: VibratorHelper, @Application context: Context, - private val featureFlags: FeatureFlags, ) { /** The set of modalities available for this prompt */ val modalities: Flow<BiometricModalities> = @@ -339,7 +334,7 @@ constructor( _message.value = PromptMessage.Error(message) if (hapticFeedback) { - vibrator.error(failedModality) + vibrateOnError() } messageJob?.cancel() @@ -457,7 +452,7 @@ constructor( _message.value = PromptMessage.Empty if (!needsUserConfirmation) { - vibrator.success(modality) + vibrateOnSuccess() } messageJob?.cancel() @@ -495,7 +490,7 @@ constructor( _isAuthenticated.value = authState.asExplicitlyConfirmed() _message.value = PromptMessage.Empty - vibrator.success(authState.authenticatedModality) + vibrateOnSuccess() messageJob?.cancel() messageJob = null @@ -530,20 +525,12 @@ constructor( _forceLargeSize.value = true } - private fun VibratorHelper.success(modality: BiometricModality) { - if (featureFlags.isEnabled(ONE_WAY_HAPTICS_API_MIGRATION)) { - _hapticsToPlay.value = HapticFeedbackConstants.CONFIRM - } else { - vibrateAuthSuccess("$TAG, modality = $modality BP::success") - } + private fun vibrateOnSuccess() { + _hapticsToPlay.value = HapticFeedbackConstants.CONFIRM } - private fun VibratorHelper.error(modality: BiometricModality = BiometricModality.None) { - if (featureFlags.isEnabled(ONE_WAY_HAPTICS_API_MIGRATION)) { - _hapticsToPlay.value = HapticFeedbackConstants.REJECT - } else { - vibrateAuthError("$TAG, modality = $modality BP::error") - } + private fun vibrateOnError() { + _hapticsToPlay.value = HapticFeedbackConstants.REJECT } /** Clears the [hapticsToPlay] variable by setting it to the NO_HAPTICS default. */ diff --git a/packages/SystemUI/src/com/android/systemui/classifier/FalsingCollector.java b/packages/SystemUI/src/com/android/systemui/classifier/FalsingCollector.java index f77f98956cbf..a79a654aedc2 100644 --- a/packages/SystemUI/src/com/android/systemui/classifier/FalsingCollector.java +++ b/packages/SystemUI/src/com/android/systemui/classifier/FalsingCollector.java @@ -75,5 +75,8 @@ public interface FalsingCollector { /** Indicates an a11y action was made. */ void onA11yAction(); + + /** Initialize the class. */ + void init(); } diff --git a/packages/SystemUI/src/com/android/systemui/classifier/FalsingCollectorFake.java b/packages/SystemUI/src/com/android/systemui/classifier/FalsingCollectorFake.java index 0dfaf0f4318d..d6b9a119e31c 100644 --- a/packages/SystemUI/src/com/android/systemui/classifier/FalsingCollectorFake.java +++ b/packages/SystemUI/src/com/android/systemui/classifier/FalsingCollectorFake.java @@ -23,6 +23,10 @@ import javax.inject.Inject; /** */ public class FalsingCollectorFake implements FalsingCollector { + @Override + public void init() { + } + @Inject public FalsingCollectorFake() { } diff --git a/packages/SystemUI/src/com/android/systemui/classifier/FalsingCollectorImpl.java b/packages/SystemUI/src/com/android/systemui/classifier/FalsingCollectorImpl.java index a6b073da2530..12df96e41b2c 100644 --- a/packages/SystemUI/src/com/android/systemui/classifier/FalsingCollectorImpl.java +++ b/packages/SystemUI/src/com/android/systemui/classifier/FalsingCollectorImpl.java @@ -32,13 +32,14 @@ import com.android.systemui.dagger.qualifiers.Main; import com.android.systemui.dock.DockManager; import com.android.systemui.plugins.FalsingManager; import com.android.systemui.plugins.statusbar.StatusBarStateController; -import com.android.systemui.shade.ShadeExpansionStateManager; +import com.android.systemui.shade.domain.interactor.ShadeInteractor; import com.android.systemui.statusbar.StatusBarState; import com.android.systemui.statusbar.policy.BatteryController; import com.android.systemui.statusbar.policy.BatteryController.BatteryStateChangeCallback; import com.android.systemui.statusbar.policy.KeyguardStateController; import com.android.systemui.user.domain.interactor.SelectedUserInteractor; import com.android.systemui.util.concurrency.DelayableExecutor; +import com.android.systemui.util.kotlin.JavaAdapter; import com.android.systemui.util.sensors.ProximitySensor; import com.android.systemui.util.sensors.ThresholdSensor; import com.android.systemui.util.sensors.ThresholdSensorEvent; @@ -65,9 +66,11 @@ class FalsingCollectorImpl implements FalsingCollector { private final ProximitySensor mProximitySensor; private final StatusBarStateController mStatusBarStateController; private final KeyguardStateController mKeyguardStateController; + private final Lazy<ShadeInteractor> mShadeInteractorLazy; private final BatteryController mBatteryController; private final DockManager mDockManager; private final DelayableExecutor mMainExecutor; + private final JavaAdapter mJavaAdapter; private final SystemClock mSystemClock; private final Lazy<SelectedUserInteractor> mUserInteractor; @@ -136,10 +139,11 @@ class FalsingCollectorImpl implements FalsingCollector { ProximitySensor proximitySensor, StatusBarStateController statusBarStateController, KeyguardStateController keyguardStateController, - ShadeExpansionStateManager shadeExpansionStateManager, + Lazy<ShadeInteractor> shadeInteractorLazy, BatteryController batteryController, DockManager dockManager, @Main DelayableExecutor mainExecutor, + JavaAdapter javaAdapter, SystemClock systemClock, Lazy<SelectedUserInteractor> userInteractor) { mFalsingDataProvider = falsingDataProvider; @@ -149,12 +153,17 @@ class FalsingCollectorImpl implements FalsingCollector { mProximitySensor = proximitySensor; mStatusBarStateController = statusBarStateController; mKeyguardStateController = keyguardStateController; + mShadeInteractorLazy = shadeInteractorLazy; mBatteryController = batteryController; mDockManager = dockManager; mMainExecutor = mainExecutor; + mJavaAdapter = javaAdapter; mSystemClock = systemClock; mUserInteractor = userInteractor; + } + @Override + public void init() { mProximitySensor.setTag(PROXIMITY_SENSOR_TAG); mProximitySensor.setDelay(SensorManager.SENSOR_DELAY_GAME); @@ -163,7 +172,10 @@ class FalsingCollectorImpl implements FalsingCollector { mKeyguardUpdateMonitor.registerCallback(mKeyguardUpdateCallback); - shadeExpansionStateManager.addQsExpansionListener(this::onQsExpansionChanged); + mJavaAdapter.alwaysCollectFlow( + mShadeInteractorLazy.get().isQsExpanded(), + this::onQsExpansionChanged + ); mBatteryController.addCallback(mBatteryListener); mDockManager.addListener(mDockEventListener); diff --git a/packages/SystemUI/src/com/android/systemui/classifier/FalsingCollectorNoOp.kt b/packages/SystemUI/src/com/android/systemui/classifier/FalsingCollectorNoOp.kt index e5b404f30889..c5d8c795853d 100644 --- a/packages/SystemUI/src/com/android/systemui/classifier/FalsingCollectorNoOp.kt +++ b/packages/SystemUI/src/com/android/systemui/classifier/FalsingCollectorNoOp.kt @@ -23,6 +23,10 @@ import javax.inject.Inject @SysUISingleton class FalsingCollectorNoOp @Inject constructor() : FalsingCollector { + override fun init() { + logDebug("NOOP: init") + } + override fun onSuccessfulUnlock() { logDebug("NOOP: onSuccessfulUnlock") } diff --git a/packages/SystemUI/src/com/android/systemui/classifier/FalsingCoreStartable.kt b/packages/SystemUI/src/com/android/systemui/classifier/FalsingCoreStartable.kt new file mode 100644 index 000000000000..b79538aac3e6 --- /dev/null +++ b/packages/SystemUI/src/com/android/systemui/classifier/FalsingCoreStartable.kt @@ -0,0 +1,29 @@ +/* + * Copyright (C) 2023 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.android.systemui.classifier + +import com.android.systemui.CoreStartable +import com.android.systemui.dagger.SysUISingleton +import javax.inject.Inject + +/** Initializes classes related to falsing. */ +@SysUISingleton +class FalsingCoreStartable @Inject constructor(val falsingCollector: FalsingCollector) : + CoreStartable { + override fun start() { + falsingCollector.init() + } +} diff --git a/packages/SystemUI/src/com/android/systemui/classifier/FalsingModule.java b/packages/SystemUI/src/com/android/systemui/classifier/FalsingModule.java index 2729b7b0a4fd..af467ef1319b 100644 --- a/packages/SystemUI/src/com/android/systemui/classifier/FalsingModule.java +++ b/packages/SystemUI/src/com/android/systemui/classifier/FalsingModule.java @@ -19,9 +19,9 @@ package com.android.systemui.classifier; import android.content.res.Resources; import android.view.ViewConfiguration; -import com.android.systemui.res.R; import com.android.systemui.dagger.SysUISingleton; import com.android.systemui.dagger.qualifiers.Main; +import com.android.systemui.res.R; import com.android.systemui.scene.shared.flag.SceneContainerFlags; import com.android.systemui.statusbar.phone.NotificationTapHelper; @@ -37,7 +37,7 @@ import java.util.Set; import javax.inject.Named; /** Dagger Module for Falsing. */ -@Module +@Module(includes = {FalsingStartModule.class}) public interface FalsingModule { String BRIGHT_LINE_GESTURE_CLASSIFERS = "bright_line_gesture_classifiers"; String SINGLE_TAP_TOUCH_SLOP = "falsing_single_tap_touch_slop"; diff --git a/packages/SystemUI/src/com/android/systemui/classifier/FalsingStartModule.kt b/packages/SystemUI/src/com/android/systemui/classifier/FalsingStartModule.kt new file mode 100644 index 000000000000..a9f8f37fffa9 --- /dev/null +++ b/packages/SystemUI/src/com/android/systemui/classifier/FalsingStartModule.kt @@ -0,0 +1,31 @@ +/* + * Copyright (C) 2023 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.android.systemui.classifier + +import com.android.systemui.CoreStartable +import dagger.Binds +import dagger.Module +import dagger.multibindings.ClassKey +import dagger.multibindings.IntoMap + +@Module +interface FalsingStartModule { + /** */ + @Binds + @IntoMap + @ClassKey(FalsingCoreStartable::class) + fun bindFalsingCoreStartable(falsingCoreStartable: FalsingCoreStartable?): CoreStartable? +} diff --git a/packages/SystemUI/src/com/android/systemui/common/shared/model/SharedNotificationContainerPosition.kt b/packages/SystemUI/src/com/android/systemui/common/shared/model/SharedNotificationContainerPosition.kt index b2bc06f0ae29..48d374207388 100644 --- a/packages/SystemUI/src/com/android/systemui/common/shared/model/SharedNotificationContainerPosition.kt +++ b/packages/SystemUI/src/com/android/systemui/common/shared/model/SharedNotificationContainerPosition.kt @@ -20,4 +20,7 @@ package com.android.systemui.common.shared.model data class SharedNotificationContainerPosition( val top: Float = 0f, val bottom: Float = 0f, + + /** Whether any modifications to top/bottom are smoothly animated */ + val animate: Boolean = false, ) diff --git a/packages/SystemUI/src/com/android/systemui/communal/shared/model/CommunalContentSize.kt b/packages/SystemUI/src/com/android/systemui/communal/shared/model/CommunalContentSize.kt index 39a6476929ed..c903709aa2ee 100644 --- a/packages/SystemUI/src/com/android/systemui/communal/shared/model/CommunalContentSize.kt +++ b/packages/SystemUI/src/com/android/systemui/communal/shared/model/CommunalContentSize.kt @@ -16,14 +16,19 @@ package com.android.systemui.communal.shared.model -/** Supported sizes for communal content in the layout grid. */ -enum class CommunalContentSize { +/** + * Supported sizes for communal content in the layout grid. + * + * @param span The span of the content in a column. For example, if FULL is 6, then 3 represents + * HALF, 2 represents THIRD, and 1 represents SIXTH. + */ +enum class CommunalContentSize(val span: Int) { /** Content takes the full height of the column. */ - FULL, + FULL(6), /** Content takes half of the height of the column. */ - HALF, + HALF(3), /** Content takes a third of the height of the column. */ - THIRD, + THIRD(2), } diff --git a/packages/SystemUI/src/com/android/systemui/communal/ui/model/CommunalContentUiModel.kt b/packages/SystemUI/src/com/android/systemui/communal/ui/model/CommunalContentUiModel.kt index 98060dc1dceb..b60dc2a21699 100644 --- a/packages/SystemUI/src/com/android/systemui/communal/ui/model/CommunalContentUiModel.kt +++ b/packages/SystemUI/src/com/android/systemui/communal/ui/model/CommunalContentUiModel.kt @@ -9,7 +9,7 @@ import com.android.systemui.communal.shared.model.CommunalContentSize * This model stays in the UI layer. */ data class CommunalContentUiModel( + val id: String, val view: View, - val size: CommunalContentSize, - val priority: Int, + val size: CommunalContentSize = CommunalContentSize.HALF, ) diff --git a/packages/SystemUI/src/com/android/systemui/communal/ui/viewmodel/CommunalViewModel.kt b/packages/SystemUI/src/com/android/systemui/communal/ui/viewmodel/CommunalViewModel.kt index 25c64eafe255..390b580bad28 100644 --- a/packages/SystemUI/src/com/android/systemui/communal/ui/viewmodel/CommunalViewModel.kt +++ b/packages/SystemUI/src/com/android/systemui/communal/ui/viewmodel/CommunalViewModel.kt @@ -20,7 +20,6 @@ import android.appwidget.AppWidgetHost import android.content.Context import com.android.systemui.communal.domain.interactor.CommunalInteractor import com.android.systemui.communal.domain.interactor.CommunalTutorialInteractor -import com.android.systemui.communal.shared.model.CommunalContentSize import com.android.systemui.communal.ui.model.CommunalContentUiModel import com.android.systemui.dagger.SysUISingleton import com.android.systemui.dagger.qualifiers.Application @@ -42,16 +41,16 @@ constructor( /** List of widgets to be displayed in the communal hub. */ val widgetContent: Flow<List<CommunalContentUiModel>> = - communalInteractor.widgetContent.map { - it.map { + communalInteractor.widgetContent.map { widgets -> + widgets.map Widget@{ widget -> // TODO(b/306406256): As adding and removing widgets functionalities are // supported, cache the host views so they're not recreated each time. - val hostView = appWidgetHost.createView(context, it.appWidgetId, it.providerInfo) - return@map CommunalContentUiModel( + val hostView = + appWidgetHost.createView(context, widget.appWidgetId, widget.providerInfo) + return@Widget CommunalContentUiModel( + // TODO(b/308148193): a more scalable solution for unique ids. + id = "widget_${widget.appWidgetId}", view = hostView, - priority = it.priority, - // All widgets have HALF size. - size = CommunalContentSize.HALF, ) } } diff --git a/packages/SystemUI/src/com/android/systemui/controls/ui/ControlActionCoordinatorImpl.kt b/packages/SystemUI/src/com/android/systemui/controls/ui/ControlActionCoordinatorImpl.kt index 00d95c02c172..0f038e10dd4e 100644 --- a/packages/SystemUI/src/com/android/systemui/controls/ui/ControlActionCoordinatorImpl.kt +++ b/packages/SystemUI/src/com/android/systemui/controls/ui/ControlActionCoordinatorImpl.kt @@ -37,8 +37,6 @@ import com.android.systemui.controls.ControlsMetricsLogger import com.android.systemui.controls.settings.ControlsSettingsRepository import com.android.systemui.dagger.SysUISingleton import com.android.systemui.dagger.qualifiers.Main -import com.android.systemui.flags.FeatureFlags -import com.android.systemui.flags.Flags.ONE_WAY_HAPTICS_API_MIGRATION import com.android.systemui.plugins.ActivityStarter import com.android.systemui.statusbar.VibratorHelper import com.android.systemui.statusbar.policy.KeyguardStateController @@ -59,7 +57,6 @@ class ControlActionCoordinatorImpl @Inject constructor( private val controlsMetricsLogger: ControlsMetricsLogger, private val vibrator: VibratorHelper, private val controlsSettingsRepository: ControlsSettingsRepository, - private val featureFlags: FeatureFlags, ) : ControlActionCoordinator { private var dialog: Dialog? = null private var pendingAction: Action? = null @@ -123,17 +120,12 @@ class ControlActionCoordinatorImpl @Inject constructor( } override fun drag(cvh: ControlViewHolder, isEdge: Boolean) { - if (featureFlags.isEnabled(ONE_WAY_HAPTICS_API_MIGRATION)) { - val constant = - if (isEdge) - HapticFeedbackConstants.SEGMENT_TICK - else - HapticFeedbackConstants.SEGMENT_FREQUENT_TICK - vibrator.performHapticFeedback(cvh.layout, constant) - } else { - val effect = if (isEdge) Vibrations.rangeEdgeEffect else Vibrations.rangeMiddleEffect - vibrate(effect) - } + val constant = + if (isEdge) + HapticFeedbackConstants.SEGMENT_TICK + else + HapticFeedbackConstants.SEGMENT_FREQUENT_TICK + vibrator.performHapticFeedback(cvh.layout, constant) } override fun setValue(cvh: ControlViewHolder, templateId: String, newValue: Float) { diff --git a/packages/SystemUI/src/com/android/systemui/controls/ui/Vibrations.kt b/packages/SystemUI/src/com/android/systemui/controls/ui/Vibrations.kt deleted file mode 100644 index 29b7e985fabc..000000000000 --- a/packages/SystemUI/src/com/android/systemui/controls/ui/Vibrations.kt +++ /dev/null @@ -1,37 +0,0 @@ -/* - * Copyright (C) 2020 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.android.systemui.controls.ui - -import android.os.VibrationEffect -import android.os.VibrationEffect.Composition.PRIMITIVE_TICK - -object Vibrations { - val rangeEdgeEffect = initRangeEdgeEffect() - val rangeMiddleEffect = initRangeMiddleEffect() - - private fun initRangeEdgeEffect(): VibrationEffect { - val composition = VibrationEffect.startComposition() - composition.addPrimitive(VibrationEffect.Composition.PRIMITIVE_TICK, 0.5f) - return composition.compose() - } - - private fun initRangeMiddleEffect(): VibrationEffect { - val composition = VibrationEffect.startComposition() - composition.addPrimitive(VibrationEffect.Composition.PRIMITIVE_TICK, 0.1f) - return composition.compose() - } -} diff --git a/packages/SystemUI/src/com/android/systemui/dagger/ReferenceSystemUIModule.java b/packages/SystemUI/src/com/android/systemui/dagger/ReferenceSystemUIModule.java index 1dd4abfa0767..236c5b8ed2d7 100644 --- a/packages/SystemUI/src/com/android/systemui/dagger/ReferenceSystemUIModule.java +++ b/packages/SystemUI/src/com/android/systemui/dagger/ReferenceSystemUIModule.java @@ -48,7 +48,6 @@ import com.android.systemui.statusbar.NotificationLockscreenUserManager; import com.android.systemui.statusbar.NotificationLockscreenUserManagerImpl; import com.android.systemui.statusbar.NotificationShadeWindowController; import com.android.systemui.statusbar.dagger.StartCentralSurfacesModule; -import com.android.systemui.statusbar.events.StatusBarEventsModule; import com.android.systemui.statusbar.phone.DozeServiceHost; import com.android.systemui.statusbar.phone.HeadsUpModule; import com.android.systemui.statusbar.phone.StatusBarKeyguardViewManager; @@ -99,7 +98,6 @@ import javax.inject.Named; ReferenceScreenshotModule.class, RotationLockModule.class, SceneContainerFrameworkModule.class, - StatusBarEventsModule.class, StartCentralSurfacesModule.class, VolumeModule.class, WallpaperModule.class, diff --git a/packages/SystemUI/src/com/android/systemui/dagger/SystemUIModule.java b/packages/SystemUI/src/com/android/systemui/dagger/SystemUIModule.java index a41bb2f67ad2..7915088b4642 100644 --- a/packages/SystemUI/src/com/android/systemui/dagger/SystemUIModule.java +++ b/packages/SystemUI/src/com/android/systemui/dagger/SystemUIModule.java @@ -96,6 +96,7 @@ import com.android.systemui.statusbar.NotificationShadeWindowController; import com.android.systemui.statusbar.connectivity.ConnectivityModule; import com.android.systemui.statusbar.dagger.StatusBarModule; import com.android.systemui.statusbar.disableflags.dagger.DisableFlagsModule; +import com.android.systemui.statusbar.events.StatusBarEventsModule; import com.android.systemui.statusbar.events.SystemStatusAnimationScheduler; import com.android.systemui.statusbar.notification.NotifPipelineFlags; import com.android.systemui.statusbar.notification.collection.NotifPipeline; @@ -209,6 +210,7 @@ import javax.inject.Named; SettingsUtilModule.class, SmartRepliesInflationModule.class, SmartspaceModule.class, + StatusBarEventsModule.class, StatusBarModule.class, StatusBarPipelineModule.class, StatusBarPolicyModule.class, diff --git a/packages/SystemUI/src/com/android/systemui/flags/Flags.kt b/packages/SystemUI/src/com/android/systemui/flags/Flags.kt index f4a9f739d187..fa9866163646 100644 --- a/packages/SystemUI/src/com/android/systemui/flags/Flags.kt +++ b/packages/SystemUI/src/com/android/systemui/flags/Flags.kt @@ -400,8 +400,7 @@ object Flags { // 600- status bar // TODO(b/291315866): Tracking Bug - @JvmField val SIGNAL_CALLBACK_DEPRECATION = - unreleasedFlag("signal_callback_deprecation", teamfood = true) + @JvmField val SIGNAL_CALLBACK_DEPRECATION = releasedFlag("signal_callback_deprecation") // TODO(b/301610137): Tracking bug @JvmField val NEW_NETWORK_SLICE_UI = unreleasedFlag("new_network_slice_ui", teamfood = true) @@ -410,19 +409,15 @@ object Flags { val FILTER_PROVISIONING_NETWORK_SUBSCRIPTIONS = releasedFlag("filter_provisioning_network_subscriptions") - // TODO(b/265892345): Tracking Bug - val PLUG_IN_STATUS_BAR_CHIP = releasedFlag("plug_in_status_bar_chip") - // TODO(b/292533677): Tracking Bug - val WIFI_TRACKER_LIB_FOR_WIFI_ICON = - unreleasedFlag("wifi_tracker_lib_for_wifi_icon", teamfood = true) + val WIFI_TRACKER_LIB_FOR_WIFI_ICON = releasedFlag("wifi_tracker_lib_for_wifi_icon") // TODO(b/293863612): Tracking Bug @JvmField val INCOMPATIBLE_CHARGING_BATTERY_ICON = releasedFlag("incompatible_charging_battery_icon") // TODO(b/293585143): Tracking Bug - val INSTANT_TETHER = unreleasedFlag("instant_tether", teamfood = true) + val INSTANT_TETHER = releasedFlag("instant_tether") // TODO(b/294588085): Tracking Bug val WIFI_SECONDARY_NETWORKS = releasedFlag("wifi_secondary_networks") diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewConfigurator.kt b/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewConfigurator.kt index c56dfde86573..61c8e1bbc1d8 100644 --- a/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewConfigurator.kt +++ b/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewConfigurator.kt @@ -27,9 +27,10 @@ import com.android.keyguard.LockIconView import com.android.keyguard.LockIconViewController import com.android.keyguard.dagger.KeyguardStatusViewComponent import com.android.systemui.CoreStartable +import com.android.systemui.common.ui.ConfigurationState import com.android.systemui.dagger.SysUISingleton import com.android.systemui.deviceentry.domain.interactor.DeviceEntryHapticsInteractor -import com.android.systemui.flags.FeatureFlags +import com.android.systemui.flags.FeatureFlagsClassic import com.android.systemui.flags.Flags import com.android.systemui.keyguard.ui.binder.KeyguardBlueprintViewBinder import com.android.systemui.keyguard.ui.binder.KeyguardIndicationAreaBinder @@ -46,7 +47,7 @@ import com.android.systemui.shade.NotificationShadeWindowView import com.android.systemui.shade.domain.interactor.ShadeInteractor import com.android.systemui.statusbar.KeyguardIndicationController import com.android.systemui.statusbar.VibratorHelper -import com.android.systemui.statusbar.policy.KeyguardStateController +import com.android.systemui.statusbar.phone.ScreenOffAnimationController import com.android.systemui.temporarydisplay.chipbar.ChipbarCoordinator import dagger.Lazy import javax.inject.Inject @@ -63,14 +64,15 @@ constructor( private val keyguardRootViewModel: KeyguardRootViewModel, private val keyguardIndicationAreaViewModel: KeyguardIndicationAreaViewModel, private val notificationShadeWindowView: NotificationShadeWindowView, - private val featureFlags: FeatureFlags, + private val featureFlags: FeatureFlagsClassic, private val indicationController: KeyguardIndicationController, - private val keyguardStateController: KeyguardStateController, + private val screenOffAnimationController: ScreenOffAnimationController, private val occludingAppDeviceEntryMessageViewModel: OccludingAppDeviceEntryMessageViewModel, private val chipbarCoordinator: ChipbarCoordinator, private val keyguardBlueprintCommandListener: KeyguardBlueprintCommandListener, private val keyguardBlueprintViewModel: KeyguardBlueprintViewModel, private val keyguardStatusViewComponentFactory: KeyguardStatusViewComponent.Factory, + private val configuration: ConfigurationState, private val context: Context, private val keyguardIndicationController: KeyguardIndicationController, private val lockIconViewController: Lazy<LockIconViewController>, @@ -143,10 +145,11 @@ constructor( KeyguardRootViewBinder.bind( keyguardRootView, keyguardRootViewModel, + configuration, featureFlags, occludingAppDeviceEntryMessageViewModel, chipbarCoordinator, - keyguardStateController, + screenOffAnimationController, shadeInteractor, { keyguardStatusViewController!!.getClockController() }, interactionJankMonitor, diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/ui/binder/KeyguardRootViewBinder.kt b/packages/SystemUI/src/com/android/systemui/keyguard/ui/binder/KeyguardRootViewBinder.kt index 4d5c503d1c4e..ad4895734709 100644 --- a/packages/SystemUI/src/com/android/systemui/keyguard/ui/binder/KeyguardRootViewBinder.kt +++ b/packages/SystemUI/src/com/android/systemui/keyguard/ui/binder/KeyguardRootViewBinder.kt @@ -16,23 +16,31 @@ package com.android.systemui.keyguard.ui.binder +import android.animation.Animator +import android.animation.AnimatorListenerAdapter import android.annotation.DrawableRes import android.view.HapticFeedbackConstants import android.view.View import android.view.View.OnLayoutChangeListener import android.view.ViewGroup import android.view.ViewGroup.OnHierarchyChangeListener +import android.view.ViewPropertyAnimator +import android.view.WindowInsets import androidx.lifecycle.Lifecycle +import androidx.lifecycle.lifecycleScope import androidx.lifecycle.repeatOnLifecycle +import com.android.app.animation.Interpolators import com.android.internal.jank.InteractionJankMonitor import com.android.internal.jank.InteractionJankMonitor.CUJ_SCREEN_OFF_SHOW_AOD import com.android.keyguard.KeyguardClockSwitch.MISSING_CLOCK_ID import com.android.systemui.common.shared.model.Icon import com.android.systemui.common.shared.model.Text import com.android.systemui.common.shared.model.TintedIcon +import com.android.systemui.common.ui.ConfigurationState import com.android.systemui.deviceentry.domain.interactor.DeviceEntryHapticsInteractor -import com.android.systemui.flags.FeatureFlags +import com.android.systemui.flags.FeatureFlagsClassic import com.android.systemui.flags.Flags +import com.android.systemui.flags.RefactorFlag import com.android.systemui.keyguard.shared.model.TransitionState import com.android.systemui.keyguard.ui.viewmodel.KeyguardRootViewModel import com.android.systemui.keyguard.ui.viewmodel.OccludingAppDeviceEntryMessageViewModel @@ -40,29 +48,38 @@ import com.android.systemui.lifecycle.repeatWhenAttached import com.android.systemui.plugins.ClockController import com.android.systemui.res.R import com.android.systemui.shade.domain.interactor.ShadeInteractor +import com.android.systemui.statusbar.CrossFadeHelper import com.android.systemui.statusbar.VibratorHelper -import com.android.systemui.statusbar.policy.KeyguardStateController +import com.android.systemui.statusbar.notification.shared.NotificationIconContainerRefactor +import com.android.systemui.statusbar.phone.ScreenOffAnimationController import com.android.systemui.temporarydisplay.ViewPriority import com.android.systemui.temporarydisplay.chipbar.ChipbarCoordinator import com.android.systemui.temporarydisplay.chipbar.ChipbarInfo +import com.android.systemui.util.ui.AnimatedValue +import com.android.systemui.util.ui.isAnimating +import com.android.systemui.util.ui.stopAnimating +import com.android.systemui.util.ui.value import javax.inject.Provider import kotlinx.coroutines.DisposableHandle import kotlinx.coroutines.ExperimentalCoroutinesApi +import kotlinx.coroutines.flow.Flow import kotlinx.coroutines.flow.filter +import kotlinx.coroutines.flow.stateIn import kotlinx.coroutines.launch /** Bind occludingAppDeviceEntryMessageViewModel to run whenever the keyguard view is attached. */ -@ExperimentalCoroutinesApi +@OptIn(ExperimentalCoroutinesApi::class) object KeyguardRootViewBinder { @JvmStatic fun bind( view: ViewGroup, viewModel: KeyguardRootViewModel, - featureFlags: FeatureFlags, + configuration: ConfigurationState, + featureFlags: FeatureFlagsClassic, occludingAppDeviceEntryMessageViewModel: OccludingAppDeviceEntryMessageViewModel, chipbarCoordinator: ChipbarCoordinator, - keyguardStateController: KeyguardStateController, + screenOffAnimationController: ScreenOffAnimationController, shadeInteractor: ShadeInteractor, clockControllerProvider: Provider<ClockController>?, interactionJankMonitor: InteractionJankMonitor?, @@ -147,6 +164,24 @@ object KeyguardRootViewBinder { } } + if (NotificationIconContainerRefactor.isEnabled) { + launch { + val iconsAppearTranslationPx = + configuration + .getDimensionPixelSize(R.dimen.shelf_appear_translation) + .stateIn(this) + viewModel.isNotifIconContainerVisible.collect { isVisible -> + childViews[aodNotificationIconContainerId] + ?.setAodNotifIconContainerIsVisible( + isVisible, + featureFlags, + iconsAppearTranslationPx.value, + screenOffAnimationController, + ) + } + } + } + interactionJankMonitor?.let { jankMonitor -> launch { viewModel.goneToAodTransition.collect { @@ -242,11 +277,18 @@ object KeyguardRootViewBinder { } ) + view.setOnApplyWindowInsetsListener { v: View, insets: WindowInsets -> + val insetTypes = WindowInsets.Type.systemBars() or WindowInsets.Type.displayCutout() + viewModel.topInset = insets.getInsetsIgnoringVisibility(insetTypes).top + insets + } + return object : DisposableHandle { override fun dispose() { disposableHandle.dispose() view.removeOnLayoutChangeListener(onLayoutChangeListener) view.setOnHierarchyChangeListener(null) + view.setOnApplyWindowInsetsListener(null) childViews.clear() } } @@ -288,7 +330,6 @@ object KeyguardRootViewBinder { oldBottom: Int ) { val nsslPlaceholder = v.findViewById(R.id.nssl_placeholder) as View? - if (nsslPlaceholder != null) { // After layout, ensure the notifications are positioned correctly viewModel.onSharedNotificationContainerPositionChanged( @@ -296,8 +337,132 @@ object KeyguardRootViewBinder { nsslPlaceholder.bottom.toFloat(), ) } + + val ksv = v.findViewById(R.id.keyguard_status_view) as View? + if (ksv != null) { + viewModel.statusViewTop = ksv.top + } + } + } + + @JvmStatic + fun bindAodIconVisibility( + view: View, + isVisible: Flow<AnimatedValue<Boolean>>, + configuration: ConfigurationState, + featureFlags: FeatureFlagsClassic, + screenOffAnimationController: ScreenOffAnimationController, + ): DisposableHandle? { + RefactorFlag(featureFlags, Flags.MIGRATE_KEYGUARD_STATUS_VIEW).assertInLegacyMode() + if (NotificationIconContainerRefactor.isUnexpectedlyInLegacyMode()) return null + return view.repeatWhenAttached { + lifecycleScope.launch { + val iconAppearTranslationPx = + configuration + .getDimensionPixelSize(R.dimen.shelf_appear_translation) + .stateIn(this) + isVisible.collect { isVisible -> + view.setAodNotifIconContainerIsVisible( + isVisible, + featureFlags, + iconAppearTranslationPx.value, + screenOffAnimationController, + ) + } + } } } + private fun View.setAodNotifIconContainerIsVisible( + isVisible: AnimatedValue<Boolean>, + featureFlags: FeatureFlagsClassic, + iconsAppearTranslationPx: Int, + screenOffAnimationController: ScreenOffAnimationController, + ) { + val statusViewMigrated = featureFlags.isEnabled(Flags.MIGRATE_KEYGUARD_STATUS_VIEW) + animate().cancel() + val animatorListener = + object : AnimatorListenerAdapter() { + override fun onAnimationEnd(animation: Animator) { + isVisible.stopAnimating() + } + } + when { + !isVisible.isAnimating -> { + alpha = 1f + if (!statusViewMigrated) { + translationY = 0f + } + visibility = if (isVisible.value) View.VISIBLE else View.INVISIBLE + } + featureFlags.isEnabled(Flags.NEW_AOD_TRANSITION) -> { + animateInIconTranslation(statusViewMigrated) + if (isVisible.value) { + CrossFadeHelper.fadeIn(this, animatorListener) + } else { + CrossFadeHelper.fadeOut(this, animatorListener) + } + } + !isVisible.value -> { + // Let's make sure the icon are translated to 0, since we cancelled it above + animateInIconTranslation(statusViewMigrated) + CrossFadeHelper.fadeOut(this, animatorListener) + } + visibility != View.VISIBLE -> { + // No fading here, let's just appear the icons instead! + visibility = View.VISIBLE + alpha = 1f + appearIcons( + animate = screenOffAnimationController.shouldAnimateAodIcons(), + iconsAppearTranslationPx, + statusViewMigrated, + animatorListener, + ) + } + else -> { + // Let's make sure the icons are translated to 0, since we cancelled it above + animateInIconTranslation(statusViewMigrated) + // We were fading out, let's fade in instead + CrossFadeHelper.fadeIn(this, animatorListener) + } + } + } + + private fun View.appearIcons( + animate: Boolean, + iconAppearTranslation: Int, + statusViewMigrated: Boolean, + animatorListener: Animator.AnimatorListener, + ) { + if (animate) { + if (!statusViewMigrated) { + translationY = -iconAppearTranslation.toFloat() + } + alpha = 0f + animate() + .alpha(1f) + .setInterpolator(Interpolators.LINEAR) + .setDuration(AOD_ICONS_APPEAR_DURATION) + .apply { if (statusViewMigrated) animateInIconTranslation() } + .setListener(animatorListener) + .start() + } else { + alpha = 1.0f + if (!statusViewMigrated) { + translationY = 0f + } + } + } + + private fun View.animateInIconTranslation(statusViewMigrated: Boolean) { + if (!statusViewMigrated) { + animate().animateInIconTranslation().setDuration(AOD_ICONS_APPEAR_DURATION).start() + } + } + + private fun ViewPropertyAnimator.animateInIconTranslation(): ViewPropertyAnimator = + setInterpolator(Interpolators.DECELERATE_QUINT).translationY(0f) + private const val ID = "occluding_app_device_entry_unlock_msg" + private const val AOD_ICONS_APPEAR_DURATION: Long = 200 } diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/ui/preview/KeyguardPreviewRenderer.kt b/packages/SystemUI/src/com/android/systemui/keyguard/ui/preview/KeyguardPreviewRenderer.kt index fe6a21ed89a0..b797c4b45445 100644 --- a/packages/SystemUI/src/com/android/systemui/keyguard/ui/preview/KeyguardPreviewRenderer.kt +++ b/packages/SystemUI/src/com/android/systemui/keyguard/ui/preview/KeyguardPreviewRenderer.kt @@ -44,10 +44,10 @@ import com.android.keyguard.KeyguardClockSwitch import com.android.systemui.animation.view.LaunchableImageView import com.android.systemui.biometrics.domain.interactor.UdfpsOverlayInteractor import com.android.systemui.broadcast.BroadcastDispatcher +import com.android.systemui.common.ui.ConfigurationState import com.android.systemui.dagger.qualifiers.Application import com.android.systemui.dagger.qualifiers.Main -import com.android.systemui.deviceentry.domain.interactor.DeviceEntryHapticsInteractor -import com.android.systemui.flags.FeatureFlags +import com.android.systemui.flags.FeatureFlagsClassic import com.android.systemui.flags.Flags import com.android.systemui.keyguard.ui.binder.KeyguardPreviewClockViewBinder import com.android.systemui.keyguard.ui.binder.KeyguardPreviewSmartspaceViewBinder @@ -76,7 +76,7 @@ import com.android.systemui.statusbar.KeyguardIndicationController import com.android.systemui.statusbar.VibratorHelper import com.android.systemui.statusbar.lockscreen.LockscreenSmartspaceController import com.android.systemui.statusbar.phone.KeyguardBottomAreaView -import com.android.systemui.statusbar.policy.KeyguardStateController +import com.android.systemui.statusbar.phone.ScreenOffAnimationController import com.android.systemui.temporarydisplay.chipbar.ChipbarCoordinator import dagger.assisted.Assisted import dagger.assisted.AssistedInject @@ -99,12 +99,13 @@ constructor( private val quickAffordancesCombinedViewModel: KeyguardQuickAffordancesCombinedViewModel, displayManager: DisplayManager, private val windowManager: WindowManager, + private val configuration: ConfigurationState, private val clockController: ClockEventController, private val clockRegistry: ClockRegistry, private val broadcastDispatcher: BroadcastDispatcher, private val lockscreenSmartspaceController: LockscreenSmartspaceController, private val udfpsOverlayInteractor: UdfpsOverlayInteractor, - private val featureFlags: FeatureFlags, + private val featureFlags: FeatureFlagsClassic, private val falsingManager: FalsingManager, private val vibratorHelper: VibratorHelper, private val indicationController: KeyguardIndicationController, @@ -113,9 +114,8 @@ constructor( private val keyguardBlueprintViewModel: KeyguardBlueprintViewModel, private val occludingAppDeviceEntryMessageViewModel: OccludingAppDeviceEntryMessageViewModel, private val chipbarCoordinator: ChipbarCoordinator, - private val keyguardStateController: KeyguardStateController, + private val screenOffAnimationController: ScreenOffAnimationController, private val shadeInteractor: ShadeInteractor, - private val deviceEntryHapticsInteractor: DeviceEntryHapticsInteractor, ) { val hostToken: IBinder? = bundle.getBinder(KEY_HOST_TOKEN) @@ -341,10 +341,11 @@ constructor( KeyguardRootViewBinder.bind( keyguardRootView, keyguardRootViewModel, + configuration, featureFlags, occludingAppDeviceEntryMessageViewModel, chipbarCoordinator, - keyguardStateController, + screenOffAnimationController, shadeInteractor, null, // clock provider only needed for burn in null, // jank monitor not required for preview mode diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/ui/view/layout/sections/AodNotificationIconsSection.kt b/packages/SystemUI/src/com/android/systemui/keyguard/ui/view/layout/sections/AodNotificationIconsSection.kt index b7fe9605a221..0390077a572f 100644 --- a/packages/SystemUI/src/com/android/systemui/keyguard/ui/view/layout/sections/AodNotificationIconsSection.kt +++ b/packages/SystemUI/src/com/android/systemui/keyguard/ui/view/layout/sections/AodNotificationIconsSection.kt @@ -31,7 +31,6 @@ import com.android.systemui.flags.FeatureFlagsClassic import com.android.systemui.flags.Flags import com.android.systemui.keyguard.shared.model.KeyguardSection import com.android.systemui.res.R -import com.android.systemui.shade.NotificationPanelView import com.android.systemui.statusbar.notification.icon.ui.viewbinder.AlwaysOnDisplayNotificationIconViewStore import com.android.systemui.statusbar.notification.icon.ui.viewbinder.NotificationIconContainerViewBinder import com.android.systemui.statusbar.notification.icon.ui.viewmodel.NotificationIconContainerAlwaysOnDisplayViewModel @@ -39,7 +38,6 @@ import com.android.systemui.statusbar.notification.shared.NotificationIconContai import com.android.systemui.statusbar.phone.DozeParameters import com.android.systemui.statusbar.phone.NotificationIconAreaController import com.android.systemui.statusbar.phone.NotificationIconContainer -import com.android.systemui.statusbar.phone.ScreenOffAnimationController import com.android.systemui.statusbar.policy.ConfigurationController import javax.inject.Inject import kotlinx.coroutines.DisposableHandle @@ -54,9 +52,7 @@ constructor( private val featureFlags: FeatureFlagsClassic, private val nicAodViewModel: NotificationIconContainerAlwaysOnDisplayViewModel, private val nicAodIconViewStore: AlwaysOnDisplayNotificationIconViewStore, - private val notificationPanelView: NotificationPanelView, private val notificationIconAreaController: NotificationIconAreaController, - private val screenOffAnimationController: ScreenOffAnimationController, ) : KeyguardSection() { private var nicBindingDisposable: DisposableHandle? = null @@ -97,8 +93,6 @@ constructor( configurationState, configurationController, dozeParameters, - featureFlags, - screenOffAnimationController, nicAodIconViewStore, ) } else { diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/KeyguardRootViewModel.kt b/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/KeyguardRootViewModel.kt index 1f98082c4065..60f75f03609c 100644 --- a/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/KeyguardRootViewModel.kt +++ b/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/KeyguardRootViewModel.kt @@ -22,14 +22,28 @@ import android.util.MathUtils import android.view.View.VISIBLE import com.android.app.animation.Interpolators import com.android.systemui.common.shared.model.SharedNotificationContainerPosition +import com.android.systemui.dagger.SysUISingleton +import com.android.systemui.deviceentry.domain.interactor.DeviceEntryInteractor +import com.android.systemui.flags.FeatureFlagsClassic +import com.android.systemui.flags.Flags import com.android.systemui.keyguard.domain.interactor.BurnInInteractor import com.android.systemui.keyguard.domain.interactor.KeyguardInteractor import com.android.systemui.keyguard.domain.interactor.KeyguardTransitionInteractor import com.android.systemui.keyguard.shared.model.BurnInModel +import com.android.systemui.keyguard.shared.model.KeyguardState import com.android.systemui.keyguard.shared.model.KeyguardState.AOD import com.android.systemui.keyguard.shared.model.KeyguardState.LOCKSCREEN import com.android.systemui.plugins.ClockController import com.android.systemui.res.R +import com.android.systemui.statusbar.notification.domain.interactor.NotificationsKeyguardInteractor +import com.android.systemui.statusbar.phone.DozeParameters +import com.android.systemui.statusbar.phone.ScreenOffAnimationController +import com.android.systemui.util.kotlin.pairwise +import com.android.systemui.util.kotlin.sample +import com.android.systemui.util.ui.AnimatableEvent +import com.android.systemui.util.ui.AnimatedValue +import com.android.systemui.util.ui.toAnimatedValueFlow +import com.android.systemui.util.ui.zip import javax.inject.Inject import javax.inject.Provider import kotlinx.coroutines.ExperimentalCoroutinesApi @@ -45,15 +59,21 @@ import kotlinx.coroutines.flow.merge import kotlinx.coroutines.flow.onStart @OptIn(ExperimentalCoroutinesApi::class) +@SysUISingleton class KeyguardRootViewModel @Inject constructor( private val context: Context, + private val deviceEntryInteractor: DeviceEntryInteractor, + private val dozeParameters: DozeParameters, + private val featureFlags: FeatureFlagsClassic, private val keyguardInteractor: KeyguardInteractor, + private val keyguardTransitionInteractor: KeyguardTransitionInteractor, + private val notificationsKeyguardInteractor: NotificationsKeyguardInteractor, private val burnInInteractor: BurnInInteractor, private val goneToAodTransitionViewModel: GoneToAodTransitionViewModel, private val aodToLockscreenTransitionViewModel: AodToLockscreenTransitionViewModel, - private val keyguardTransitionInteractor: KeyguardTransitionInteractor, + screenOffAnimationController: ScreenOffAnimationController, ) { data class PreviewMode(val isInPreviewMode: Boolean = false) @@ -65,7 +85,12 @@ constructor( */ private val previewMode = MutableStateFlow(PreviewMode()) - public var clockControllerProvider: Provider<ClockController>? = null + var clockControllerProvider: Provider<ClockController>? = null + + /** System insets that keyguard needs to stay out of */ + var topInset: Int = 0 + /** Status view top, without translation added in */ + var statusViewTop: Int = 0 val burnInLayerVisibility: Flow<Int> = keyguardTransitionInteractor.startedKeyguardState @@ -102,9 +127,12 @@ constructor( scale = MathUtils.lerp(burnIn.scale, 1f, 1f - interpolation), ) } else { + // Ensure the desired translation doesn't encroach on the top inset + val burnInY = MathUtils.lerp(0, burnIn.translationY, interpolation).toInt() + val translationY = -(statusViewTop - Math.max(topInset, statusViewTop + burnInY)) BurnInModel( translationX = MathUtils.lerp(0, burnIn.translationX, interpolation).toInt(), - translationY = MathUtils.lerp(0, burnIn.translationY, interpolation).toInt(), + translationY = translationY, scale = MathUtils.lerp(burnIn.scale, 1f, 1f - interpolation), scaleClockOnly = true, ) @@ -166,6 +194,47 @@ constructor( } } + /** Is the notification icon container visible? */ + val isNotifIconContainerVisible: Flow<AnimatedValue<Boolean>> = + combine( + keyguardTransitionInteractor.finishedKeyguardState.map { + KeyguardState.lockscreenVisibleInState(it) + }, + deviceEntryInteractor.isBypassEnabled, + areNotifsFullyHiddenAnimated(), + isPulseExpandingAnimated(), + ) { + onKeyguard: Boolean, + isBypassEnabled: Boolean, + notifsFullyHidden: AnimatedValue<Boolean>, + pulseExpanding: AnimatedValue<Boolean>, + -> + when { + // Hide the AOD icons if we're not in the KEYGUARD state unless the screen off + // animation is playing, in which case we want them to be visible if we're + // animating in the AOD UI and will be switching to KEYGUARD shortly. + !onKeyguard && !screenOffAnimationController.shouldShowAodIconsWhenShade() -> + AnimatedValue.NotAnimating(false) + else -> + zip(notifsFullyHidden, pulseExpanding) { + areNotifsFullyHidden, + isPulseExpanding, + -> + when { + // If we're bypassing, then we're visible + isBypassEnabled -> true + // If we are pulsing (and not bypassing), then we are hidden + isPulseExpanding -> false + // If notifs are fully gone, then we're visible + areNotifsFullyHidden -> true + // Otherwise, we're hidden + else -> false + } + } + } + } + .distinctUntilChanged() + /** * Puts this view-model in "preview mode", which means it's being used for UI that is rendering * the lock screen preview in wallpaper picker / settings and not the real experience on the @@ -183,4 +252,39 @@ constructor( keyguardInteractor.sharedNotificationContainerPosition.value = SharedNotificationContainerPosition(top, bottom) } + + /** Is there an expanded pulse, are we animating in response? */ + private fun isPulseExpandingAnimated(): Flow<AnimatedValue<Boolean>> { + return notificationsKeyguardInteractor.isPulseExpanding + .pairwise(initialValue = null) + // If pulsing changes, start animating, unless it's the first emission + .map { (prev, expanding) -> AnimatableEvent(expanding, startAnimating = prev != null) } + .toAnimatedValueFlow() + } + + /** Are notifications completely hidden from view, are we animating in response? */ + private fun areNotifsFullyHiddenAnimated(): Flow<AnimatedValue<Boolean>> { + return notificationsKeyguardInteractor.areNotificationsFullyHidden + .pairwise(initialValue = null) + .sample(deviceEntryInteractor.isBypassEnabled) { (prev, fullyHidden), bypassEnabled -> + val animate = + when { + // Don't animate for the first value + prev == null -> false + // Always animate if bypass is enabled. + bypassEnabled -> true + // If we're not bypassing and we're not going to AOD, then we're not + // animating. + !dozeParameters.alwaysOn -> false + // Don't animate when going to AOD if the display needs blanking. + dozeParameters.displayNeedsBlanking -> false + // We only want the appear animations to happen when the notifications + // get fully hidden, since otherwise the un-hide animation overlaps. + featureFlags.isEnabled(Flags.NEW_AOD_TRANSITION) -> true + else -> fullyHidden + } + AnimatableEvent(fullyHidden, animate) + } + .toAnimatedValueFlow() + } } diff --git a/packages/SystemUI/src/com/android/systemui/log/SideFpsLogger.kt b/packages/SystemUI/src/com/android/systemui/log/SideFpsLogger.kt new file mode 100644 index 000000000000..74923eec4891 --- /dev/null +++ b/packages/SystemUI/src/com/android/systemui/log/SideFpsLogger.kt @@ -0,0 +1,132 @@ +/* + * Copyright (C) 2023 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.systemui.log + +import android.graphics.Point +import android.graphics.Rect +import com.android.systemui.biometrics.shared.model.DisplayRotation +import com.android.systemui.dagger.SysUISingleton +import com.android.systemui.log.core.LogLevel +import com.android.systemui.log.dagger.BouncerLog +import javax.inject.Inject + +private const val TAG = "SideFpsLogger" + +/** + * Helper class for logging for SFPS related functionality + * + * To enable logcat echoing for an entire buffer: + * ``` + * adb shell settings put global systemui/buffer/BouncerLog <logLevel> + * + * ``` + */ +@SysUISingleton +class SideFpsLogger @Inject constructor(@BouncerLog private val buffer: LogBuffer) { + fun sfpsProgressBarStateChanged( + visible: Boolean, + location: Point, + shouldRotate: Boolean, + fpDetectRunning: Boolean, + sensorWidth: Int + ) { + buffer.log( + TAG, + LogLevel.DEBUG, + { + bool1 = visible + int1 = location.x + int2 = location.y + bool2 = shouldRotate + bool3 = fpDetectRunning + long1 = sensorWidth.toLong() + }, + { + "SFPS progress bar state changed: visible: $bool1, " + + "sensorLocation (x, y): ($int1, $int2), " + + "shouldRotate = $bool2, " + + "fpDetectRunning: $bool3, " + + "sensorWidth: $long1" + } + ) + } + + fun hidingSfpsIndicator() { + buffer.log(TAG, LogLevel.DEBUG, "hiding SFPS indicator to show progress bar") + } + + fun showingSfpsIndicator() { + buffer.log( + TAG, + LogLevel.DEBUG, + "Requesting show SFPS indicator because progress bar " + + "is being hidden and FP detect is currently running" + ) + } + + fun isProlongedTouchRequiredForAuthenticationChanged(enabled: Boolean) { + buffer.log( + TAG, + LogLevel.DEBUG, + { bool1 = enabled }, + { "isProlongedTouchRequiredForAuthentication: $bool1" } + ) + } + + fun logStateChange(sfpsAvailable: Boolean, settingEnabled: Boolean) { + buffer.log( + TAG, + LogLevel.DEBUG, + { + bool1 = sfpsAvailable + bool2 = settingEnabled + }, + { "SFPS rest to unlock state changed: sfpsAvailable: $bool1, settingEnabled: $bool2" } + ) + } + + fun sensorLocationStateChanged( + windowSize: Rect?, + rotation: DisplayRotation, + displayWidth: Int, + displayHeight: Int, + sensorWidth: Int, + sensorVerticalInDefaultOrientation: Boolean + ) { + buffer.log( + TAG, + LogLevel.DEBUG, + { + str1 = "$windowSize" + str2 = rotation.name + int1 = displayWidth + int2 = displayHeight + long1 = sensorWidth.toLong() + bool1 = sensorVerticalInDefaultOrientation + }, + { + "sensorLocation state changed: " + + "windowSize: $str1, " + + "rotation: $str2, " + + "widthInRotation0: $int1, " + + "heightInRotation0: $int2, " + + "sensorWidth: $long1, " + + "sensorVerticalInDefaultOrientation: $bool1" + } + ) + } +} diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/InternetTileNewImpl.kt b/packages/SystemUI/src/com/android/systemui/qs/tiles/InternetTileNewImpl.kt index 8103152dda37..13271c32c52f 100644 --- a/packages/SystemUI/src/com/android/systemui/qs/tiles/InternetTileNewImpl.kt +++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/InternetTileNewImpl.kt @@ -21,8 +21,8 @@ import android.os.Handler import android.os.Looper import android.provider.Settings import android.view.View +import android.widget.Switch import com.android.internal.logging.MetricsLogger -import com.android.systemui.res.R import com.android.systemui.dagger.qualifiers.Background import com.android.systemui.dagger.qualifiers.Main import com.android.systemui.plugins.ActivityStarter @@ -34,6 +34,7 @@ import com.android.systemui.qs.QsEventLogger import com.android.systemui.qs.logging.QSLogger import com.android.systemui.qs.tileimpl.QSTileImpl import com.android.systemui.qs.tiles.dialog.InternetDialogFactory +import com.android.systemui.res.R import com.android.systemui.statusbar.connectivity.AccessPointController import com.android.systemui.statusbar.pipeline.shared.ui.binder.InternetTileBinder import com.android.systemui.statusbar.pipeline.shared.ui.model.InternetTileModel @@ -96,6 +97,7 @@ constructor( override fun handleUpdateState(state: QSTile.BooleanState, arg: Any?) { state.label = mContext.resources.getString(R.string.quick_settings_internet_label) + state.expandedAccessibilityClassName = Switch::class.java.name model.applyTo(state, mContext) } diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/impl/custom/data/entity/CustomTileDefaults.kt b/packages/SystemUI/src/com/android/systemui/qs/tiles/impl/custom/data/entity/CustomTileDefaults.kt new file mode 100644 index 000000000000..dfeb65b7c5aa --- /dev/null +++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/impl/custom/data/entity/CustomTileDefaults.kt @@ -0,0 +1,28 @@ +/* + * Copyright (C) 2023 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.systemui.qs.tiles.impl.custom.data.entity + +import android.graphics.drawable.Icon + +sealed interface CustomTileDefaults { + + data object Error : CustomTileDefaults + data class Result( + val icon: Icon, + val label: CharSequence, + ) : CustomTileDefaults +} diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/impl/custom/data/repository/CustomTileDefaultsRepository.kt b/packages/SystemUI/src/com/android/systemui/qs/tiles/impl/custom/data/repository/CustomTileDefaultsRepository.kt new file mode 100644 index 000000000000..1546ec2c54bd --- /dev/null +++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/impl/custom/data/repository/CustomTileDefaultsRepository.kt @@ -0,0 +1,153 @@ +/* + * Copyright (C) 2023 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.systemui.qs.tiles.impl.custom.data.repository + +import android.content.ComponentName +import android.content.Context +import android.content.pm.PackageManager +import android.content.pm.ServiceInfo +import android.graphics.drawable.Icon +import android.os.UserHandle +import com.android.systemui.dagger.qualifiers.Application +import com.android.systemui.dagger.qualifiers.Background +import com.android.systemui.qs.tiles.impl.custom.data.entity.CustomTileDefaults +import com.android.systemui.qs.tiles.impl.di.QSTileScope +import javax.inject.Inject +import kotlinx.coroutines.CoroutineDispatcher +import kotlinx.coroutines.CoroutineScope +import kotlinx.coroutines.channels.BufferOverflow +import kotlinx.coroutines.flow.Flow +import kotlinx.coroutines.flow.MutableSharedFlow +import kotlinx.coroutines.flow.SharedFlow +import kotlinx.coroutines.flow.SharingStarted +import kotlinx.coroutines.flow.distinctUntilChanged +import kotlinx.coroutines.flow.filter +import kotlinx.coroutines.flow.map +import kotlinx.coroutines.flow.shareIn +import kotlinx.coroutines.withContext + +/** Gets a label and an icon for a custom tile based on its package. */ +interface CustomTileDefaultsRepository { + + /** + * Returns [CustomTileDefaults] for a specified [user]. An updated value may be emitted as a + * response for [requestNewDefaults]. + * + * @see requestNewDefaults + */ + fun defaults(user: UserHandle): Flow<CustomTileDefaults> + + /** + * Requests the new default from the [PackageManager]. The result is cached until the input of + * this method changes or [force] == true is passed. + * + * Listen to [defaults] to get the loaded result + */ + fun requestNewDefaults( + user: UserHandle, + componentName: ComponentName, + force: Boolean = false, + ) +} + +@QSTileScope +class CustomTileDefaultsRepositoryImpl +@Inject +constructor( + private val context: Context, + @Application applicationScope: CoroutineScope, + @Background private val backgroundDispatcher: CoroutineDispatcher, +) : CustomTileDefaultsRepository { + + private val defaultsRequests = + MutableSharedFlow<DefaultsRequest>( + replay = 1, + onBufferOverflow = BufferOverflow.DROP_OLDEST + ) + + private val defaults: SharedFlow<DefaultsResult> = + defaultsRequests + .distinctUntilChanged { old, new -> + if (new.force) { + // force update should always pass + false + } else { + old == new + } + } + .map { DefaultsResult(it.user, loadDefaults(it.user, it.componentName)) } + .shareIn(applicationScope, SharingStarted.WhileSubscribed(), replay = 1) + + override fun defaults(user: UserHandle): Flow<CustomTileDefaults> = + defaults.filter { it.user == user }.map { it.data } + + override fun requestNewDefaults( + user: UserHandle, + componentName: ComponentName, + force: Boolean, + ) { + defaultsRequests.tryEmit(DefaultsRequest(user, componentName, force)) + } + + private suspend fun loadDefaults( + user: UserHandle, + componentName: ComponentName + ): CustomTileDefaults = + withContext(backgroundDispatcher) { + try { + val userContext = context.createContextAsUser(user, 0) + val info = componentName.getServiceInfo(userContext.packageManager) + + val iconRes = if (info.icon == NO_ICON_RES) info.applicationInfo.icon else info.icon + if (iconRes == NO_ICON_RES) { + return@withContext CustomTileDefaults.Error + } + + CustomTileDefaults.Result( + Icon.createWithResource(componentName.packageName, iconRes), + info.loadLabel(userContext.packageManager) + ) + } catch (e: PackageManager.NameNotFoundException) { + CustomTileDefaults.Error + } + } + + private fun ComponentName.getServiceInfo( + packageManager: PackageManager, + ): ServiceInfo { + val isSystemApp = packageManager.getApplicationInfo(packageName, 0).isSystemApp + var flags = + (PackageManager.MATCH_DIRECT_BOOT_UNAWARE or PackageManager.MATCH_DIRECT_BOOT_AWARE) + if (isSystemApp) { + flags = flags or PackageManager.MATCH_DISABLED_COMPONENTS + } + return packageManager.getServiceInfo(this, flags) + } + + private data class DefaultsRequest( + val user: UserHandle, + val componentName: ComponentName, + val force: Boolean = false, + ) + + private data class DefaultsResult(val user: UserHandle, val data: CustomTileDefaults) + + private companion object { + + const val NO_ICON_RES = 0 + } +} diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/impl/custom/di/CustomTileModule.kt b/packages/SystemUI/src/com/android/systemui/qs/tiles/impl/custom/di/CustomTileModule.kt index ccff8afe7628..482bf9bcd051 100644 --- a/packages/SystemUI/src/com/android/systemui/qs/tiles/impl/custom/di/CustomTileModule.kt +++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/impl/custom/di/CustomTileModule.kt @@ -23,6 +23,8 @@ import com.android.systemui.qs.tiles.impl.custom.CustomTileData import com.android.systemui.qs.tiles.impl.custom.CustomTileInteractor import com.android.systemui.qs.tiles.impl.custom.CustomTileMapper import com.android.systemui.qs.tiles.impl.custom.CustomTileUserActionInteractor +import com.android.systemui.qs.tiles.impl.custom.data.repository.CustomTileDefaultsRepository +import com.android.systemui.qs.tiles.impl.custom.data.repository.CustomTileDefaultsRepositoryImpl import com.android.systemui.qs.tiles.impl.custom.di.bound.CustomTileBoundComponent import dagger.Binds import dagger.Module @@ -43,4 +45,9 @@ interface CustomTileModule { @Binds fun bindMapper(customTileMapper: CustomTileMapper): QSTileDataToStateMapper<CustomTileData> + + @Binds + fun bindCustomTileDefaultsRepository( + impl: CustomTileDefaultsRepositoryImpl + ): CustomTileDefaultsRepository } diff --git a/packages/SystemUI/src/com/android/systemui/shade/NotificationPanelViewController.java b/packages/SystemUI/src/com/android/systemui/shade/NotificationPanelViewController.java index cc59f8750b56..dfe6adc49f9a 100644 --- a/packages/SystemUI/src/com/android/systemui/shade/NotificationPanelViewController.java +++ b/packages/SystemUI/src/com/android/systemui/shade/NotificationPanelViewController.java @@ -1070,7 +1070,6 @@ public final class NotificationPanelViewController implements ShadeSurface, Dump mNotificationStackScrollLayoutController.setOnEmptySpaceClickListener( mOnEmptySpaceClickListener); mQsController.init(); - mShadeExpansionStateManager.addQsExpansionListener(this::onQsExpansionChanged); mShadeHeadsUpTracker.addTrackingHeadsUpListener( mNotificationStackScrollLayoutController::setTrackingHeadsUp); if (!mFeatureFlags.isEnabled(Flags.MIGRATE_SPLIT_KEYGUARD_BOTTOM_AREA)) { @@ -4219,7 +4218,7 @@ public final class NotificationPanelViewController implements ShadeSurface, Dump return mShadeExpansionStateManager; } - private void onQsExpansionChanged(boolean expanded) { + void onQsExpansionChanged(boolean expanded) { updateExpandedHeightToMaxHeight(); setStatusAccessibilityImportance(expanded ? View.IMPORTANT_FOR_ACCESSIBILITY_NO_HIDE_DESCENDANTS diff --git a/packages/SystemUI/src/com/android/systemui/shade/NotificationShadeWindowControllerImpl.java b/packages/SystemUI/src/com/android/systemui/shade/NotificationShadeWindowControllerImpl.java index 04263882d3a8..51148263b6ac 100644 --- a/packages/SystemUI/src/com/android/systemui/shade/NotificationShadeWindowControllerImpl.java +++ b/packages/SystemUI/src/com/android/systemui/shade/NotificationShadeWindowControllerImpl.java @@ -156,7 +156,6 @@ public class NotificationShadeWindowControllerImpl implements NotificationShadeW KeyguardStateController keyguardStateController, ScreenOffAnimationController screenOffAnimationController, AuthController authController, - ShadeExpansionStateManager shadeExpansionStateManager, Lazy<ShadeInteractor> shadeInteractorLazy, ShadeWindowLogger logger, Lazy<SelectedUserInteractor> userInteractor) { @@ -185,7 +184,6 @@ public class NotificationShadeWindowControllerImpl implements NotificationShadeW .addCallback(mStateListener, SysuiStatusBarStateController.RANK_STATUS_BAR_WINDOW_CONTROLLER); configurationController.addCallback(this); - shadeExpansionStateManager.addQsExpansionListener(this::onQsExpansionChanged); float desiredPreferredRefreshRate = context.getResources() .getInteger(R.integer.config_keyguardRefreshRate); @@ -303,6 +301,11 @@ public class NotificationShadeWindowControllerImpl implements NotificationShadeW mShadeInteractorLazy.get().isAnyExpanded(), this::onShadeOrQsExpanded ); + collectFlow( + mWindowRootView, + mShadeInteractorLazy.get().isQsExpanded(), + this::onQsExpansionChanged + ); } @Override diff --git a/packages/SystemUI/src/com/android/systemui/shade/NotificationsQSContainerController.kt b/packages/SystemUI/src/com/android/systemui/shade/NotificationsQSContainerController.kt index cc46b23ec75f..866cfb443b0a 100644 --- a/packages/SystemUI/src/com/android/systemui/shade/NotificationsQSContainerController.kt +++ b/packages/SystemUI/src/com/android/systemui/shade/NotificationsQSContainerController.kt @@ -26,23 +26,27 @@ import androidx.constraintlayout.widget.ConstraintSet.END import androidx.constraintlayout.widget.ConstraintSet.PARENT_ID import androidx.constraintlayout.widget.ConstraintSet.START import androidx.constraintlayout.widget.ConstraintSet.TOP -import com.android.systemui.res.R +import androidx.lifecycle.lifecycleScope import com.android.systemui.dagger.SysUISingleton import com.android.systemui.dagger.qualifiers.Main import com.android.systemui.flags.FeatureFlags import com.android.systemui.flags.Flags import com.android.systemui.fragments.FragmentService +import com.android.systemui.lifecycle.repeatWhenAttached import com.android.systemui.navigationbar.NavigationModeController import com.android.systemui.plugins.qs.QS import com.android.systemui.plugins.qs.QSContainerController import com.android.systemui.recents.OverviewProxyService import com.android.systemui.recents.OverviewProxyService.OverviewProxyListener +import com.android.systemui.res.R +import com.android.systemui.shade.domain.interactor.ShadeInteractor import com.android.systemui.shared.system.QuickStepContract import com.android.systemui.statusbar.notification.stack.NotificationStackScrollLayoutController import com.android.systemui.statusbar.policy.SplitShadeStateController import com.android.systemui.util.LargeScreenUtils import com.android.systemui.util.ViewController import com.android.systemui.util.concurrency.DelayableExecutor +import kotlinx.coroutines.launch import java.util.function.Consumer import javax.inject.Inject import kotlin.reflect.KMutableProperty0 @@ -56,7 +60,7 @@ class NotificationsQSContainerController @Inject constructor( private val navigationModeController: NavigationModeController, private val overviewProxyService: OverviewProxyService, private val shadeHeaderController: ShadeHeaderController, - private val shadeExpansionStateManager: ShadeExpansionStateManager, + private val shadeInteractor: ShadeInteractor, private val fragmentService: FragmentService, @Main private val delayableExecutor: DelayableExecutor, private val featureFlags: FeatureFlags, @@ -65,7 +69,6 @@ class NotificationsQSContainerController @Inject constructor( private val splitShadeStateController: SplitShadeStateController ) : ViewController<NotificationsQuickSettingsContainer>(view), QSContainerController { - private var qsExpanded = false private var splitShadeEnabled = false private var isQSDetailShowing = false private var isQSCustomizing = false @@ -89,13 +92,6 @@ class NotificationsQSContainerController @Inject constructor( taskbarVisible = visible } } - private val shadeQsExpansionListener: ShadeQsExpansionListener = - ShadeQsExpansionListener { isQsExpanded -> - if (qsExpanded != isQsExpanded) { - qsExpanded = isQsExpanded - mView.invalidate() - } - } // With certain configuration changes (like light/dark changes), the nav bar will disappear // for a bit, causing `bottomStableInsets` to be unstable for some time. Debounce the value @@ -122,6 +118,11 @@ class NotificationsQSContainerController @Inject constructor( } override fun onInit() { + mView.repeatWhenAttached { + lifecycleScope.launch { + shadeInteractor.isQsExpanded.collect{ _ -> mView.invalidate() } + } + } val currentMode: Int = navigationModeController.addListener { mode: Int -> isGestureNavigation = QuickStepContract.isGesturalMode(mode) } @@ -137,7 +138,6 @@ class NotificationsQSContainerController @Inject constructor( public override fun onViewAttached() { updateResources() overviewProxyService.addCallback(taskbarVisibilityListener) - shadeExpansionStateManager.addQsExpansionListener(shadeQsExpansionListener) mView.setInsetsChangedListener(delayedInsetSetter) mView.setQSFragmentAttachedListener { qs: QS -> qs.setContainerController(this) } mView.setConfigurationChangedListener { updateResources() } @@ -146,7 +146,6 @@ class NotificationsQSContainerController @Inject constructor( override fun onViewDetached() { overviewProxyService.removeCallback(taskbarVisibilityListener) - shadeExpansionStateManager.removeQsExpansionListener(shadeQsExpansionListener) mView.removeOnInsetsChangedListener() mView.removeQSFragmentAttachedListener() mView.setConfigurationChangedListener(null) diff --git a/packages/SystemUI/src/com/android/systemui/shade/QuickSettingsController.java b/packages/SystemUI/src/com/android/systemui/shade/QuickSettingsController.java index 0ec7a36b5a6d..d73fa1460bd4 100644 --- a/packages/SystemUI/src/com/android/systemui/shade/QuickSettingsController.java +++ b/packages/SystemUI/src/com/android/systemui/shade/QuickSettingsController.java @@ -207,12 +207,6 @@ public class QuickSettingsController implements Dumpable { /** pointerId of the pointer we're currently tracking */ private int mTrackingPointer; - /** - * Indicates that QS is in expanded state which can happen by: - * - single pane shade: expanding shade and then expanding QS - * - split shade: just expanding shade (QS are expanded automatically) - */ - private boolean mExpanded; /** Indicates QS is at its max height */ private boolean mFullyExpanded; /** @@ -594,9 +588,8 @@ public class QuickSettingsController implements Dumpable { return twoFingerDrag || stylusButtonClickDrag || mouseButtonClickDrag; } - public boolean getExpanded() { - return mExpanded; + return mShadeRepository.getLegacyIsQsExpanded().getValue(); } @VisibleForTesting @@ -613,7 +606,7 @@ public class QuickSettingsController implements Dumpable { // close the whole shade with one motion. Also this will be always true when closing // split shade as there QS are always expanded so every collapsing motion is motion from // expanded QS to closed panel - return mExpandImmediate || (mExpanded + return mExpandImmediate || (getExpanded() && !isTracking() && !isExpansionAnimating() && !mExpansionFromOverscroll); } @@ -778,11 +771,11 @@ public class QuickSettingsController implements Dumpable { @VisibleForTesting void setExpanded(boolean expanded) { - boolean changed = mExpanded != expanded; + boolean changed = getExpanded() != expanded; if (changed) { - mExpanded = expanded; + mShadeRepository.setLegacyIsQsExpanded(expanded); updateQsState(); - mShadeExpansionStateManager.onQsExpansionChanged(expanded); + mPanelViewControllerLazy.get().onQsExpansionChanged(expanded); mShadeLog.logQsExpansionChanged("QS Expansion Changed.", expanded, getMinExpansionHeight(), getMaxExpansionHeight(), mStackScrollerOverscrolling, mAnimatorExpand, mAnimating); @@ -846,7 +839,7 @@ public class QuickSettingsController implements Dumpable { /** Called when Shade view layout changed. Updates QS expansion or * starts size change animation if height has changed. */ void handleShadeLayoutChanged(int oldMaxHeight) { - if (mExpanded && mFullyExpanded) { + if (getExpanded() && mFullyExpanded) { mExpansionHeight = mMaxExpansionHeight; if (mExpansionHeightSetToMaxListener != null) { mExpansionHeightSetToMaxListener.onExpansionHeightSetToMax(true); @@ -988,24 +981,24 @@ public class QuickSettingsController implements Dumpable { } void updateQsState() { - boolean qsFullScreen = mExpanded && !mSplitShadeEnabled; + boolean qsFullScreen = getExpanded() && !mSplitShadeEnabled; mNotificationStackScrollLayoutController.setQsFullScreen(qsFullScreen); mNotificationStackScrollLayoutController.setScrollingEnabled( mBarState != KEYGUARD && (!qsFullScreen || mExpansionFromOverscroll)); if (mQsStateUpdateListener != null) { - mQsStateUpdateListener.onQsStateUpdated(mExpanded, mStackScrollerOverscrolling); + mQsStateUpdateListener.onQsStateUpdated(getExpanded(), mStackScrollerOverscrolling); } if (mQs == null) return; - mQs.setExpanded(mExpanded); + mQs.setExpanded(getExpanded()); } /** update expanded state of QS */ public void updateExpansion() { if (mQs == null) return; final float squishiness; - if ((mExpandImmediate || mExpanded) && !mSplitShadeEnabled) { + if ((mExpandImmediate || getExpanded()) && !mSplitShadeEnabled) { squishiness = 1; } else if (mTransitioningToFullShadeProgress > 0.0f) { squishiness = mLockscreenShadeTransitionController.getQsSquishTransitionFraction(); @@ -1125,7 +1118,7 @@ public class QuickSettingsController implements Dumpable { mMediaHierarchyManager.setCollapsingShadeFromQS(mExpandedWhenExpandingStarted /* We also start expanding when flinging closed Qs. Let's exclude that */ && !mAnimating); - if (mExpanded) { + if (getExpanded()) { onExpansionStarted(); } // Since there are QS tiles in the header now, we need to make sure we start listening @@ -1234,7 +1227,7 @@ public class QuickSettingsController implements Dumpable { Math.min(top / (float) mScrimCornerRadius, 1f)); float bottomRadius = mSplitShadeEnabled ? screenCornerRadius : 0; - if (!mExpanded) { + if (!getExpanded()) { bottomRadius = calculateBottomCornerRadius(bottomRadius); } mScrimController.setNotificationBottomRadius(bottomRadius); @@ -1547,7 +1540,7 @@ public class QuickSettingsController implements Dumpable { @VisibleForTesting void onHeightChanged() { mMaxExpansionHeight = isQsFragmentCreated() ? mQs.getDesiredHeight() : 0; - if (mExpanded && mFullyExpanded) { + if (getExpanded() && mFullyExpanded) { mExpansionHeight = mMaxExpansionHeight; if (mExpansionHeightSetToMaxListener != null) { mExpansionHeightSetToMaxListener.onExpansionHeightSetToMax(true); @@ -2083,7 +2076,7 @@ public class QuickSettingsController implements Dumpable { ipw.print("mTrackingPointer="); ipw.println(mTrackingPointer); ipw.print("mExpanded="); - ipw.println(mExpanded); + ipw.println(getExpanded()); ipw.print("mFullyExpanded="); ipw.println(mFullyExpanded); ipw.print("mExpandImmediate="); diff --git a/packages/SystemUI/src/com/android/systemui/shade/ShadeExpansionStateManager.kt b/packages/SystemUI/src/com/android/systemui/shade/ShadeExpansionStateManager.kt index 949398969d67..fca98f580702 100644 --- a/packages/SystemUI/src/com/android/systemui/shade/ShadeExpansionStateManager.kt +++ b/packages/SystemUI/src/com/android/systemui/shade/ShadeExpansionStateManager.kt @@ -36,15 +36,12 @@ import javax.inject.Inject class ShadeExpansionStateManager @Inject constructor() : ShadeStateEvents { private val expansionListeners = CopyOnWriteArrayList<ShadeExpansionListener>() - private val qsExpansionListeners = CopyOnWriteArrayList<ShadeQsExpansionListener>() private val stateListeners = CopyOnWriteArrayList<ShadeStateListener>() private val shadeStateEventsListeners = CopyOnWriteArrayList<ShadeStateEventsListener>() @PanelState private var state: Int = STATE_CLOSED @FloatRange(from = 0.0, to = 1.0) private var fraction: Float = 0f private var expanded: Boolean = false - private var qsExpanded: Boolean = false - private var qsExpansionFraction = 0f private var tracking: Boolean = false private var dragDownPxAmount: Float = 0f @@ -64,15 +61,6 @@ class ShadeExpansionStateManager @Inject constructor() : ShadeStateEvents { expansionListeners.remove(listener) } - fun addQsExpansionListener(listener: ShadeQsExpansionListener) { - qsExpansionListeners.add(listener) - listener.onQsExpansionChanged(qsExpanded) - } - - fun removeQsExpansionListener(listener: ShadeQsExpansionListener) { - qsExpansionListeners.remove(listener) - } - /** Adds a listener that will be notified when the panel state has changed. */ fun addStateListener(listener: ShadeStateListener) { stateListeners.add(listener) @@ -153,14 +141,6 @@ class ShadeExpansionStateManager @Inject constructor() : ShadeStateEvents { expansionListeners.forEach { it.onPanelExpansionChanged(expansionChangeEvent) } } - /** Called when the quick settings expansion changes to fully expanded or collapsed. */ - fun onQsExpansionChanged(qsExpanded: Boolean) { - this.qsExpanded = qsExpanded - - debugLog("qsExpanded=$qsExpanded") - qsExpansionListeners.forEach { it.onQsExpansionChanged(qsExpanded) } - } - /** Updates the panel state if necessary. */ fun updateState(@PanelState state: Int) { debugLog( diff --git a/packages/SystemUI/src/com/android/systemui/shade/data/repository/ShadeRepository.kt b/packages/SystemUI/src/com/android/systemui/shade/data/repository/ShadeRepository.kt index 024c8e32a441..e2e4556f59f7 100644 --- a/packages/SystemUI/src/com/android/systemui/shade/data/repository/ShadeRepository.kt +++ b/packages/SystemUI/src/com/android/systemui/shade/data/repository/ShadeRepository.kt @@ -83,6 +83,17 @@ interface ShadeRepository { val legacyExpandedOrAwaitingInputTransfer: StateFlow<Boolean> /** + * QuickSettingsController.mExpanded as a flow. Indicates that QS is in expanded state: + * - single pane shade: expanding shade and then expanding QS + * - split shade: just expanding shade (QS are expanded automatically) + */ + @Deprecated("Use ShadeInteractor instead") val legacyIsQsExpanded: StateFlow<Boolean> + + /** Sets whether QS is expanded. */ + @Deprecated("Use ShadeInteractor instead") + fun setLegacyIsQsExpanded(legacyIsQsExpanded: Boolean) + + /** * Sets whether the expansion fraction is greater than zero or NPVC is about to accept an input * transfer from the status bar, home screen, or trackpad. */ @@ -175,6 +186,15 @@ constructor(shadeExpansionStateManager: ShadeExpansionStateManager) : ShadeRepos override val legacyExpandedOrAwaitingInputTransfer: StateFlow<Boolean> = _legacyExpandedOrAwaitingInputTransfer.asStateFlow() + private val _legacyIsQsExpanded = MutableStateFlow(false) + @Deprecated("Use ShadeInteractor instead") + override val legacyIsQsExpanded: StateFlow<Boolean> = _legacyIsQsExpanded.asStateFlow() + + @Deprecated("Use ShadeInteractor instead") + override fun setLegacyIsQsExpanded(legacyIsQsExpanded: Boolean) { + _legacyIsQsExpanded.value = legacyIsQsExpanded + } + @Deprecated("Use ShadeInteractor instead") override fun setLegacyExpandedOrAwaitingInputTransfer( legacyExpandedOrAwaitingInputTransfer: Boolean diff --git a/packages/SystemUI/src/com/android/systemui/shade/domain/interactor/ShadeInteractor.kt b/packages/SystemUI/src/com/android/systemui/shade/domain/interactor/ShadeInteractor.kt index f043c717f923..a4c4503a6550 100644 --- a/packages/SystemUI/src/com/android/systemui/shade/domain/interactor/ShadeInteractor.kt +++ b/packages/SystemUI/src/com/android/systemui/shade/domain/interactor/ShadeInteractor.kt @@ -121,16 +121,37 @@ constructor( /** * The amount [0-1] QS has been opened. Normal shade with notifications (QQS) visible will - * report 0f. + * report 0f. If split shade is enabled, value matches shadeExpansion. */ val qsExpansion: StateFlow<Float> = if (sceneContainerFlags.isEnabled()) { - sceneBasedExpansion(sceneInteractorProvider.get(), SceneKey.QuickSettings) + val qsExp = sceneBasedExpansion(sceneInteractorProvider.get(), SceneKey.QuickSettings) + combine(isSplitShadeEnabled, shadeExpansion, qsExp) { + isSplitShadeEnabled, + shadeExp, + qsExp -> + if (isSplitShadeEnabled) { + shadeExp + } else { + qsExp + } + } .stateIn(scope, SharingStarted.Eagerly, 0f) } else { repository.qsExpansion } + /** Whether Quick Settings is expanded a non-zero amount. */ + val isQsExpanded: StateFlow<Boolean> = + if (sceneContainerFlags.isEnabled()) { + qsExpansion + .map { it > 0 } + .distinctUntilChanged() + .stateIn(scope, SharingStarted.Eagerly, false) + } else { + repository.legacyIsQsExpanded + } + /** The amount [0-1] either QS or the shade has been opened. */ val anyExpansion: StateFlow<Float> = combine(shadeExpansion, qsExpansion) { shadeExp, qsExp -> maxOf(shadeExp, qsExp) } diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/PulseExpansionHandler.kt b/packages/SystemUI/src/com/android/systemui/statusbar/PulseExpansionHandler.kt index 4ea70264b152..e19fcd05e9a4 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/PulseExpansionHandler.kt +++ b/packages/SystemUI/src/com/android/systemui/statusbar/PulseExpansionHandler.kt @@ -32,17 +32,15 @@ import com.android.app.animation.Interpolators import com.android.systemui.Dumpable import com.android.systemui.Gefingerpoken import com.android.systemui.classifier.Classifier.NOTIFICATION_DRAG_DOWN -import com.android.systemui.classifier.FalsingCollector import com.android.systemui.dagger.SysUISingleton import com.android.systemui.dump.DumpManager import com.android.systemui.plugins.FalsingManager import com.android.systemui.plugins.statusbar.StatusBarStateController import com.android.systemui.res.R -import com.android.systemui.shade.ShadeExpansionStateManager +import com.android.systemui.shade.domain.interactor.ShadeInteractor import com.android.systemui.statusbar.notification.NotificationWakeUpCoordinator import com.android.systemui.statusbar.notification.row.ExpandableNotificationRow import com.android.systemui.statusbar.notification.row.ExpandableView -import com.android.systemui.statusbar.notification.stack.NotificationRoundnessManager import com.android.systemui.statusbar.notification.stack.NotificationStackScrollLayoutController import com.android.systemui.statusbar.phone.KeyguardBypassController import com.android.systemui.statusbar.policy.ConfigurationController @@ -64,13 +62,11 @@ constructor( private val wakeUpCoordinator: NotificationWakeUpCoordinator, private val bypassController: KeyguardBypassController, private val headsUpManager: HeadsUpManager, - private val roundnessManager: NotificationRoundnessManager, configurationController: ConfigurationController, private val statusBarStateController: StatusBarStateController, private val falsingManager: FalsingManager, - shadeExpansionStateManager: ShadeExpansionStateManager, + private val shadeInteractor: ShadeInteractor, private val lockscreenShadeTransitionController: LockscreenShadeTransitionController, - private val falsingCollector: FalsingCollector, dumpManager: DumpManager ) : Gefingerpoken, Dumpable { companion object { @@ -115,7 +111,6 @@ constructor( private val isFalseTouch: Boolean get() = falsingManager.isFalseTouch(NOTIFICATION_DRAG_DOWN) - var qsExpanded: Boolean = false var pulseExpandAbortListener: Runnable? = null var bouncerShowing: Boolean = false @@ -127,12 +122,6 @@ constructor( } }) - shadeExpansionStateManager.addQsExpansionListener { isQsExpanded -> - if (qsExpanded != isQsExpanded) { - qsExpanded = isQsExpanded - } - } - mPowerManager = context.getSystemService(PowerManager::class.java) dumpManager.registerDumpable(this) } @@ -148,7 +137,8 @@ constructor( } private fun canHandleMotionEvent(): Boolean { - return wakeUpCoordinator.canShowPulsingHuns && !qsExpanded && !bouncerShowing + return wakeUpCoordinator.canShowPulsingHuns && !shadeInteractor.isQsExpanded.value && + !bouncerShowing } private fun startExpansion(event: MotionEvent): Boolean { @@ -379,7 +369,6 @@ constructor( it.println("isExpanding: $isExpanding") it.println("leavingLockscreen: $leavingLockscreen") it.println("mPulsing: $mPulsing") - it.println("qsExpanded: $qsExpanded") it.println("bouncerShowing: $bouncerShowing") } } diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/events/PrivacyDotViewController.kt b/packages/SystemUI/src/com/android/systemui/statusbar/events/PrivacyDotViewController.kt index 5af7cfc212d5..a36d36c3827b 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/events/PrivacyDotViewController.kt +++ b/packages/SystemUI/src/com/android/systemui/statusbar/events/PrivacyDotViewController.kt @@ -16,7 +16,6 @@ package com.android.systemui.statusbar.events -import androidx.core.animation.Animator import android.annotation.UiThread import android.graphics.Point import android.graphics.Rect @@ -24,13 +23,15 @@ import android.util.Log import android.view.Gravity import android.view.View import android.widget.FrameLayout -import com.android.internal.annotations.GuardedBy -import com.android.systemui.res.R +import androidx.core.animation.Animator import com.android.app.animation.Interpolators +import com.android.internal.annotations.GuardedBy import com.android.systemui.dagger.SysUISingleton +import com.android.systemui.dagger.qualifiers.Application import com.android.systemui.dagger.qualifiers.Main import com.android.systemui.plugins.statusbar.StatusBarStateController -import com.android.systemui.shade.ShadeExpansionStateManager +import com.android.systemui.res.R +import com.android.systemui.shade.domain.interactor.ShadeInteractor import com.android.systemui.statusbar.StatusBarState.SHADE import com.android.systemui.statusbar.StatusBarState.SHADE_LOCKED import com.android.systemui.statusbar.phone.StatusBarContentInsetsChangedListener @@ -43,6 +44,8 @@ import com.android.systemui.util.leak.RotationUtils.ROTATION_NONE import com.android.systemui.util.leak.RotationUtils.ROTATION_SEASCAPE import com.android.systemui.util.leak.RotationUtils.ROTATION_UPSIDE_DOWN import com.android.systemui.util.leak.RotationUtils.Rotation +import kotlinx.coroutines.CoroutineScope +import kotlinx.coroutines.launch import java.util.concurrent.Executor import javax.inject.Inject @@ -64,11 +67,12 @@ import javax.inject.Inject @SysUISingleton open class PrivacyDotViewController @Inject constructor( @Main private val mainExecutor: Executor, + @Application scope: CoroutineScope, private val stateController: StatusBarStateController, private val configurationController: ConfigurationController, private val contentInsetsProvider: StatusBarContentInsetsProvider, private val animationScheduler: SystemStatusAnimationScheduler, - shadeExpansionStateManager: ShadeExpansionStateManager + shadeInteractor: ShadeInteractor? ) { private lateinit var tl: View private lateinit var tr: View @@ -135,10 +139,12 @@ open class PrivacyDotViewController @Inject constructor( } }) - shadeExpansionStateManager.addQsExpansionListener { isQsExpanded -> - dlog("setQsExpanded $isQsExpanded") - synchronized(lock) { - nextViewState = nextViewState.copy(qsExpanded = isQsExpanded) + scope.launch { + shadeInteractor?.isQsExpanded?.collect { isQsExpanded -> + dlog("setQsExpanded $isQsExpanded") + synchronized(lock) { + nextViewState = nextViewState.copy(qsExpanded = isQsExpanded) + } } } } diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/events/StatusBarEventsModule.kt b/packages/SystemUI/src/com/android/systemui/statusbar/events/StatusBarEventsModule.kt index 84796f9acbc0..ed964821a5c1 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/events/StatusBarEventsModule.kt +++ b/packages/SystemUI/src/com/android/systemui/statusbar/events/StatusBarEventsModule.kt @@ -17,19 +17,11 @@ package com.android.systemui.statusbar.events import com.android.systemui.dagger.SysUISingleton -import com.android.systemui.dagger.qualifiers.Application -import com.android.systemui.dagger.qualifiers.Main -import com.android.systemui.dump.DumpManager -import com.android.systemui.flags.FeatureFlags -import com.android.systemui.flags.Flags import com.android.systemui.log.LogBuffer import com.android.systemui.log.LogBufferFactory -import com.android.systemui.statusbar.window.StatusBarWindowController -import com.android.systemui.util.concurrency.DelayableExecutor -import com.android.systemui.util.time.SystemClock +import dagger.Binds import dagger.Module import dagger.Provides -import kotlinx.coroutines.CoroutineScope @Module interface StatusBarEventsModule { @@ -42,41 +34,11 @@ interface StatusBarEventsModule { fun provideSystemStatusAnimationSchedulerLogBuffer(factory: LogBufferFactory): LogBuffer { return factory.create("SystemStatusAnimationSchedulerLog", 60) } - - @Provides - @SysUISingleton - fun provideSystemStatusAnimationScheduler( - featureFlags: FeatureFlags, - coordinator: SystemEventCoordinator, - chipAnimationController: SystemEventChipAnimationController, - statusBarWindowController: StatusBarWindowController, - dumpManager: DumpManager, - systemClock: SystemClock, - @Application coroutineScope: CoroutineScope, - @Main executor: DelayableExecutor, - logger: SystemStatusAnimationSchedulerLogger - ): SystemStatusAnimationScheduler { - return if (featureFlags.isEnabled(Flags.PLUG_IN_STATUS_BAR_CHIP)) { - SystemStatusAnimationSchedulerImpl( - coordinator, - chipAnimationController, - statusBarWindowController, - dumpManager, - systemClock, - coroutineScope, - logger - ) - } else { - SystemStatusAnimationSchedulerLegacyImpl( - coordinator, - chipAnimationController, - statusBarWindowController, - dumpManager, - systemClock, - executor - ) - } - } } -} + @Binds + @SysUISingleton + fun bindSystemStatusAnimationScheduler( + systemStatusAnimationSchedulerImpl: SystemStatusAnimationSchedulerImpl + ): SystemStatusAnimationScheduler +}
\ No newline at end of file diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/events/SystemEventChipAnimationController.kt b/packages/SystemUI/src/com/android/systemui/statusbar/events/SystemEventChipAnimationController.kt index 73c0bfec69a1..fec176523b4c 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/events/SystemEventChipAnimationController.kt +++ b/packages/SystemUI/src/com/android/systemui/statusbar/events/SystemEventChipAnimationController.kt @@ -32,8 +32,6 @@ import androidx.core.animation.AnimatorSet import androidx.core.animation.ValueAnimator import com.android.internal.annotations.VisibleForTesting import com.android.systemui.res.R -import com.android.systemui.flags.FeatureFlags -import com.android.systemui.flags.Flags import com.android.systemui.statusbar.phone.StatusBarContentInsetsChangedListener import com.android.systemui.statusbar.phone.StatusBarContentInsetsProvider import com.android.systemui.statusbar.window.StatusBarWindowController @@ -47,8 +45,7 @@ import kotlin.math.roundToInt class SystemEventChipAnimationController @Inject constructor( private val context: Context, private val statusBarWindowController: StatusBarWindowController, - private val contentInsetsProvider: StatusBarContentInsetsProvider, - private val featureFlags: FeatureFlags, + private val contentInsetsProvider: StatusBarContentInsetsProvider ) : SystemStatusAnimationCallback { private lateinit var animationWindowView: FrameLayout @@ -317,15 +314,8 @@ class SystemEventChipAnimationController @Inject constructor( it.marginEnd = marginEnd } - private fun initializeAnimRect() = if (featureFlags.isEnabled(Flags.PLUG_IN_STATUS_BAR_CHIP)) { - animRect.set(chipBounds) - } else { - animRect.set( - chipLeft, - currentAnimatedView!!.view.top, - chipRight, - currentAnimatedView!!.view.bottom) - } + private fun initializeAnimRect() = animRect.set(chipBounds) + /** * To be called during an animation, sets the width and updates the current animated chip view diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/events/SystemEventCoordinator.kt b/packages/SystemUI/src/com/android/systemui/statusbar/events/SystemEventCoordinator.kt index e9d5deccac94..a73d517a00e0 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/events/SystemEventCoordinator.kt +++ b/packages/SystemUI/src/com/android/systemui/statusbar/events/SystemEventCoordinator.kt @@ -24,8 +24,7 @@ import com.android.systemui.res.R import com.android.systemui.dagger.SysUISingleton import com.android.systemui.dagger.qualifiers.Application import com.android.systemui.display.domain.interactor.ConnectedDisplayInteractor -import com.android.systemui.flags.FeatureFlags -import com.android.systemui.flags.Flags +import com.android.systemui.display.domain.interactor.ConnectedDisplayInteractor.State import com.android.systemui.privacy.PrivacyChipBuilder import com.android.systemui.privacy.PrivacyItem import com.android.systemui.privacy.PrivacyItemController @@ -49,7 +48,6 @@ constructor( private val batteryController: BatteryController, private val privacyController: PrivacyItemController, private val context: Context, - private val featureFlags: FeatureFlags, @Application private val appScope: CoroutineScope, connectedDisplayInteractor: ConnectedDisplayInteractor ) { @@ -76,9 +74,7 @@ constructor( } fun notifyPluggedIn(@IntRange(from = 0, to = 100) batteryLevel: Int) { - if (featureFlags.isEnabled(Flags.PLUG_IN_STATUS_BAR_CHIP)) { - scheduler.onStatusEvent(BatteryEvent(batteryLevel)) - } + scheduler.onStatusEvent(BatteryEvent(batteryLevel)) } fun notifyPrivacyItemsEmpty() { diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/events/SystemStatusAnimationSchedulerLegacyImpl.kt b/packages/SystemUI/src/com/android/systemui/statusbar/events/SystemStatusAnimationSchedulerLegacyImpl.kt deleted file mode 100644 index 6b5a548b0afe..000000000000 --- a/packages/SystemUI/src/com/android/systemui/statusbar/events/SystemStatusAnimationSchedulerLegacyImpl.kt +++ /dev/null @@ -1,315 +0,0 @@ -/* - * Copyright (C) 2021 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.android.systemui.statusbar.events - -import android.os.Process -import android.provider.DeviceConfig -import android.util.Log -import androidx.core.animation.Animator -import androidx.core.animation.AnimatorListenerAdapter -import androidx.core.animation.AnimatorSet -import com.android.systemui.dagger.qualifiers.Main -import com.android.systemui.dump.DumpManager -import com.android.systemui.statusbar.window.StatusBarWindowController -import com.android.systemui.util.Assert -import com.android.systemui.util.concurrency.DelayableExecutor -import com.android.systemui.util.time.SystemClock -import java.io.PrintWriter -import javax.inject.Inject - -/** - * Dead-simple scheduler for system status events. Obeys the following principles (all values TBD): - * ``` - * - Avoiding log spam by only allowing 12 events per minute (1event/5s) - * - Waits 100ms to schedule any event for debouncing/prioritization - * - Simple prioritization: Privacy > Battery > connectivity (encoded in [StatusEvent]) - * - Only schedules a single event, and throws away lowest priority events - * ``` - * - * There are 4 basic stages of animation at play here: - * ``` - * 1. System chrome animation OUT - * 2. Chip animation IN - * 3. Chip animation OUT; potentially into a dot - * 4. System chrome animation IN - * ``` - * - * Thus we can keep all animations synchronized with two separate ValueAnimators, one for system - * chrome and the other for the chip. These can animate from 0,1 and listeners can parameterize - * their respective views based on the progress of the animator. Interpolation differences TBD - */ -open class SystemStatusAnimationSchedulerLegacyImpl -@Inject -constructor( - private val coordinator: SystemEventCoordinator, - private val chipAnimationController: SystemEventChipAnimationController, - private val statusBarWindowController: StatusBarWindowController, - private val dumpManager: DumpManager, - private val systemClock: SystemClock, - @Main private val executor: DelayableExecutor -) : SystemStatusAnimationScheduler { - - companion object { - private const val PROPERTY_ENABLE_IMMERSIVE_INDICATOR = "enable_immersive_indicator" - } - - fun isImmersiveIndicatorEnabled(): Boolean { - return DeviceConfig.getBoolean( - DeviceConfig.NAMESPACE_PRIVACY, - PROPERTY_ENABLE_IMMERSIVE_INDICATOR, - true - ) - } - - @SystemAnimationState private var animationState: Int = IDLE - - /** True if the persistent privacy dot should be active */ - var hasPersistentDot = false - protected set - - private var scheduledEvent: StatusEvent? = null - - val listeners = mutableSetOf<SystemStatusAnimationCallback>() - - init { - coordinator.attachScheduler(this) - dumpManager.registerDumpable(TAG, this) - } - - @SystemAnimationState override fun getAnimationState() = animationState - - override fun onStatusEvent(event: StatusEvent) { - // Ignore any updates until the system is up and running. However, for important events that - // request to be force visible (like privacy), ignore whether it's too early. - if ((isTooEarly() && !event.forceVisible) || !isImmersiveIndicatorEnabled()) { - return - } - - // Don't deal with threading for now (no need let's be honest) - Assert.isMainThread() - if ( - (event.priority > (scheduledEvent?.priority ?: -1)) && - animationState != ANIMATING_OUT && - animationState != SHOWING_PERSISTENT_DOT - ) { - // events can only be scheduled if a higher priority or no other event is in progress - if (DEBUG) { - Log.d(TAG, "scheduling event $event") - } - - scheduleEvent(event) - } else if (scheduledEvent?.shouldUpdateFromEvent(event) == true) { - if (DEBUG) { - Log.d(TAG, "updating current event from: $event. animationState=$animationState") - } - scheduledEvent?.updateFromEvent(event) - if (event.forceVisible) { - hasPersistentDot = true - // If we missed the chance to show the persistent dot, do it now - if (animationState == IDLE) { - notifyTransitionToPersistentDot() - } - } - } else { - if (DEBUG) { - Log.d(TAG, "ignoring event $event") - } - } - } - - override fun removePersistentDot() { - if (!hasPersistentDot || !isImmersiveIndicatorEnabled()) { - return - } - - hasPersistentDot = false - notifyHidePersistentDot() - return - } - - fun isTooEarly(): Boolean { - return systemClock.uptimeMillis() - Process.getStartUptimeMillis() < MIN_UPTIME - } - - /** Clear the scheduled event (if any) and schedule a new one */ - private fun scheduleEvent(event: StatusEvent) { - scheduledEvent = event - - if (event.forceVisible) { - hasPersistentDot = true - } - - // If animations are turned off, we'll transition directly to the dot - if (!event.showAnimation && event.forceVisible) { - notifyTransitionToPersistentDot() - scheduledEvent = null - return - } - - chipAnimationController.prepareChipAnimation(scheduledEvent!!.viewCreator) - animationState = ANIMATION_QUEUED - executor.executeDelayed({ runChipAnimation() }, DEBOUNCE_DELAY) - } - - /** - * 1. Define a total budget for the chip animation (1500ms) - * 2. Send out callbacks to listeners so that they can generate animations locally - * 3. Update the scheduler state so that clients know where we are - * 4. Maybe: provide scaffolding such as: dot location, margins, etc - * 5. Maybe: define a maximum animation length and enforce it. Probably only doable if we - * collect all of the animators and run them together. - */ - private fun runChipAnimation() { - statusBarWindowController.setForceStatusBarVisible(true) - animationState = ANIMATING_IN - - val animSet = collectStartAnimations() - if (animSet.totalDuration > 500) { - throw IllegalStateException( - "System animation total length exceeds budget. " + - "Expected: 500, actual: ${animSet.totalDuration}" - ) - } - animSet.addListener( - object : AnimatorListenerAdapter() { - override fun onAnimationEnd(animation: Animator) { - animationState = RUNNING_CHIP_ANIM - } - } - ) - animSet.start() - - executor.executeDelayed( - { - val animSet2 = collectFinishAnimations() - animationState = ANIMATING_OUT - animSet2.addListener( - object : AnimatorListenerAdapter() { - override fun onAnimationEnd(animation: Animator) { - animationState = - if (hasPersistentDot) { - SHOWING_PERSISTENT_DOT - } else { - IDLE - } - - statusBarWindowController.setForceStatusBarVisible(false) - } - } - ) - animSet2.start() - scheduledEvent = null - }, - DISPLAY_LENGTH - ) - } - - private fun collectStartAnimations(): AnimatorSet { - val animators = mutableListOf<Animator>() - listeners.forEach { listener -> - listener.onSystemEventAnimationBegin()?.let { anim -> animators.add(anim) } - } - animators.add(chipAnimationController.onSystemEventAnimationBegin()) - val animSet = AnimatorSet().also { it.playTogether(animators) } - - return animSet - } - - private fun collectFinishAnimations(): AnimatorSet { - val animators = mutableListOf<Animator>() - listeners.forEach { listener -> - listener.onSystemEventAnimationFinish(hasPersistentDot)?.let { anim -> - animators.add(anim) - } - } - animators.add(chipAnimationController.onSystemEventAnimationFinish(hasPersistentDot)) - if (hasPersistentDot) { - val dotAnim = notifyTransitionToPersistentDot() - if (dotAnim != null) { - animators.add(dotAnim) - } - } - val animSet = AnimatorSet().also { it.playTogether(animators) } - - return animSet - } - - private fun notifyTransitionToPersistentDot(): Animator? { - val anims: List<Animator> = - listeners.mapNotNull { - it.onSystemStatusAnimationTransitionToPersistentDot( - scheduledEvent?.contentDescription - ) - } - if (anims.isNotEmpty()) { - val aSet = AnimatorSet() - aSet.playTogether(anims) - return aSet - } - - return null - } - - private fun notifyHidePersistentDot(): Animator? { - val anims: List<Animator> = listeners.mapNotNull { it.onHidePersistentDot() } - - if (animationState == SHOWING_PERSISTENT_DOT) { - animationState = IDLE - } - - if (anims.isNotEmpty()) { - val aSet = AnimatorSet() - aSet.playTogether(anims) - return aSet - } - - return null - } - - override fun addCallback(listener: SystemStatusAnimationCallback) { - Assert.isMainThread() - - if (listeners.isEmpty()) { - coordinator.startObserving() - } - listeners.add(listener) - } - - override fun removeCallback(listener: SystemStatusAnimationCallback) { - Assert.isMainThread() - - listeners.remove(listener) - if (listeners.isEmpty()) { - coordinator.stopObserving() - } - } - - override fun dump(pw: PrintWriter, args: Array<out String>) { - pw.println("Scheduled event: $scheduledEvent") - pw.println("Has persistent privacy dot: $hasPersistentDot") - pw.println("Animation state: $animationState") - pw.println("Listeners:") - if (listeners.isEmpty()) { - pw.println("(none)") - } else { - listeners.forEach { pw.println(" $it") } - } - } -} - -private const val DEBUG = false -private const val TAG = "SystemStatusAnimationSchedulerLegacyImpl" diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/icon/ui/viewbinder/NotificationIconContainerViewBinder.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/icon/ui/viewbinder/NotificationIconContainerViewBinder.kt index c1f728a0b06e..db0fa99af440 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/icon/ui/viewbinder/NotificationIconContainerViewBinder.kt +++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/icon/ui/viewbinder/NotificationIconContainerViewBinder.kt @@ -15,26 +15,19 @@ */ package com.android.systemui.statusbar.notification.icon.ui.viewbinder -import android.animation.Animator -import android.animation.AnimatorListenerAdapter import android.graphics.Color import android.graphics.Rect import android.view.View import android.view.ViewGroup -import android.view.ViewPropertyAnimator import android.widget.FrameLayout import androidx.annotation.ColorInt import androidx.collection.ArrayMap import androidx.lifecycle.lifecycleScope -import com.android.app.animation.Interpolators import com.android.internal.policy.SystemBarUtils import com.android.internal.util.ContrastColorUtil import com.android.systemui.common.ui.ConfigurationState -import com.android.systemui.flags.FeatureFlagsClassic -import com.android.systemui.flags.Flags import com.android.systemui.lifecycle.repeatWhenAttached import com.android.systemui.res.R -import com.android.systemui.statusbar.CrossFadeHelper import com.android.systemui.statusbar.StatusBarIconView import com.android.systemui.statusbar.notification.NotificationUtils import com.android.systemui.statusbar.notification.collection.NotifCollection @@ -47,7 +40,6 @@ import com.android.systemui.statusbar.notification.icon.ui.viewmodel.Notificatio import com.android.systemui.statusbar.notification.icon.ui.viewmodel.NotificationIconsViewData import com.android.systemui.statusbar.phone.DozeParameters import com.android.systemui.statusbar.phone.NotificationIconContainer -import com.android.systemui.statusbar.phone.ScreenOffAnimationController import com.android.systemui.statusbar.policy.ConfigurationController import com.android.systemui.statusbar.policy.onConfigChanged import com.android.systemui.util.children @@ -65,7 +57,6 @@ import kotlinx.coroutines.flow.Flow import kotlinx.coroutines.flow.StateFlow import kotlinx.coroutines.flow.combine import kotlinx.coroutines.flow.mapNotNull -import kotlinx.coroutines.flow.stateIn import kotlinx.coroutines.launch /** Binds a view-model to a [NotificationIconContainer]. */ @@ -118,8 +109,6 @@ object NotificationIconContainerViewBinder { configuration: ConfigurationState, configurationController: ConfigurationController, dozeParameters: DozeParameters, - featureFlags: FeatureFlagsClassic, - screenOffAnimationController: ScreenOffAnimationController, viewStore: IconViewStore, ): DisposableHandle { return view.repeatWhenAttached { @@ -134,16 +123,6 @@ object NotificationIconContainerViewBinder { } launch { viewModel.animationsEnabled.bindAnimationsEnabled(view) } launch { viewModel.isDozing.bindIsDozing(view, dozeParameters) } - // TODO(b/278765923): this should live where AOD is bound, not inside of the NIC - // view-binder - launch { - viewModel.isVisible.bindIsVisible( - view, - configuration, - featureFlags, - screenOffAnimationController, - ) - } launch { configuration .getColorAttr(R.attr.wallpaperTextColor, DEFAULT_AOD_ICON_COLOR) @@ -333,106 +312,11 @@ object NotificationIconContainerViewBinder { setDecorColor(iconColors.tint) } - private suspend fun Flow<AnimatedValue<Boolean>>.bindIsVisible( - view: NotificationIconContainer, - configuration: ConfigurationState, - featureFlags: FeatureFlagsClassic, - screenOffAnimationController: ScreenOffAnimationController, - ): Unit = coroutineScope { - val iconAppearTranslation = - configuration.getDimensionPixelSize(R.dimen.shelf_appear_translation).stateIn(this) - val statusViewMigrated = featureFlags.isEnabled(Flags.MIGRATE_KEYGUARD_STATUS_VIEW) - collect { isVisible -> - view.animate().cancel() - val animatorListener = - object : AnimatorListenerAdapter() { - override fun onAnimationEnd(animation: Animator) { - isVisible.stopAnimating() - } - } - when { - !isVisible.isAnimating -> { - view.alpha = 1f - if (!statusViewMigrated) { - view.translationY = 0f - } - view.visibility = if (isVisible.value) View.VISIBLE else View.INVISIBLE - } - featureFlags.isEnabled(Flags.NEW_AOD_TRANSITION) -> { - view.animateInIconTranslation(statusViewMigrated) - if (isVisible.value) { - CrossFadeHelper.fadeIn(view, animatorListener) - } else { - CrossFadeHelper.fadeOut(view, animatorListener) - } - } - !isVisible.value -> { - // Let's make sure the icon are translated to 0, since we cancelled it above - view.animateInIconTranslation(statusViewMigrated) - CrossFadeHelper.fadeOut(view, animatorListener) - } - view.visibility != View.VISIBLE -> { - // No fading here, let's just appear the icons instead! - view.visibility = View.VISIBLE - view.alpha = 1f - view.appearIcons( - animate = screenOffAnimationController.shouldAnimateAodIcons(), - iconAppearTranslation.value, - statusViewMigrated, - animatorListener, - ) - } - else -> { - // Let's make sure the icons are translated to 0, since we cancelled it above - view.animateInIconTranslation(statusViewMigrated) - // We were fading out, let's fade in instead - CrossFadeHelper.fadeIn(view, animatorListener) - } - } - } - } - - private fun View.appearIcons( - animate: Boolean, - iconAppearTranslation: Int, - statusViewMigrated: Boolean, - animatorListener: Animator.AnimatorListener, - ) { - if (animate) { - if (!statusViewMigrated) { - translationY = -iconAppearTranslation.toFloat() - } - alpha = 0f - animate() - .alpha(1f) - .setInterpolator(Interpolators.LINEAR) - .setDuration(AOD_ICONS_APPEAR_DURATION) - .apply { if (statusViewMigrated) animateInIconTranslation() } - .setListener(animatorListener) - .start() - } else { - alpha = 1.0f - if (!statusViewMigrated) { - translationY = 0f - } - } - } - - private fun View.animateInIconTranslation(statusViewMigrated: Boolean) { - if (!statusViewMigrated) { - animate().animateInIconTranslation().setDuration(AOD_ICONS_APPEAR_DURATION).start() - } - } - - private fun ViewPropertyAnimator.animateInIconTranslation(): ViewPropertyAnimator = - setInterpolator(Interpolators.DECELERATE_QUINT).translationY(0f) - /** External storage for [StatusBarIconView] instances. */ fun interface IconViewStore { fun iconView(key: String): StatusBarIconView? } - private const val AOD_ICONS_APPEAR_DURATION: Long = 200 @ColorInt private val DEFAULT_AOD_ICON_COLOR = Color.WHITE } diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/icon/ui/viewmodel/NotificationIconContainerAlwaysOnDisplayViewModel.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/icon/ui/viewmodel/NotificationIconContainerAlwaysOnDisplayViewModel.kt index 611ed89c89af..835c0592c588 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/icon/ui/viewmodel/NotificationIconContainerAlwaysOnDisplayViewModel.kt +++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/icon/ui/viewmodel/NotificationIconContainerAlwaysOnDisplayViewModel.kt @@ -15,26 +15,16 @@ */ package com.android.systemui.statusbar.notification.icon.ui.viewmodel -import android.graphics.Rect import com.android.systemui.dagger.SysUISingleton -import com.android.systemui.deviceentry.domain.interactor.DeviceEntryInteractor -import com.android.systemui.flags.FeatureFlagsClassic -import com.android.systemui.flags.Flags import com.android.systemui.keyguard.domain.interactor.KeyguardInteractor import com.android.systemui.keyguard.domain.interactor.KeyguardTransitionInteractor import com.android.systemui.keyguard.shared.model.KeyguardState import com.android.systemui.keyguard.shared.model.TransitionStep import com.android.systemui.shade.domain.interactor.ShadeInteractor -import com.android.systemui.statusbar.notification.domain.interactor.NotificationsKeyguardInteractor import com.android.systemui.statusbar.notification.icon.domain.interactor.AlwaysOnDisplayNotificationIconsInteractor -import com.android.systemui.statusbar.phone.DozeParameters -import com.android.systemui.statusbar.phone.ScreenOffAnimationController -import com.android.systemui.util.kotlin.pairwise -import com.android.systemui.util.kotlin.sample import com.android.systemui.util.ui.AnimatableEvent import com.android.systemui.util.ui.AnimatedValue import com.android.systemui.util.ui.toAnimatedValueFlow -import com.android.systemui.util.ui.zip import javax.inject.Inject import kotlinx.coroutines.flow.Flow import kotlinx.coroutines.flow.combine @@ -46,14 +36,9 @@ import kotlinx.coroutines.flow.map class NotificationIconContainerAlwaysOnDisplayViewModel @Inject constructor( - private val deviceEntryInteractor: DeviceEntryInteractor, - private val dozeParameters: DozeParameters, - private val featureFlags: FeatureFlagsClassic, iconsInteractor: AlwaysOnDisplayNotificationIconsInteractor, keyguardInteractor: KeyguardInteractor, keyguardTransitionInteractor: KeyguardTransitionInteractor, - private val notificationsKeyguardInteractor: NotificationsKeyguardInteractor, - screenOffAnimationController: ScreenOffAnimationController, shadeInteractor: ShadeInteractor, ) { @@ -84,45 +69,6 @@ constructor( .distinctUntilChanged() .toAnimatedValueFlow() - /** Is the icon container visible? */ - val isVisible: Flow<AnimatedValue<Boolean>> = - combine( - keyguardTransitionInteractor.finishedKeyguardState.map { it != KeyguardState.GONE }, - deviceEntryInteractor.isBypassEnabled, - areNotifsFullyHiddenAnimated(), - isPulseExpandingAnimated(), - ) { - onKeyguard: Boolean, - isBypassEnabled: Boolean, - notifsFullyHidden: AnimatedValue<Boolean>, - pulseExpanding: AnimatedValue<Boolean>, - -> - when { - // Hide the AOD icons if we're not in the KEYGUARD state unless the screen off - // animation is playing, in which case we want them to be visible if we're - // animating in the AOD UI and will be switching to KEYGUARD shortly. - !onKeyguard && !screenOffAnimationController.shouldShowAodIconsWhenShade() -> - AnimatedValue.NotAnimating(false) - else -> - zip(notifsFullyHidden, pulseExpanding) { - areNotifsFullyHidden, - isPulseExpanding, - -> - when { - // If we're bypassing, then we're visible - isBypassEnabled -> true - // If we are pulsing (and not bypassing), then we are hidden - isPulseExpanding -> false - // If notifs are fully gone, then we're visible - areNotifsFullyHidden -> true - // Otherwise, we're hidden - else -> false - } - } - } - } - .distinctUntilChanged() - /** [NotificationIconsViewData] indicating which icons to display in the view. */ val icons: Flow<NotificationIconsViewData> = iconsInteractor.aodNotifs.map { entries -> @@ -130,43 +76,4 @@ constructor( visibleKeys = entries.mapNotNull { it.toIconInfo(it.aodIcon) }, ) } - - /** Is there an expanded pulse, are we animating in response? */ - private fun isPulseExpandingAnimated(): Flow<AnimatedValue<Boolean>> { - return notificationsKeyguardInteractor.isPulseExpanding - .pairwise(initialValue = null) - // If pulsing changes, start animating, unless it's the first emission - .map { (prev, expanding) -> AnimatableEvent(expanding, startAnimating = prev != null) } - .toAnimatedValueFlow() - } - - /** Are notifications completely hidden from view, are we animating in response? */ - private fun areNotifsFullyHiddenAnimated(): Flow<AnimatedValue<Boolean>> { - return notificationsKeyguardInteractor.areNotificationsFullyHidden - .pairwise(initialValue = null) - .sample(deviceEntryInteractor.isBypassEnabled) { (prev, fullyHidden), bypassEnabled -> - val animate = - when { - // Don't animate for the first value - prev == null -> false - // Always animate if bypass is enabled. - bypassEnabled -> true - // If we're not bypassing and we're not going to AOD, then we're not - // animating. - !dozeParameters.alwaysOn -> false - // Don't animate when going to AOD if the display needs blanking. - dozeParameters.displayNeedsBlanking -> false - // We only want the appear animations to happen when the notifications - // get fully hidden, since otherwise the un-hide animation overlaps. - featureFlags.isEnabled(Flags.NEW_AOD_TRANSITION) -> true - else -> fullyHidden - } - AnimatableEvent(fullyHidden, animate) - } - .toAnimatedValueFlow() - } - - private class IconColorsImpl(override val tint: Int) : NotificationIconColors { - override fun staticDrawableColor(viewBounds: Rect, isColorized: Boolean): Int = tint - } } diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/interruption/CommonVisualInterruptionSuppressors.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/interruption/CommonVisualInterruptionSuppressors.kt new file mode 100644 index 000000000000..11c982590477 --- /dev/null +++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/interruption/CommonVisualInterruptionSuppressors.kt @@ -0,0 +1,182 @@ +/* + * Copyright (C) 2023 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.systemui.statusbar.notification.interruption + +import android.app.Notification.VISIBILITY_PRIVATE +import android.app.NotificationManager.IMPORTANCE_DEFAULT +import android.app.NotificationManager.IMPORTANCE_HIGH +import android.database.ContentObserver +import android.hardware.display.AmbientDisplayConfiguration +import android.os.Handler +import android.os.PowerManager +import android.provider.Settings.Global.HEADS_UP_NOTIFICATIONS_ENABLED +import android.provider.Settings.Global.HEADS_UP_OFF +import com.android.systemui.dagger.qualifiers.Main +import com.android.systemui.plugins.statusbar.StatusBarStateController +import com.android.systemui.settings.UserTracker +import com.android.systemui.statusbar.StatusBarState.SHADE +import com.android.systemui.statusbar.notification.collection.NotificationEntry +import com.android.systemui.statusbar.notification.interruption.NotificationInterruptStateProviderImpl.MAX_HUN_WHEN_AGE_MS +import com.android.systemui.statusbar.notification.interruption.VisualInterruptionType.PEEK +import com.android.systemui.statusbar.notification.interruption.VisualInterruptionType.PULSE +import com.android.systemui.statusbar.policy.BatteryController +import com.android.systemui.statusbar.policy.HeadsUpManager +import com.android.systemui.util.settings.GlobalSettings +import com.android.systemui.util.time.SystemClock + +class PeekDisabledSuppressor( + private val globalSettings: GlobalSettings, + private val headsUpManager: HeadsUpManager, + private val logger: NotificationInterruptLogger, + @Main private val mainHandler: Handler, +) : VisualInterruptionCondition(types = setOf(PEEK), reason = "peek setting disabled") { + private var isEnabled = false + + override fun shouldSuppress(): Boolean = !isEnabled + + override fun start() { + val observer = + object : ContentObserver(mainHandler) { + override fun onChange(selfChange: Boolean) { + val wasEnabled = isEnabled + + isEnabled = + globalSettings.getInt(HEADS_UP_NOTIFICATIONS_ENABLED, HEADS_UP_OFF) != + HEADS_UP_OFF + + // QQQ: Do we want to log this even if it hasn't changed? + logger.logHeadsUpFeatureChanged(isEnabled) + + // QQQ: Is there a better place for this side effect? What if HeadsUpManager + // registered for it directly? + if (wasEnabled && !isEnabled) { + logger.logWillDismissAll() + headsUpManager.releaseAllImmediately() + } + } + } + + globalSettings.registerContentObserver( + globalSettings.getUriFor(HEADS_UP_NOTIFICATIONS_ENABLED), + /* notifyForDescendants = */ true, + observer + ) + + // QQQ: Do we need to register for SETTING_HEADS_UP_TICKER? It seems unused. + + observer.onChange(/* selfChange = */ true) + } +} + +class PulseDisabledSuppressor( + private val ambientDisplayConfiguration: AmbientDisplayConfiguration, + private val userTracker: UserTracker, +) : VisualInterruptionCondition(types = setOf(PULSE), reason = "pulse setting disabled") { + override fun shouldSuppress(): Boolean = + !ambientDisplayConfiguration.pulseOnNotificationEnabled(userTracker.userId) +} + +class PulseBatterySaverSuppressor(private val batteryController: BatteryController) : + VisualInterruptionCondition( + types = setOf(PULSE), + reason = "pulsing disabled by battery saver" + ) { + override fun shouldSuppress() = batteryController.isAodPowerSave() +} + +class PeekPackageSnoozedSuppressor(private val headsUpManager: HeadsUpManager) : + VisualInterruptionFilter(types = setOf(PEEK), reason = "package snoozed") { + override fun shouldSuppress(entry: NotificationEntry) = + when { + // Assume any notification with an FSI is time-sensitive (like an alarm or incoming + // call) and ignore whether HUNs have been snoozed for the package. + entry.sbn.notification.fullScreenIntent != null -> false + + // Otherwise, check if the package is snoozed. + else -> headsUpManager.isSnoozed(entry.sbn.packageName) + } +} + +class PeekAlreadyBubbledSuppressor(private val statusBarStateController: StatusBarStateController) : + VisualInterruptionFilter(types = setOf(PEEK), reason = "already bubbled") { + override fun shouldSuppress(entry: NotificationEntry) = + when { + statusBarStateController.state != SHADE -> false + else -> entry.isBubble + } +} + +class PeekDndSuppressor() : + VisualInterruptionFilter(types = setOf(PEEK), reason = "suppressed by DND") { + override fun shouldSuppress(entry: NotificationEntry) = entry.shouldSuppressPeek() +} + +class PeekNotImportantSuppressor() : + VisualInterruptionFilter(types = setOf(PEEK), reason = "not important") { + override fun shouldSuppress(entry: NotificationEntry) = entry.importance < IMPORTANCE_HIGH +} + +class PeekDeviceNotInUseSuppressor( + private val powerManager: PowerManager, + private val statusBarStateController: StatusBarStateController +) : VisualInterruptionCondition(types = setOf(PEEK), reason = "not in use") { + override fun shouldSuppress() = + when { + !powerManager.isScreenOn || statusBarStateController.isDreaming -> true + else -> false + } +} + +class PeekOldWhenSuppressor(private val systemClock: SystemClock) : + VisualInterruptionFilter(types = setOf(PEEK), reason = "old when") { + private fun whenAge(entry: NotificationEntry) = + systemClock.currentTimeMillis() - entry.sbn.notification.`when` + + override fun shouldSuppress(entry: NotificationEntry): Boolean = + when { + // Ignore a "when" of 0, as it is unlikely to be a meaningful timestamp. + entry.sbn.notification.`when` <= 0L -> false + + // Assume all HUNs with FSIs, foreground services, or user-initiated jobs are + // time-sensitive, regardless of their "when". + entry.sbn.notification.fullScreenIntent != null || + entry.sbn.notification.isForegroundService || + entry.sbn.notification.isUserInitiatedJob -> false + + // Otherwise, check if the HUN's "when" is too old. + else -> whenAge(entry) >= MAX_HUN_WHEN_AGE_MS + } +} + +class PulseEffectSuppressor() : + VisualInterruptionFilter(types = setOf(PULSE), reason = "ambient effect suppressed") { + override fun shouldSuppress(entry: NotificationEntry) = entry.shouldSuppressAmbient() +} + +class PulseLockscreenVisibilityPrivateSuppressor() : + VisualInterruptionFilter( + types = setOf(PULSE), + reason = "notification hidden on lock screen by override" + ) { + override fun shouldSuppress(entry: NotificationEntry) = + entry.ranking.lockscreenVisibilityOverride == VISIBILITY_PRIVATE +} + +class PulseLowImportanceSuppressor() : + VisualInterruptionFilter(types = setOf(PULSE), reason = "importance less than DEFAULT") { + override fun shouldSuppress(entry: NotificationEntry) = entry.importance < IMPORTANCE_DEFAULT +} diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/interruption/NotificationInterruptStateProviderImpl.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/interruption/NotificationInterruptStateProviderImpl.java index 301ddbf42ff2..f2ade340fc4f 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/interruption/NotificationInterruptStateProviderImpl.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/interruption/NotificationInterruptStateProviderImpl.java @@ -16,6 +16,9 @@ package com.android.systemui.statusbar.notification.interruption; +import static android.provider.Settings.Global.HEADS_UP_NOTIFICATIONS_ENABLED; +import static android.provider.Settings.Global.HEADS_UP_OFF; + import static com.android.systemui.statusbar.StatusBarState.SHADE; import static com.android.systemui.statusbar.notification.interruption.NotificationInterruptStateProviderImpl.NotificationInterruptEvent.FSI_SUPPRESSED_NO_HUN_OR_KEYGUARD; import static com.android.systemui.statusbar.notification.interruption.NotificationInterruptStateProviderImpl.NotificationInterruptEvent.FSI_SUPPRESSED_SUPPRESSIVE_BUBBLE_METADATA; @@ -24,12 +27,10 @@ import static com.android.systemui.statusbar.notification.interruption.Notificat import android.app.Notification; import android.app.NotificationManager; -import android.content.ContentResolver; import android.database.ContentObserver; import android.hardware.display.AmbientDisplayConfiguration; import android.os.Handler; import android.os.PowerManager; -import android.provider.Settings; import android.service.notification.StatusBarNotification; import androidx.annotation.NonNull; @@ -48,6 +49,8 @@ import com.android.systemui.statusbar.policy.BatteryController; import com.android.systemui.statusbar.policy.DeviceProvisionedController; import com.android.systemui.statusbar.policy.HeadsUpManager; import com.android.systemui.statusbar.policy.KeyguardStateController; +import com.android.systemui.util.settings.GlobalSettings; +import com.android.systemui.util.time.SystemClock; import java.util.ArrayList; import java.util.List; @@ -66,7 +69,6 @@ public class NotificationInterruptStateProviderImpl implements NotificationInter private final List<NotificationInterruptSuppressor> mSuppressors = new ArrayList<>(); private final StatusBarStateController mStatusBarStateController; private final KeyguardStateController mKeyguardStateController; - private final ContentResolver mContentResolver; private final PowerManager mPowerManager; private final AmbientDisplayConfiguration mAmbientDisplayConfiguration; private final BatteryController mBatteryController; @@ -77,6 +79,8 @@ public class NotificationInterruptStateProviderImpl implements NotificationInter private final UiEventLogger mUiEventLogger; private final UserTracker mUserTracker; private final DeviceProvisionedController mDeviceProvisionedController; + private final SystemClock mSystemClock; + private final GlobalSettings mGlobalSettings; @VisibleForTesting protected boolean mUseHeadsUp = false; @@ -111,7 +115,6 @@ public class NotificationInterruptStateProviderImpl implements NotificationInter @Inject public NotificationInterruptStateProviderImpl( - ContentResolver contentResolver, PowerManager powerManager, AmbientDisplayConfiguration ambientDisplayConfiguration, BatteryController batteryController, @@ -124,8 +127,9 @@ public class NotificationInterruptStateProviderImpl implements NotificationInter KeyguardNotificationVisibilityProvider keyguardNotificationVisibilityProvider, UiEventLogger uiEventLogger, UserTracker userTracker, - DeviceProvisionedController deviceProvisionedController) { - mContentResolver = contentResolver; + DeviceProvisionedController deviceProvisionedController, + SystemClock systemClock, + GlobalSettings globalSettings) { mPowerManager = powerManager; mBatteryController = batteryController; mAmbientDisplayConfiguration = ambientDisplayConfiguration; @@ -137,15 +141,16 @@ public class NotificationInterruptStateProviderImpl implements NotificationInter mKeyguardNotificationVisibilityProvider = keyguardNotificationVisibilityProvider; mUiEventLogger = uiEventLogger; mUserTracker = userTracker; + mDeviceProvisionedController = deviceProvisionedController; + mSystemClock = systemClock; + mGlobalSettings = globalSettings; ContentObserver headsUpObserver = new ContentObserver(mainHandler) { @Override public void onChange(boolean selfChange) { - boolean wasUsing = mUseHeadsUp; - mUseHeadsUp = ENABLE_HEADS_UP - && Settings.Global.HEADS_UP_OFF != Settings.Global.getInt( - mContentResolver, - Settings.Global.HEADS_UP_NOTIFICATIONS_ENABLED, - Settings.Global.HEADS_UP_OFF); + final boolean wasUsing = mUseHeadsUp; + final boolean settingEnabled = HEADS_UP_OFF + != mGlobalSettings.getInt(HEADS_UP_NOTIFICATIONS_ENABLED, HEADS_UP_OFF); + mUseHeadsUp = ENABLE_HEADS_UP && settingEnabled; mLogger.logHeadsUpFeatureChanged(mUseHeadsUp); if (wasUsing != mUseHeadsUp) { if (!mUseHeadsUp) { @@ -157,16 +162,15 @@ public class NotificationInterruptStateProviderImpl implements NotificationInter }; if (ENABLE_HEADS_UP) { - mContentResolver.registerContentObserver( - Settings.Global.getUriFor(Settings.Global.HEADS_UP_NOTIFICATIONS_ENABLED), + mGlobalSettings.registerContentObserver( + mGlobalSettings.getUriFor(HEADS_UP_NOTIFICATIONS_ENABLED), true, headsUpObserver); - mContentResolver.registerContentObserver( - Settings.Global.getUriFor(SETTING_HEADS_UP_TICKER), true, + mGlobalSettings.registerContentObserver( + mGlobalSettings.getUriFor(SETTING_HEADS_UP_TICKER), true, headsUpObserver); } headsUpObserver.onChange(true); // set up - mDeviceProvisionedController = deviceProvisionedController; } @Override @@ -603,7 +607,7 @@ public class NotificationInterruptStateProviderImpl implements NotificationInter } final long when = notification.when; - final long now = System.currentTimeMillis(); + final long now = mSystemClock.currentTimeMillis(); final long age = now - when; if (age < MAX_HUN_WHEN_AGE_MS) { diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/interruption/VisualInterruptionDecisionProvider.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/interruption/VisualInterruptionDecisionProvider.kt index 920bbe96b33b..da8474e92629 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/interruption/VisualInterruptionDecisionProvider.kt +++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/interruption/VisualInterruptionDecisionProvider.kt @@ -13,6 +13,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ + package com.android.systemui.statusbar.notification.interruption import com.android.systemui.statusbar.notification.collection.NotificationEntry @@ -51,6 +52,13 @@ interface VisualInterruptionDecisionProvider { } /** + * Initializes the provider. + * + * Must be called before any method except [addLegacySuppressor]. + */ + fun start() {} + + /** * Adds a [component][suppressor] that can suppress visual interruptions. * * This class may call suppressors in any order. diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/interruption/VisualInterruptionDecisionProviderImpl.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/interruption/VisualInterruptionDecisionProviderImpl.kt new file mode 100644 index 000000000000..7f144bf14615 --- /dev/null +++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/interruption/VisualInterruptionDecisionProviderImpl.kt @@ -0,0 +1,261 @@ +/* + * Copyright (C) 2023 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.android.systemui.statusbar.notification.interruption + +import android.hardware.display.AmbientDisplayConfiguration +import android.os.Handler +import android.os.PowerManager +import android.util.Log +import com.android.systemui.dagger.qualifiers.Main +import com.android.systemui.plugins.statusbar.StatusBarStateController +import com.android.systemui.settings.UserTracker +import com.android.systemui.statusbar.notification.collection.NotificationEntry +import com.android.systemui.statusbar.notification.interruption.VisualInterruptionDecisionProvider.Decision +import com.android.systemui.statusbar.notification.interruption.VisualInterruptionDecisionProvider.FullScreenIntentDecision +import com.android.systemui.statusbar.notification.interruption.VisualInterruptionType.BUBBLE +import com.android.systemui.statusbar.notification.interruption.VisualInterruptionType.PEEK +import com.android.systemui.statusbar.notification.interruption.VisualInterruptionType.PULSE +import com.android.systemui.statusbar.policy.BatteryController +import com.android.systemui.statusbar.policy.HeadsUpManager +import com.android.systemui.util.settings.GlobalSettings +import com.android.systemui.util.time.SystemClock +import javax.inject.Inject + +class VisualInterruptionDecisionProviderImpl +@Inject +constructor( + private val ambientDisplayConfiguration: AmbientDisplayConfiguration, + private val batteryController: BatteryController, + private val globalSettings: GlobalSettings, + private val headsUpManager: HeadsUpManager, + private val logger: NotificationInterruptLogger, + @Main private val mainHandler: Handler, + private val powerManager: PowerManager, + private val statusBarStateController: StatusBarStateController, + private val systemClock: SystemClock, + private val userTracker: UserTracker, +) : VisualInterruptionDecisionProvider { + private var started = false + + override fun start() { + check(!started) + + addCondition(PeekDisabledSuppressor(globalSettings, headsUpManager, logger, mainHandler)) + addCondition(PulseDisabledSuppressor(ambientDisplayConfiguration, userTracker)) + addCondition(PulseBatterySaverSuppressor(batteryController)) + addFilter(PeekPackageSnoozedSuppressor(headsUpManager)) + addFilter(PeekAlreadyBubbledSuppressor(statusBarStateController)) + addFilter(PeekDndSuppressor()) + addFilter(PeekNotImportantSuppressor()) + addCondition(PeekDeviceNotInUseSuppressor(powerManager, statusBarStateController)) + addFilter(PeekOldWhenSuppressor(systemClock)) + addFilter(PulseEffectSuppressor()) + addFilter(PulseLockscreenVisibilityPrivateSuppressor()) + addFilter(PulseLowImportanceSuppressor()) + + started = true + } + + private class DecisionImpl( + override val shouldInterrupt: Boolean, + override val logReason: String + ) : Decision + + private class FullScreenIntentDecisionImpl( + override val shouldInterrupt: Boolean, + override val wouldInterruptWithoutDnd: Boolean, + override val logReason: String, + val originalEntry: NotificationEntry, + ) : FullScreenIntentDecision { + var hasBeenLogged = false + } + + private val legacySuppressors = mutableSetOf<NotificationInterruptSuppressor>() + private val conditions = mutableListOf<VisualInterruptionCondition>() + private val filters = mutableListOf<VisualInterruptionFilter>() + + override fun addLegacySuppressor(suppressor: NotificationInterruptSuppressor) { + legacySuppressors.add(suppressor) + } + + override fun removeLegacySuppressor(suppressor: NotificationInterruptSuppressor) { + legacySuppressors.remove(suppressor) + } + + fun addCondition(condition: VisualInterruptionCondition) { + conditions.add(condition) + condition.start() + } + + fun addFilter(filter: VisualInterruptionFilter) { + filters.add(filter) + filter.start() + } + + override fun makeUnloggedHeadsUpDecision(entry: NotificationEntry): Decision { + check(started) + return makeHeadsUpDecision(entry) + } + + override fun makeAndLogHeadsUpDecision(entry: NotificationEntry): Decision { + check(started) + return makeHeadsUpDecision(entry).also { logHeadsUpDecision(entry, it) } + } + + override fun makeUnloggedFullScreenIntentDecision( + entry: NotificationEntry + ): FullScreenIntentDecision { + check(started) + return makeFullScreenDecision(entry) + } + + override fun logFullScreenIntentDecision(decision: FullScreenIntentDecision) { + check(started) + val decisionImpl = + decision as? FullScreenIntentDecisionImpl + ?: run { + Log.wtf(TAG, "Wrong subclass of FullScreenIntentDecision: $decision") + return + } + if (decision.hasBeenLogged) { + Log.wtf(TAG, "Already logged decision: $decision") + return + } + logFullScreenIntentDecision(decisionImpl) + decision.hasBeenLogged = true + } + + override fun makeAndLogBubbleDecision(entry: NotificationEntry): Decision { + check(started) + return makeBubbleDecision(entry).also { logBubbleDecision(entry, it) } + } + + private fun makeHeadsUpDecision(entry: NotificationEntry): DecisionImpl { + if (statusBarStateController.isDozing) { + return makePulseDecision(entry) + } else { + return makePeekDecision(entry) + } + } + + private fun makePeekDecision(entry: NotificationEntry): DecisionImpl { + checkConditions(PEEK)?.let { + return DecisionImpl(shouldInterrupt = false, logReason = it.reason) + } + checkFilters(PEEK, entry)?.let { + return DecisionImpl(shouldInterrupt = false, logReason = it.reason) + } + checkSuppressors(entry)?.let { + return DecisionImpl( + shouldInterrupt = false, + logReason = "${it.name}.suppressInterruptions" + ) + } + checkAwakeSuppressors(entry)?.let { + return DecisionImpl( + shouldInterrupt = false, + logReason = "${it.name}.suppressAwakeInterruptions" + ) + } + checkAwakeHeadsUpSuppressors(entry)?.let { + return DecisionImpl( + shouldInterrupt = false, + logReason = "${it.name}.suppressAwakeHeadsUpInterruptions" + ) + } + return DecisionImpl(shouldInterrupt = true, logReason = "not suppressed") + } + + private fun makePulseDecision(entry: NotificationEntry): DecisionImpl { + checkConditions(PULSE)?.let { + return DecisionImpl(shouldInterrupt = false, logReason = it.reason) + } + checkFilters(PULSE, entry)?.let { + return DecisionImpl(shouldInterrupt = false, logReason = it.reason) + } + checkSuppressors(entry)?.let { + return DecisionImpl( + shouldInterrupt = false, + logReason = "${it.name}.suppressInterruptions" + ) + } + return DecisionImpl(shouldInterrupt = true, logReason = "not suppressed") + } + + private fun makeBubbleDecision(entry: NotificationEntry): DecisionImpl { + checkConditions(BUBBLE)?.let { + return DecisionImpl(shouldInterrupt = false, logReason = it.reason) + } + checkFilters(BUBBLE, entry)?.let { + return DecisionImpl(shouldInterrupt = false, logReason = it.reason) + } + checkSuppressors(entry)?.let { + return DecisionImpl( + shouldInterrupt = false, + logReason = "${it.name}.suppressInterruptions" + ) + } + checkAwakeSuppressors(entry)?.let { + return DecisionImpl( + shouldInterrupt = false, + logReason = "${it.name}.suppressAwakeInterruptions" + ) + } + return DecisionImpl(shouldInterrupt = true, logReason = "not suppressed") + } + + private fun makeFullScreenDecision(entry: NotificationEntry): FullScreenIntentDecisionImpl { + // Not yet implemented. + return FullScreenIntentDecisionImpl( + shouldInterrupt = true, + wouldInterruptWithoutDnd = true, + logReason = "FSI logic not yet implemented in VisualInterruptionDecisionProviderImpl", + originalEntry = entry + ) + } + + private fun logHeadsUpDecision(entry: NotificationEntry, decision: DecisionImpl) { + // Not yet implemented. + } + + private fun logBubbleDecision(entry: NotificationEntry, decision: DecisionImpl) { + // Not yet implemented. + } + + private fun logFullScreenIntentDecision(decision: FullScreenIntentDecisionImpl) { + // Not yet implemented. + } + + private fun checkSuppressors(entry: NotificationEntry) = + legacySuppressors.firstOrNull { it.suppressInterruptions(entry) } + + private fun checkAwakeSuppressors(entry: NotificationEntry) = + legacySuppressors.firstOrNull { it.suppressAwakeInterruptions(entry) } + + private fun checkAwakeHeadsUpSuppressors(entry: NotificationEntry) = + legacySuppressors.firstOrNull { it.suppressAwakeHeadsUp(entry) } + + private fun checkConditions(type: VisualInterruptionType): VisualInterruptionCondition? = + conditions.firstOrNull { it.types.contains(type) && it.shouldSuppress() } + + private fun checkFilters( + type: VisualInterruptionType, + entry: NotificationEntry + ): VisualInterruptionFilter? = + filters.firstOrNull { it.types.contains(type) && it.shouldSuppress(entry) } +} + +private const val TAG = "VisualInterruptionDecisionProviderImpl" diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/interruption/VisualInterruptionRefactor.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/interruption/VisualInterruptionRefactor.kt new file mode 100644 index 000000000000..2624363c7dec --- /dev/null +++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/interruption/VisualInterruptionRefactor.kt @@ -0,0 +1,46 @@ +/* + * Copyright (C) 2023 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.systemui.statusbar.notification.interruption + +import com.android.systemui.Flags +import com.android.systemui.flags.RefactorFlagUtils + +/** Helper for reading or using the visual interruptions refactor flag state. */ +object VisualInterruptionRefactor { + const val FLAG_NAME = Flags.FLAG_VISUAL_INTERRUPTIONS_REFACTOR + + /** Whether the refactor is enabled */ + @JvmStatic + inline val isEnabled + get() = Flags.visualInterruptionsRefactor() + + /** + * Called to ensure code is only run when the flag is enabled. This protects users from the + * unintended behaviors caused by accidentally running new logic, while also crashing on an eng + * build to ensure that the refactor author catches issues in testing. + */ + @JvmStatic + inline fun isUnexpectedlyInLegacyMode() = + RefactorFlagUtils.isUnexpectedlyInLegacyMode(isEnabled, FLAG_NAME) + + /** + * Called to ensure code is only run when the flag is disabled. This will throw an exception if + * the flag is enabled to ensure that the refactor author catches issues in testing. + */ + @JvmStatic + inline fun assertInLegacyMode() = RefactorFlagUtils.assertInLegacyMode(isEnabled, FLAG_NAME) +} diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/interruption/VisualInterruptionSuppressor.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/interruption/VisualInterruptionSuppressor.kt index 4ef80e38bc63..39199df37bd4 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/interruption/VisualInterruptionSuppressor.kt +++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/interruption/VisualInterruptionSuppressor.kt @@ -13,6 +13,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ + package com.android.systemui.statusbar.notification.interruption import com.android.internal.logging.UiEventLogger.UiEventEnum @@ -50,6 +51,12 @@ sealed interface VisualInterruptionSuppressor { /** An optional UiEvent ID to be recorded when this suppresses an interruption. */ val uiEventId: UiEventEnum? + + /** + * Called after the suppressor is added to the [VisualInterruptionDecisionProvider] but before + * any other methods are called on the suppressor. + */ + fun start() {} } /** A reason why visual interruptions might be suppressed regardless of the notification. */ diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/ui/viewbinder/SharedNotificationContainerBinder.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/ui/viewbinder/SharedNotificationContainerBinder.kt index 2af7181f2f31..6785da4bf4f1 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/ui/viewbinder/SharedNotificationContainerBinder.kt +++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/ui/viewbinder/SharedNotificationContainerBinder.kt @@ -59,10 +59,8 @@ object SharedNotificationContainerBinder { launch { viewModel.position.collect { - controller.updateTopPadding( - it.top, - controller.isAddOrRemoveAnimationPending() - ) + val animate = it.animate || controller.isAddOrRemoveAnimationPending() + controller.updateTopPadding(it.top, animate) } } diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/ui/viewmodel/SharedNotificationContainerViewModel.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/ui/viewmodel/SharedNotificationContainerViewModel.kt index 1229cb9b49ac..b86b5dcc7939 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/ui/viewmodel/SharedNotificationContainerViewModel.kt +++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/ui/viewmodel/SharedNotificationContainerViewModel.kt @@ -25,6 +25,7 @@ import com.android.systemui.shade.domain.interactor.ShadeInteractor import com.android.systemui.statusbar.notification.stack.NotificationStackScrollLayoutController import com.android.systemui.statusbar.notification.stack.NotificationStackSizeCalculator import com.android.systemui.statusbar.notification.stack.domain.interactor.SharedNotificationContainerInteractor +import com.android.systemui.util.kotlin.sample import javax.inject.Inject import kotlinx.coroutines.flow.Flow import kotlinx.coroutines.flow.combine @@ -118,8 +119,15 @@ constructor( } } } else { - interactor.topPosition.map { top -> - keyguardInteractor.sharedNotificationContainerPosition.value.copy(top = top) + interactor.topPosition.sample(shadeInteractor.qsExpansion, ::Pair).map { + (top, qsExpansion) -> + // When QS expansion > 0, it should directly set the top padding so do not + // animate it + val animate = qsExpansion == 0f + keyguardInteractor.sharedNotificationContainerPosition.value.copy( + top = top, + animate = animate + ) } } } diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/ActivityStarterImpl.kt b/packages/SystemUI/src/com/android/systemui/statusbar/phone/ActivityStarterImpl.kt index 2d125462b16e..e1fba2eda1c4 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/ActivityStarterImpl.kt +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/ActivityStarterImpl.kt @@ -494,7 +494,7 @@ constructor( // this runnable is called right after the keyguard is solved, so we tell // WM that we should dismiss it to avoid flickers when opening an activity // that can also be shown over the keyguard. - options.setDismissKeyguard() + options.setDismissKeyguardIfInsecure() options.setDisallowEnterPictureInPictureWhileLaunching( disallowEnterPictureInPictureWhileLaunching ) diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/LightBarTransitionsController.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/LightBarTransitionsController.java index ae70384aa71a..c20732471cf4 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/LightBarTransitionsController.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/LightBarTransitionsController.java @@ -25,6 +25,7 @@ import android.util.MathUtils; import android.util.TimeUtils; import com.android.app.animation.Interpolators; +import com.android.internal.policy.GestureNavigationSettingsObserver; import com.android.systemui.Dumpable; import com.android.systemui.plugins.statusbar.StatusBarStateController; import com.android.systemui.shared.system.QuickStepContract; @@ -95,6 +96,7 @@ public class LightBarTransitionsController implements Dumpable { private final KeyguardStateController mKeyguardStateController; private final StatusBarStateController mStatusBarStateController; private final CommandQueue mCommandQueue; + private final GestureNavigationSettingsObserver mGestureNavigationSettingsObserver; private boolean mTransitionDeferring; private long mTransitionDeferringStartTime; @@ -134,6 +136,8 @@ public class LightBarTransitionsController implements Dumpable { mDozeAmount = mStatusBarStateController.getDozeAmount(); mContext = context; mDisplayId = mContext.getDisplayId(); + mGestureNavigationSettingsObserver = new GestureNavigationSettingsObserver( + mHandler, mContext, null); } /** Call to cleanup the LightBarTransitionsController when done with it. */ @@ -279,7 +283,8 @@ public class LightBarTransitionsController implements Dumpable { */ public boolean supportsIconTintForNavMode(int navigationMode) { // In gesture mode, we already do region sampling to update tint based on content beneath. - return !QuickStepContract.isGesturalMode(navigationMode); + return !QuickStepContract.isGesturalMode(navigationMode) + || mGestureNavigationSettingsObserver.areNavigationButtonForcedVisible(); } /** diff --git a/packages/SystemUI/src/com/android/systemui/stylus/StylusUsiPowerUI.kt b/packages/SystemUI/src/com/android/systemui/stylus/StylusUsiPowerUI.kt index fa9256f82dbd..2797b8d2e2dd 100644 --- a/packages/SystemUI/src/com/android/systemui/stylus/StylusUsiPowerUI.kt +++ b/packages/SystemUI/src/com/android/systemui/stylus/StylusUsiPowerUI.kt @@ -162,6 +162,7 @@ constructor( .setContentText(context.getString(R.string.stylus_battery_low_subtitle)) .setPriority(NotificationCompat.PRIORITY_DEFAULT) .setLocalOnly(true) + .setOnlyAlertOnce(true) .setAutoCancel(true) .build() diff --git a/packages/SystemUI/src/com/android/systemui/volume/VolumeDialogComponent.java b/packages/SystemUI/src/com/android/systemui/volume/VolumeDialogComponent.java index a4537267ed62..d261b08321ca 100644 --- a/packages/SystemUI/src/com/android/systemui/volume/VolumeDialogComponent.java +++ b/packages/SystemUI/src/com/android/systemui/volume/VolumeDialogComponent.java @@ -57,7 +57,7 @@ public class VolumeDialogComponent implements VolumeComponent, TunerService.Tuna public static final String VOLUME_SILENT_DO_NOT_DISTURB = "sysui_do_not_disturb"; private final boolean mDefaultVolumeDownToEnterSilent; - public static final boolean DEFAULT_VOLUME_UP_TO_EXIT_SILENT = false; + public final boolean mDefaultVolumeUpToExitSilent; public static final boolean DEFAULT_DO_NOT_DISTURB_WHEN_SILENT = false; private static final Intent ZEN_SETTINGS = @@ -107,10 +107,12 @@ public class VolumeDialogComponent implements VolumeComponent, TunerService.Tuna mDefaultVolumeDownToEnterSilent = mContext.getResources() .getBoolean(R.bool.config_volume_down_to_enter_silent); + mDefaultVolumeUpToExitSilent = mContext.getResources() + .getBoolean(R.bool.config_volume_up_to_exit_silent); mVolumePolicy = new VolumePolicy( mDefaultVolumeDownToEnterSilent, // volumeDownToEnterSilent - DEFAULT_VOLUME_UP_TO_EXIT_SILENT, // volumeUpToExitSilent + mDefaultVolumeUpToExitSilent, // volumeUpToExitSilent DEFAULT_DO_NOT_DISTURB_WHEN_SILENT, // doNotDisturbWhenSilent 400 // vibrateToSilentDebounce ); @@ -133,7 +135,7 @@ public class VolumeDialogComponent implements VolumeComponent, TunerService.Tuna TunerService.parseIntegerSwitch(newValue, mDefaultVolumeDownToEnterSilent); } else if (VOLUME_UP_SILENT.equals(key)) { volumeUpToExitSilent = - TunerService.parseIntegerSwitch(newValue, DEFAULT_VOLUME_UP_TO_EXIT_SILENT); + TunerService.parseIntegerSwitch(newValue, mDefaultVolumeUpToExitSilent); } else if (VOLUME_SILENT_DO_NOT_DISTURB.equals(key)) { doNotDisturbWhenSilent = TunerService.parseIntegerSwitch(newValue, DEFAULT_DO_NOT_DISTURB_WHEN_SILENT); diff --git a/packages/SystemUI/tests/src/com/android/keyguard/KeyguardClockSwitchControllerBaseTest.java b/packages/SystemUI/tests/src/com/android/keyguard/KeyguardClockSwitchControllerBaseTest.java index 603d548694ec..4a799d8565b8 100644 --- a/packages/SystemUI/tests/src/com/android/keyguard/KeyguardClockSwitchControllerBaseTest.java +++ b/packages/SystemUI/tests/src/com/android/keyguard/KeyguardClockSwitchControllerBaseTest.java @@ -41,6 +41,7 @@ import com.android.systemui.dump.DumpManager; import com.android.systemui.flags.FakeFeatureFlags; import com.android.systemui.keyguard.KeyguardUnlockAnimationController; import com.android.systemui.keyguard.domain.interactor.KeyguardInteractorFactory; +import com.android.systemui.keyguard.ui.viewmodel.KeyguardRootViewModel; import com.android.systemui.log.LogBuffer; import com.android.systemui.plugins.ClockAnimations; import com.android.systemui.plugins.ClockController; @@ -191,6 +192,7 @@ public class KeyguardClockSwitchControllerBaseTest extends SysuiTestCase { mClockEventController, mLogBuffer, mock(NotificationIconContainerAlwaysOnDisplayViewModel.class), + mock(KeyguardRootViewModel.class), mock(ConfigurationState.class), mock(DozeParameters.class), mock(AlwaysOnDisplayNotificationIconViewStore.class), diff --git a/packages/SystemUI/tests/src/com/android/keyguard/KeyguardUpdateMonitorTest.java b/packages/SystemUI/tests/src/com/android/keyguard/KeyguardUpdateMonitorTest.java index 6099ece161b8..776799ec054e 100644 --- a/packages/SystemUI/tests/src/com/android/keyguard/KeyguardUpdateMonitorTest.java +++ b/packages/SystemUI/tests/src/com/android/keyguard/KeyguardUpdateMonitorTest.java @@ -870,6 +870,23 @@ public class KeyguardUpdateMonitorTest extends SysuiTestCase { } @Test + public void whenDetectFingerprint_detectError() { + ArgumentCaptor<FingerprintManager.FingerprintDetectionCallback> fpDetectCallbackCaptor = + ArgumentCaptor.forClass(FingerprintManager.FingerprintDetectionCallback.class); + + givenDetectFingerprintWithClearingFingerprintManagerInvocations(); + verify(mFingerprintManager).detectFingerprint( + any(), fpDetectCallbackCaptor.capture(), any()); + fpDetectCallbackCaptor.getValue().onDetectionError(/* msgId */ 10); + + // THEN verify keyguardUpdateMonitorCallback receives a biometric error + verify(mTestCallback).onBiometricError( + eq(10), eq(""), eq(BiometricSourceType.FINGERPRINT)); + verify(mTestCallback, never()).onBiometricAuthenticated( + anyInt(), any(), anyBoolean()); + } + + @Test public void whenDetectFace_biometricDetectCallback() throws RemoteException { ArgumentCaptor<FaceManager.FaceDetectionCallback> faceDetectCallbackCaptor = ArgumentCaptor.forClass(FaceManager.FaceDetectionCallback.class); @@ -1212,6 +1229,34 @@ public class KeyguardUpdateMonitorTest extends SysuiTestCase { } @Test + public void fpStopsListeningWhenBiometricPromptShows_resumesOnBpHidden() { + // verify AuthController.Callback is added: + ArgumentCaptor<AuthController.Callback> captor = ArgumentCaptor.forClass( + AuthController.Callback.class); + verify(mAuthController).addCallback(captor.capture()); + AuthController.Callback callback = captor.getValue(); + + // GIVEN keyguard showing + mKeyguardUpdateMonitor.dispatchStartedWakingUp(PowerManager.WAKE_REASON_POWER_BUTTON); + mKeyguardUpdateMonitor.setKeyguardShowing(true, false); + + // THEN fingerprint should listen + assertThat(mKeyguardUpdateMonitor.shouldListenForFingerprint(false)).isTrue(); + + // WHEN biometric prompt is shown + callback.onBiometricPromptShown(); + + // THEN shouldn't listen for fingerprint + assertThat(mKeyguardUpdateMonitor.shouldListenForFingerprint(false)).isFalse(); + + // WHEN biometric prompt is dismissed + callback.onBiometricPromptDismissed(); + + // THEN we should listen for fingerprint + assertThat(mKeyguardUpdateMonitor.shouldListenForFingerprint(false)).isTrue(); + } + + @Test public void testTriesToAuthenticate_whenTrustOnAgentKeyguard_ifBypass() { mKeyguardUpdateMonitor.dispatchStartedWakingUp(PowerManager.WAKE_REASON_POWER_BUTTON); mTestableLooper.processAllMessages(); diff --git a/packages/SystemUI/tests/src/com/android/systemui/biometrics/AuthContainerViewTest.kt b/packages/SystemUI/tests/src/com/android/systemui/biometrics/AuthContainerViewTest.kt index f899e2fb968a..5e7b85779599 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/biometrics/AuthContainerViewTest.kt +++ b/packages/SystemUI/tests/src/com/android/systemui/biometrics/AuthContainerViewTest.kt @@ -505,7 +505,6 @@ open class AuthContainerViewTest : SysuiTestCase() { this.authenticators = authenticators } }, - featureFlags, testScope.backgroundScope, fingerprintProps, faceProps, @@ -519,9 +518,7 @@ open class AuthContainerViewTest : SysuiTestCase() { PromptViewModel( displayStateInteractor, promptSelectorInteractor, - vibrator, context, - featureFlags ), { credentialViewModel }, Handler(TestableLooper.get(this).looper), diff --git a/packages/SystemUI/tests/src/com/android/systemui/biometrics/AuthControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/biometrics/AuthControllerTest.java index 885abcb72f1a..11c5d3bb27b3 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/biometrics/AuthControllerTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/biometrics/AuthControllerTest.java @@ -88,7 +88,6 @@ import com.android.systemui.biometrics.domain.interactor.PromptCredentialInterac import com.android.systemui.biometrics.domain.interactor.PromptSelectorInteractor; import com.android.systemui.biometrics.ui.viewmodel.CredentialViewModel; import com.android.systemui.biometrics.ui.viewmodel.PromptViewModel; -import com.android.systemui.flags.FakeFeatureFlags; import com.android.systemui.keyguard.WakefulnessLifecycle; import com.android.systemui.statusbar.CommandQueue; import com.android.systemui.statusbar.VibratorHelper; @@ -195,7 +194,6 @@ public class AuthControllerTest extends SysuiTestCase { private Handler mHandler; private DelayableExecutor mBackgroundExecutor; private TestableAuthController mAuthController; - private FakeFeatureFlags mFeatureFlags = new FakeFeatureFlags(); @Before public void setup() throws RemoteException { @@ -1023,7 +1021,7 @@ public class AuthControllerTest extends SysuiTestCase { private PromptInfo mLastBiometricPromptInfo; TestableAuthController(Context context) { - super(context, mFeatureFlags, null /* applicationCoroutineScope */, + super(context, null /* applicationCoroutineScope */, mExecution, mCommandQueue, mActivityTaskManager, mWindowManager, mFingerprintManager, mFaceManager, () -> mUdfpsController, () -> mSideFpsController, mDisplayManager, mWakefulnessLifecycle, diff --git a/packages/SystemUI/tests/src/com/android/systemui/biometrics/domain/interactor/SideFpsSensorInteractorTest.kt b/packages/SystemUI/tests/src/com/android/systemui/biometrics/domain/interactor/SideFpsSensorInteractorTest.kt index 99501c426e0c..1e7a3d3ef6ff 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/biometrics/domain/interactor/SideFpsSensorInteractorTest.kt +++ b/packages/SystemUI/tests/src/com/android/systemui/biometrics/domain/interactor/SideFpsSensorInteractorTest.kt @@ -26,6 +26,7 @@ import android.view.WindowManager import android.view.WindowMetrics import androidx.test.filters.SmallTest import com.android.systemui.SysuiTestCase +import com.android.systemui.biometrics.FingerprintInteractiveToAuthProvider import com.android.systemui.biometrics.data.repository.FakeFingerprintPropertyRepository import com.android.systemui.biometrics.shared.model.DisplayRotation import com.android.systemui.biometrics.shared.model.DisplayRotation.ROTATION_0 @@ -35,11 +36,14 @@ import com.android.systemui.biometrics.shared.model.DisplayRotation.ROTATION_90 import com.android.systemui.biometrics.shared.model.FingerprintSensorType import com.android.systemui.biometrics.shared.model.SensorStrength import com.android.systemui.coroutines.collectLastValue +import com.android.systemui.dump.logcatLogBuffer import com.android.systemui.flags.FakeFeatureFlagsClassic import com.android.systemui.flags.Flags.REST_TO_UNLOCK +import com.android.systemui.log.SideFpsLogger import com.android.systemui.res.R import com.android.systemui.util.mockito.whenever import com.google.common.truth.Truth.assertThat +import java.util.Optional import kotlinx.coroutines.ExperimentalCoroutinesApi import kotlinx.coroutines.flow.MutableStateFlow import kotlinx.coroutines.test.StandardTestDispatcher @@ -62,7 +66,7 @@ import org.mockito.junit.MockitoJUnit class SideFpsSensorInteractorTest : SysuiTestCase() { @JvmField @Rule var mockitoRule = MockitoJUnit.rule() - private lateinit var testScope: TestScope + private val testScope = TestScope(StandardTestDispatcher()) private val fingerprintRepository = FakeFingerprintPropertyRepository() @@ -70,32 +74,38 @@ class SideFpsSensorInteractorTest : SysuiTestCase() { @Mock private lateinit var windowManager: WindowManager @Mock private lateinit var displayStateInteractor: DisplayStateInteractor - + @Mock + private lateinit var fingerprintInteractiveToAuthProvider: FingerprintInteractiveToAuthProvider + private val isRestToUnlockEnabled = MutableStateFlow(false) private val contextDisplayInfo = DisplayInfo() private val displayChangeEvent = MutableStateFlow(0) private val currentRotation = MutableStateFlow(ROTATION_0) @Before fun setup() { - testScope = TestScope(StandardTestDispatcher()) mContext = spy(mContext) - val displayManager = mock(DisplayManagerGlobal::class.java) val resources = mContext.resources whenever(mContext.display) - .thenReturn(Display(displayManager, 1, contextDisplayInfo, resources)) + .thenReturn( + Display(mock(DisplayManagerGlobal::class.java), 1, contextDisplayInfo, resources) + ) whenever(displayStateInteractor.displayChanges).thenReturn(displayChangeEvent) whenever(displayStateInteractor.currentRotation).thenReturn(currentRotation) contextDisplayInfo.uniqueId = "current-display" - + val featureFlags = FakeFeatureFlagsClassic().apply { set(REST_TO_UNLOCK, true) } + whenever(fingerprintInteractiveToAuthProvider.enabledForCurrentUser) + .thenReturn(isRestToUnlockEnabled) underTest = SideFpsSensorInteractor( mContext, fingerprintRepository, windowManager, displayStateInteractor, - FakeFeatureFlagsClassic().apply { set(REST_TO_UNLOCK, true) } + featureFlags, + Optional.of(fingerprintInteractiveToAuthProvider), + SideFpsLogger(logcatLogBuffer("SfpsLogger")) ) } @@ -348,6 +358,21 @@ class SideFpsSensorInteractorTest : SysuiTestCase() { assertThat(sensorLocation!!.width).isEqualTo(100) } + @Test + fun isProlongedTouchRequiredForAuthentication_dependsOnSettingsToggle() = + testScope.runTest { + val isEnabled by collectLastValue(underTest.isProlongedTouchRequiredForAuthentication) + setupFingerprint(FingerprintSensorType.POWER_BUTTON) + + isRestToUnlockEnabled.value = true + runCurrent() + assertThat(isEnabled).isTrue() + + isRestToUnlockEnabled.value = false + runCurrent() + assertThat(isEnabled).isFalse() + } + private suspend fun TestScope.setupFPLocationAndDisplaySize( width: Int, height: Int, diff --git a/packages/SystemUI/tests/src/com/android/systemui/biometrics/ui/viewmodel/PromptViewModelTest.kt b/packages/SystemUI/tests/src/com/android/systemui/biometrics/ui/viewmodel/PromptViewModelTest.kt index b695a0ee1fa3..d06cbbb5e433 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/biometrics/ui/viewmodel/PromptViewModelTest.kt +++ b/packages/SystemUI/tests/src/com/android/systemui/biometrics/ui/viewmodel/PromptViewModelTest.kt @@ -44,18 +44,16 @@ import com.android.systemui.biometrics.shared.model.toSensorType import com.android.systemui.coroutines.collectLastValue import com.android.systemui.coroutines.collectValues import com.android.systemui.display.data.repository.FakeDisplayRepository -import com.android.systemui.flags.FakeFeatureFlags -import com.android.systemui.flags.Flags.ONE_WAY_HAPTICS_API_MIGRATION import com.android.systemui.res.R import com.android.systemui.statusbar.VibratorHelper import com.android.systemui.util.concurrency.FakeExecutor -import com.android.systemui.util.mockito.any import com.android.systemui.util.time.FakeSystemClock import com.google.common.truth.Truth.assertThat import kotlinx.coroutines.ExperimentalCoroutinesApi import kotlinx.coroutines.flow.first import kotlinx.coroutines.launch import kotlinx.coroutines.test.TestScope +import kotlinx.coroutines.test.advanceUntilIdle import kotlinx.coroutines.test.runCurrent import kotlinx.coroutines.test.runTest import org.junit.Before @@ -64,9 +62,7 @@ import org.junit.Test import org.junit.runner.RunWith import org.junit.runners.Parameterized import org.mockito.Mock -import org.mockito.Mockito.never import org.mockito.Mockito.times -import org.mockito.Mockito.verify import org.mockito.junit.MockitoJUnit private const val USER_ID = 4 @@ -95,7 +91,6 @@ internal class PromptViewModelTest(private val testCase: TestCase) : SysuiTestCa private lateinit var selector: PromptSelectorInteractor private lateinit var viewModel: PromptViewModel private lateinit var iconViewModel: PromptIconViewModel - private val featureFlags = FakeFeatureFlags() @Before fun setup() { @@ -125,10 +120,8 @@ internal class PromptViewModelTest(private val testCase: TestCase) : SysuiTestCa PromptSelectorInteractorImpl(fingerprintRepository, promptRepository, lockPatternUtils) selector.resetPrompt() - viewModel = - PromptViewModel(displayStateInteractor, selector, vibrator, mContext, featureFlags) + viewModel = PromptViewModel(displayStateInteractor, selector, mContext) iconViewModel = viewModel.iconViewModel - featureFlags.set(ONE_WAY_HAPTICS_API_MIGRATION, false) } @Test @@ -180,26 +173,29 @@ internal class PromptViewModelTest(private val testCase: TestCase) : SysuiTestCa } @Test - fun play_haptic_on_confirm_when_confirmation_required_otherwise_on_authenticated() = + fun set_haptic_on_confirm_when_confirmation_required_otherwise_on_authenticated() = runGenericTest { val expectConfirmation = testCase.expectConfirmation(atLeastOneFailure = false) viewModel.showAuthenticated(testCase.authenticatedModality, 1_000L) - verify(vibrator, if (expectConfirmation) never() else times(1)) - .vibrateAuthSuccess(any()) + val confirmConstant by collectLastValue(viewModel.hapticsToPlay) + assertThat(confirmConstant) + .isEqualTo( + if (expectConfirmation) HapticFeedbackConstants.NO_HAPTICS + else HapticFeedbackConstants.CONFIRM + ) if (expectConfirmation) { viewModel.confirmAuthenticated() } - verify(vibrator).vibrateAuthSuccess(any()) - verify(vibrator, never()).vibrateAuthError(any()) + val confirmedConstant by collectLastValue(viewModel.hapticsToPlay) + assertThat(confirmedConstant).isEqualTo(HapticFeedbackConstants.CONFIRM) } @Test - fun playSuccessHaptic_onwayHapticsEnabled_SetsConfirmConstant() = runGenericTest { - featureFlags.set(ONE_WAY_HAPTICS_API_MIGRATION, true) + fun playSuccessHaptic_SetsConfirmConstant() = runGenericTest { val expectConfirmation = testCase.expectConfirmation(atLeastOneFailure = false) viewModel.showAuthenticated(testCase.authenticatedModality, 1_000L) @@ -212,8 +208,7 @@ internal class PromptViewModelTest(private val testCase: TestCase) : SysuiTestCa } @Test - fun playErrorHaptic_onwayHapticsEnabled_SetsRejectConstant() = runGenericTest { - featureFlags.set(ONE_WAY_HAPTICS_API_MIGRATION, true) + fun playErrorHaptic_SetsRejectConstant() = runGenericTest { viewModel.showTemporaryError("test", "messageAfterError", false) val currentConstant by collectLastValue(viewModel.hapticsToPlay) @@ -251,7 +246,8 @@ internal class PromptViewModelTest(private val testCase: TestCase) : SysuiTestCa DisplayRotation.ROTATION_180 -> R.raw.biometricprompt_fingerprint_to_error_landscape DisplayRotation.ROTATION_270 -> - R.raw.biometricprompt_symbol_fingerprint_to_error_portrait_bottomright + R.raw + .biometricprompt_symbol_fingerprint_to_error_portrait_bottomright else -> throw Exception("invalid rotation") } assertThat(iconOverlayAsset).isEqualTo(expectedOverlayAsset) @@ -496,7 +492,8 @@ internal class PromptViewModelTest(private val testCase: TestCase) : SysuiTestCa DisplayRotation.ROTATION_180 -> R.raw.biometricprompt_symbol_fingerprint_to_success_landscape DisplayRotation.ROTATION_270 -> - R.raw.biometricprompt_symbol_fingerprint_to_success_portrait_bottomright + R.raw + .biometricprompt_symbol_fingerprint_to_success_portrait_bottomright else -> throw Exception("invalid rotation") } assertThat(iconOverlayAsset).isEqualTo(expectedOverlayAsset) @@ -733,7 +730,7 @@ internal class PromptViewModelTest(private val testCase: TestCase) : SysuiTestCa } @Test - fun plays_haptic_on_errors() = runGenericTest { + fun set_haptic_on_errors() = runGenericTest { viewModel.showTemporaryError( "so sad", messageAfterError = "", @@ -741,8 +738,8 @@ internal class PromptViewModelTest(private val testCase: TestCase) : SysuiTestCa hapticFeedback = true, ) - verify(vibrator).vibrateAuthError(any()) - verify(vibrator, never()).vibrateAuthSuccess(any()) + val constant by collectLastValue(viewModel.hapticsToPlay) + assertThat(constant).isEqualTo(HapticFeedbackConstants.REJECT) } @Test @@ -754,8 +751,8 @@ internal class PromptViewModelTest(private val testCase: TestCase) : SysuiTestCa hapticFeedback = false, ) - verify(vibrator, never()).vibrateAuthError(any()) - verify(vibrator, never()).vibrateAuthSuccess(any()) + val constant by collectLastValue(viewModel.hapticsToPlay) + assertThat(constant).isEqualTo(HapticFeedbackConstants.NO_HAPTICS) } private suspend fun TestScope.showTemporaryErrors( diff --git a/packages/SystemUI/tests/src/com/android/systemui/classifier/FalsingCollectorImplTest.java b/packages/SystemUI/tests/src/com/android/systemui/classifier/FalsingCollectorImplTest.java index 80fe9e762832..fcb18f52086d 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/classifier/FalsingCollectorImplTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/classifier/FalsingCollectorImplTest.java @@ -26,6 +26,7 @@ import static org.mockito.Mockito.verify; import static org.mockito.Mockito.when; import android.testing.AndroidTestingRunner; +import android.testing.TestableLooper; import android.view.MotionEvent; import androidx.test.filters.SmallTest; @@ -35,13 +36,14 @@ import com.android.systemui.SysuiTestCase; import com.android.systemui.dock.DockManager; import com.android.systemui.dock.DockManagerFake; import com.android.systemui.plugins.statusbar.StatusBarStateController; -import com.android.systemui.shade.ShadeExpansionStateManager; +import com.android.systemui.shade.domain.interactor.ShadeInteractor; import com.android.systemui.statusbar.StatusBarState; import com.android.systemui.statusbar.SysuiStatusBarStateController; import com.android.systemui.statusbar.policy.BatteryController; import com.android.systemui.statusbar.policy.KeyguardStateController; import com.android.systemui.user.domain.interactor.SelectedUserInteractor; import com.android.systemui.util.concurrency.FakeExecutor; +import com.android.systemui.util.kotlin.JavaAdapter; import com.android.systemui.util.sensors.ProximitySensor; import com.android.systemui.util.sensors.ThresholdSensor; import com.android.systemui.util.time.FakeSystemClock; @@ -54,8 +56,11 @@ import org.mockito.InOrder; import org.mockito.Mock; import org.mockito.MockitoAnnotations; +import kotlinx.coroutines.flow.StateFlowKt; + @SmallTest @RunWith(AndroidTestingRunner.class) +@TestableLooper.RunWithLooper(setAsMainLooper = true) public class FalsingCollectorImplTest extends SysuiTestCase { private FalsingCollectorImpl mFalsingCollector; @@ -73,7 +78,9 @@ public class FalsingCollectorImplTest extends SysuiTestCase { @Mock private KeyguardStateController mKeyguardStateController; @Mock - private ShadeExpansionStateManager mShadeExpansionStateManager; + private ShadeInteractor mShadeInteractor; + @Mock + private JavaAdapter mJavaAdapter; @Mock private BatteryController mBatteryController; @Mock @@ -88,12 +95,16 @@ public class FalsingCollectorImplTest extends SysuiTestCase { when(mStatusBarStateController.getState()).thenReturn(StatusBarState.KEYGUARD); when(mKeyguardStateController.isShowing()).thenReturn(true); + when(mShadeInteractor.isQsExpanded()).thenReturn(StateFlowKt.MutableStateFlow(false)); mFalsingCollector = new FalsingCollectorImpl(mFalsingDataProvider, mFalsingManager, mKeyguardUpdateMonitor, mHistoryTracker, mProximitySensor, - mStatusBarStateController, mKeyguardStateController, mShadeExpansionStateManager, - mBatteryController, - mDockManager, mFakeExecutor, mFakeSystemClock, () -> mSelectedUserInteractor); + mStatusBarStateController, mKeyguardStateController, + () -> mShadeInteractor, mBatteryController, + mDockManager, mFakeExecutor, + mJavaAdapter, mFakeSystemClock, () -> mSelectedUserInteractor + ); + mFalsingCollector.init(); } @Test diff --git a/packages/SystemUI/tests/src/com/android/systemui/controls/controller/ControlActionCoordinatorImplTest.kt b/packages/SystemUI/tests/src/com/android/systemui/controls/controller/ControlActionCoordinatorImplTest.kt index 8416c46a3f38..6a79ee8553c5 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/controls/controller/ControlActionCoordinatorImplTest.kt +++ b/packages/SystemUI/tests/src/com/android/systemui/controls/controller/ControlActionCoordinatorImplTest.kt @@ -24,8 +24,6 @@ import com.android.systemui.broadcast.BroadcastSender import com.android.systemui.controls.ControlsMetricsLogger import com.android.systemui.controls.settings.ControlsSettingsDialogManager import com.android.systemui.controls.settings.FakeControlsSettingsRepository -import com.android.systemui.flags.FakeFeatureFlags -import com.android.systemui.flags.Flags.ONE_WAY_HAPTICS_API_MIGRATION import com.android.systemui.plugins.ActivityStarter import com.android.systemui.statusbar.VibratorHelper import com.android.systemui.statusbar.policy.KeyguardStateController @@ -83,8 +81,6 @@ class ControlActionCoordinatorImplTest : SysuiTestCase() { private lateinit var action: ControlActionCoordinatorImpl.Action private lateinit var controlsSettingsRepository: FakeControlsSettingsRepository - private val featureFlags = FakeFeatureFlags() - @Before fun setUp() { MockitoAnnotations.initMocks(this) @@ -104,7 +100,6 @@ class ControlActionCoordinatorImplTest : SysuiTestCase() { metricsLogger, vibratorHelper, controlsSettingsRepository, - featureFlags )) coordinator.activityContext = mContext @@ -200,31 +195,7 @@ class ControlActionCoordinatorImplTest : SysuiTestCase() { } @Test - fun drag_isEdge_oneWayHapticsDisabled_usesVibrate() { - featureFlags.set(ONE_WAY_HAPTICS_API_MIGRATION, false) - - coordinator.drag(cvh, true) - - verify(vibratorHelper).vibrate( - Vibrations.rangeEdgeEffect - ) - } - - @Test - fun drag_isNotEdge_oneWayHapticsDisabled_usesVibrate() { - featureFlags.set(ONE_WAY_HAPTICS_API_MIGRATION, false) - - coordinator.drag(cvh, false) - - verify(vibratorHelper).vibrate( - Vibrations.rangeMiddleEffect - ) - } - - @Test - fun drag_isEdge_oneWayHapticsEnabled_usesPerformHapticFeedback() { - featureFlags.set(ONE_WAY_HAPTICS_API_MIGRATION, true) - + fun drag_isEdge_performsSegmentTickHaptics() { coordinator.drag(cvh, true) verify(vibratorHelper).performHapticFeedback( @@ -234,9 +205,7 @@ class ControlActionCoordinatorImplTest : SysuiTestCase() { } @Test - fun drag_isNotEdge_oneWayHapticsEnabled_usesPerformHapticFeedback() { - featureFlags.set(ONE_WAY_HAPTICS_API_MIGRATION, true) - + fun drag_isNotEdge_performsFrequentTickHaptics() { coordinator.drag(cvh, false) verify(vibratorHelper).performHapticFeedback( diff --git a/packages/SystemUI/tests/src/com/android/systemui/keyguard/KeyguardViewMediatorTest.java b/packages/SystemUI/tests/src/com/android/systemui/keyguard/KeyguardViewMediatorTest.java index 2b280c05ba1b..814a317a72f8 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/keyguard/KeyguardViewMediatorTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/keyguard/KeyguardViewMediatorTest.java @@ -253,7 +253,6 @@ public class KeyguardViewMediatorTest extends SysuiTestCase { mKeyguardStateController, mScreenOffAnimationController, mAuthController, - mShadeExpansionStateManager, () -> mShadeInteractor, mShadeWindowLogger, () -> mSelectedUserInteractor); diff --git a/packages/SystemUI/tests/src/com/android/systemui/keyguard/ui/viewmodel/KeyguardRootViewModelTest.kt b/packages/SystemUI/tests/src/com/android/systemui/keyguard/ui/viewmodel/KeyguardRootViewModelTest.kt index 4f545cb0e288..4a1386e21e2a 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/keyguard/ui/viewmodel/KeyguardRootViewModelTest.kt +++ b/packages/SystemUI/tests/src/com/android/systemui/keyguard/ui/viewmodel/KeyguardRootViewModelTest.kt @@ -15,16 +15,24 @@ * */ +@file:OptIn(ExperimentalCoroutinesApi::class) + package com.android.systemui.keyguard.ui.viewmodel import android.view.View import androidx.test.filters.SmallTest +import com.android.SysUITestModule +import com.android.TestMocksModule import com.android.systemui.SysuiTestCase import com.android.systemui.common.ui.data.repository.FakeConfigurationRepository import com.android.systemui.coroutines.collectLastValue -import com.android.systemui.flags.FakeFeatureFlags +import com.android.systemui.dagger.SysUISingleton +import com.android.systemui.deviceentry.data.repository.FakeDeviceEntryRepository +import com.android.systemui.flags.FakeFeatureFlagsClassic +import com.android.systemui.flags.FakeFeatureFlagsClassicModule import com.android.systemui.flags.Flags import com.android.systemui.keyguard.data.repository.FakeKeyguardRepository +import com.android.systemui.keyguard.data.repository.FakeKeyguardTransitionRepository import com.android.systemui.keyguard.domain.interactor.BurnInInteractor import com.android.systemui.keyguard.domain.interactor.KeyguardInteractor import com.android.systemui.keyguard.domain.interactor.KeyguardInteractorFactory @@ -33,14 +41,25 @@ import com.android.systemui.keyguard.shared.model.BurnInModel import com.android.systemui.keyguard.shared.model.KeyguardState import com.android.systemui.keyguard.shared.model.TransitionStep import com.android.systemui.plugins.ClockController +import com.android.systemui.statusbar.notification.data.repository.FakeNotificationsKeyguardViewStateRepository +import com.android.systemui.statusbar.phone.DozeParameters +import com.android.systemui.statusbar.phone.ScreenOffAnimationController +import com.android.systemui.util.mockito.mock import com.android.systemui.util.mockito.whenever +import com.android.systemui.util.ui.isAnimating +import com.android.systemui.util.ui.stopAnimating +import com.android.systemui.util.ui.value import com.google.common.truth.Truth.assertThat +import dagger.BindsInstance +import dagger.Component import javax.inject.Provider +import kotlinx.coroutines.ExperimentalCoroutinesApi import kotlinx.coroutines.flow.MutableSharedFlow import kotlinx.coroutines.flow.MutableStateFlow import kotlinx.coroutines.flow.emptyFlow import kotlinx.coroutines.test.StandardTestDispatcher import kotlinx.coroutines.test.TestScope +import kotlinx.coroutines.test.runCurrent import kotlinx.coroutines.test.runTest import org.junit.Before import org.junit.Test @@ -48,7 +67,10 @@ import org.junit.runner.RunWith import org.junit.runners.JUnit4 import org.mockito.Answers import org.mockito.Mock +import org.mockito.Mockito.RETURNS_DEEP_STUBS import org.mockito.Mockito.anyInt +import org.mockito.Mockito.reset +import org.mockito.Mockito.withSettings import org.mockito.MockitoAnnotations @SmallTest @@ -81,7 +103,7 @@ class KeyguardRootViewModelTest : SysuiTestCase() { MockitoAnnotations.initMocks(this) val featureFlags = - FakeFeatureFlags().apply { + FakeFeatureFlagsClassic().apply { set(Flags.MIGRATE_SPLIT_KEYGUARD_BOTTOM_AREA, true) set(Flags.FACE_AUTH_REFACTOR, true) } @@ -107,11 +129,21 @@ class KeyguardRootViewModelTest : SysuiTestCase() { underTest = KeyguardRootViewModel( context, + deviceEntryInteractor = + mock { whenever(isBypassEnabled).thenReturn(MutableStateFlow(false)) }, + dozeParameters = mock(), + featureFlags, keyguardInteractor, + keyguardTransitionInteractor, + notificationsKeyguardInteractor = + mock { + whenever(areNotificationsFullyHidden).thenReturn(emptyFlow()) + whenever(isPulseExpanding).thenReturn(emptyFlow()) + }, burnInInteractor, goneToAodTransitionViewModel, aodToLockscreenTransitionViewModel, - keyguardTransitionInteractor, + screenOffAnimationController = mock(), ) underTest.clockControllerProvider = Provider { clockController } } @@ -179,6 +211,8 @@ class KeyguardRootViewModelTest : SysuiTestCase() { val translationY by collectLastValue(underTest.translationY) val scale by collectLastValue(underTest.scale) + underTest.statusViewTop = 100 + // Set to dozing (on AOD) dozeAmountTransitionStep.emit(TransitionStep(value = 1f)) // Trigger a change to the burn-in model @@ -200,6 +234,37 @@ class KeyguardRootViewModelTest : SysuiTestCase() { } @Test + fun translationAndScaleFromBurnFullyDozingStaysOutOfTopInset() = + testScope.runTest { + val translationX by collectLastValue(underTest.translationX) + val translationY by collectLastValue(underTest.translationY) + val scale by collectLastValue(underTest.scale) + + underTest.statusViewTop = 100 + underTest.topInset = 80 + + // Set to dozing (on AOD) + dozeAmountTransitionStep.emit(TransitionStep(value = 1f)) + // Trigger a change to the burn-in model + burnInFlow.value = + BurnInModel( + translationX = 20, + translationY = -30, + scale = 0.5f, + ) + assertThat(translationX).isEqualTo(20) + // -20 instead of -30, due to inset of 80 + assertThat(translationY).isEqualTo(-20) + assertThat(scale).isEqualTo(Pair(0.5f, true /* scaleClockOnly */)) + + // Set to the beginning of GONE->AOD transition + goneToAodTransitionStep.emit(TransitionStep(value = 0f)) + assertThat(translationX).isEqualTo(0) + assertThat(translationY).isEqualTo(0) + assertThat(scale).isEqualTo(Pair(1f, true /* scaleClockOnly */)) + } + + @Test fun translationAndScaleFromBurnInUseScaleOnly() = testScope.runTest { whenever(clockController.config.useAlternateSmartspaceAODTransition).thenReturn(true) @@ -248,3 +313,169 @@ class KeyguardRootViewModelTest : SysuiTestCase() { assertThat(burnInLayerAlpha).isEqualTo(1f) } } + +@SmallTest +class KeyguardRootViewModelTestWithFakes : SysuiTestCase() { + + @Component(modules = [SysUITestModule::class]) + @SysUISingleton + interface TestComponent { + val underTest: KeyguardRootViewModel + val deviceEntryRepository: FakeDeviceEntryRepository + val notifsKeyguardRepository: FakeNotificationsKeyguardViewStateRepository + val repository: FakeKeyguardRepository + val testScope: TestScope + val transitionRepository: FakeKeyguardTransitionRepository + + @Component.Factory + interface Factory { + fun create( + @BindsInstance test: SysuiTestCase, + featureFlags: FakeFeatureFlagsClassicModule, + mocks: TestMocksModule, + ): TestComponent + } + } + + private val clockController: ClockController = + mock(withSettings().defaultAnswer(RETURNS_DEEP_STUBS)) + private val dozeParams: DozeParameters = mock() + private val screenOffAnimController: ScreenOffAnimationController = mock() + + private fun runTest(block: suspend TestComponent.() -> Unit): Unit = + DaggerKeyguardRootViewModelTestWithFakes_TestComponent.factory() + .create( + test = this, + featureFlags = + FakeFeatureFlagsClassicModule { + setDefault(Flags.NEW_AOD_TRANSITION) + set(Flags.MIGRATE_SPLIT_KEYGUARD_BOTTOM_AREA, true) + set(Flags.FACE_AUTH_REFACTOR, true) + }, + mocks = + TestMocksModule( + dozeParameters = dozeParams, + screenOffAnimationController = screenOffAnimController, + ) + ) + .run { + reset(clockController) + underTest.clockControllerProvider = Provider { clockController } + testScope.runTest { + runCurrent() + block() + } + } + + @Test + fun iconContainer_isNotVisible_notOnKeyguard_dontShowAodIconsWhenShade() = runTest { + val isVisible by testScope.collectLastValue(underTest.isNotifIconContainerVisible) + testScope.runCurrent() + transitionRepository.sendTransitionSteps( + from = KeyguardState.OFF, + to = KeyguardState.GONE, + testScope, + ) + whenever(screenOffAnimController.shouldShowAodIconsWhenShade()).thenReturn(false) + testScope.runCurrent() + + assertThat(isVisible?.value).isFalse() + assertThat(isVisible?.isAnimating).isFalse() + } + + @Test + fun iconContainer_isVisible_bypassEnabled() = runTest { + val isVisible by testScope.collectLastValue(underTest.isNotifIconContainerVisible) + testScope.runCurrent() + deviceEntryRepository.setBypassEnabled(true) + testScope.runCurrent() + + assertThat(isVisible?.value).isTrue() + } + + @Test + fun iconContainer_isNotVisible_pulseExpanding_notBypassing() = runTest { + val isVisible by testScope.collectLastValue(underTest.isNotifIconContainerVisible) + testScope.runCurrent() + notifsKeyguardRepository.setPulseExpanding(true) + deviceEntryRepository.setBypassEnabled(false) + testScope.runCurrent() + + assertThat(isVisible?.value).isEqualTo(false) + } + + @Test + fun iconContainer_isVisible_notifsFullyHidden_bypassEnabled() = runTest { + val isVisible by testScope.collectLastValue(underTest.isNotifIconContainerVisible) + testScope.runCurrent() + notifsKeyguardRepository.setPulseExpanding(false) + deviceEntryRepository.setBypassEnabled(true) + notifsKeyguardRepository.setNotificationsFullyHidden(true) + testScope.runCurrent() + + assertThat(isVisible?.value).isTrue() + assertThat(isVisible?.isAnimating).isTrue() + } + + @Test + fun iconContainer_isVisible_notifsFullyHidden_bypassDisabled_aodDisabled() = runTest { + val isVisible by testScope.collectLastValue(underTest.isNotifIconContainerVisible) + testScope.runCurrent() + notifsKeyguardRepository.setPulseExpanding(false) + deviceEntryRepository.setBypassEnabled(false) + whenever(dozeParams.alwaysOn).thenReturn(false) + notifsKeyguardRepository.setNotificationsFullyHidden(true) + testScope.runCurrent() + + assertThat(isVisible?.value).isTrue() + assertThat(isVisible?.isAnimating).isFalse() + } + + @Test + fun iconContainer_isVisible_notifsFullyHidden_bypassDisabled_displayNeedsBlanking() = runTest { + val isVisible by testScope.collectLastValue(underTest.isNotifIconContainerVisible) + testScope.runCurrent() + notifsKeyguardRepository.setPulseExpanding(false) + deviceEntryRepository.setBypassEnabled(false) + whenever(dozeParams.alwaysOn).thenReturn(true) + whenever(dozeParams.displayNeedsBlanking).thenReturn(true) + notifsKeyguardRepository.setNotificationsFullyHidden(true) + testScope.runCurrent() + + assertThat(isVisible?.value).isTrue() + assertThat(isVisible?.isAnimating).isFalse() + } + + @Test + fun iconContainer_isVisible_notifsFullyHidden_bypassDisabled() = runTest { + val isVisible by testScope.collectLastValue(underTest.isNotifIconContainerVisible) + testScope.runCurrent() + notifsKeyguardRepository.setPulseExpanding(false) + deviceEntryRepository.setBypassEnabled(false) + whenever(dozeParams.alwaysOn).thenReturn(true) + whenever(dozeParams.displayNeedsBlanking).thenReturn(false) + notifsKeyguardRepository.setNotificationsFullyHidden(true) + testScope.runCurrent() + + assertThat(isVisible?.value).isTrue() + assertThat(isVisible?.isAnimating).isTrue() + } + + @Test + fun isIconContainerVisible_stopAnimation() = runTest { + val isVisible by testScope.collectLastValue(underTest.isNotifIconContainerVisible) + testScope.runCurrent() + notifsKeyguardRepository.setPulseExpanding(false) + deviceEntryRepository.setBypassEnabled(false) + whenever(dozeParams.alwaysOn).thenReturn(true) + whenever(dozeParams.displayNeedsBlanking).thenReturn(false) + notifsKeyguardRepository.setNotificationsFullyHidden(true) + testScope.runCurrent() + + assertThat(isVisible?.isAnimating).isEqualTo(true) + isVisible?.stopAnimating() + testScope.runCurrent() + + assertThat(isVisible?.isAnimating).isEqualTo(false) + } +} diff --git a/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/impl/custom/CustomTileDefaultsRepositoryTest.kt b/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/impl/custom/CustomTileDefaultsRepositoryTest.kt new file mode 100644 index 000000000000..89ba69fce9ad --- /dev/null +++ b/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/impl/custom/CustomTileDefaultsRepositoryTest.kt @@ -0,0 +1,259 @@ +/* + * Copyright (C) 2023 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.systemui.qs.tiles.impl.custom + +import android.content.ComponentName +import android.content.Context +import android.content.pm.ApplicationInfo +import android.content.pm.PackageManager +import android.content.pm.ServiceInfo +import android.os.UserHandle +import androidx.test.ext.junit.runners.AndroidJUnit4 +import androidx.test.filters.SmallTest +import com.android.systemui.SysuiTestCase +import com.android.systemui.qs.tiles.impl.custom.data.entity.CustomTileDefaults +import com.android.systemui.qs.tiles.impl.custom.data.repository.CustomTileDefaultsRepository +import com.android.systemui.qs.tiles.impl.custom.data.repository.CustomTileDefaultsRepositoryImpl +import com.android.systemui.util.mockito.any +import com.android.systemui.util.mockito.eq +import com.android.systemui.util.mockito.whenever +import com.google.common.truth.Truth.assertThat +import kotlinx.coroutines.ExperimentalCoroutinesApi +import kotlinx.coroutines.Job +import kotlinx.coroutines.flow.first +import kotlinx.coroutines.flow.launchIn +import kotlinx.coroutines.flow.map +import kotlinx.coroutines.launch +import kotlinx.coroutines.test.StandardTestDispatcher +import kotlinx.coroutines.test.TestScope +import kotlinx.coroutines.test.runCurrent +import kotlinx.coroutines.test.runTest +import org.junit.Before +import org.junit.Test +import org.junit.runner.RunWith +import org.mockito.Mock +import org.mockito.MockitoAnnotations + +@SmallTest +@RunWith(AndroidJUnit4::class) +@OptIn(ExperimentalCoroutinesApi::class) +class CustomTileDefaultsRepositoryTest : SysuiTestCase() { + + @Mock private lateinit var sysuiContext: Context + @Mock private lateinit var user1Context: Context + @Mock private lateinit var user2Context: Context + @Mock private lateinit var packageManager1: PackageManager + @Mock private lateinit var packageManager2: PackageManager + + private val testDispatcher = StandardTestDispatcher() + private val testScope = TestScope(testDispatcher) + + private lateinit var underTest: CustomTileDefaultsRepository + + @Before + fun setup() { + MockitoAnnotations.initMocks(this) + + whenever(sysuiContext.createContextAsUser(eq(USER_1), any())).thenReturn(user1Context) + whenever(user1Context.packageManager).thenReturn(packageManager1) + packageManager1.setupApp1() + + whenever(sysuiContext.createContextAsUser(eq(USER_2), any())).thenReturn(user2Context) + whenever(user2Context.packageManager).thenReturn(packageManager2) + packageManager2.setupApp2() + + underTest = + CustomTileDefaultsRepositoryImpl( + sysuiContext, + testScope.backgroundScope, + testDispatcher, + ) + } + + @Test + fun regularRequestingEmitsTheNewDefault() = + testScope.runTest { + underTest.requestNewDefaults(USER_1, COMPONENT_NAME_1, false) + + runCurrent() + + val default = underTest.defaults(USER_1).first() as CustomTileDefaults.Result + assertThat(default.label).isEqualTo(APP_LABEL_1) + assertThat(default.icon.resId).isEqualTo(SERVICE_ICON_1) + assertThat(default.icon.resPackage).isEqualTo(COMPONENT_NAME_1.packageName) + } + + @Test + fun requestingSystemAppEmitsTheNewDefault() = + testScope.runTest { + underTest.requestNewDefaults(USER_1, COMPONENT_NAME_1, false) + + runCurrent() + + val default = underTest.defaults(USER_1).first() as CustomTileDefaults.Result + assertThat(default.label).isEqualTo(APP_LABEL_1) + assertThat(default.icon.resId).isEqualTo(SERVICE_ICON_1) + assertThat(default.icon.resPackage).isEqualTo(COMPONENT_NAME_1.packageName) + } + + @Test + fun requestingForcesTheNewEmit() = + testScope.runTest { + val defaults = mutableListOf<CustomTileDefaults.Result>() + backgroundScope.launch { + underTest + .defaults(USER_1) + .map { it as CustomTileDefaults.Result } + .collect { defaults.add(it) } + } + underTest.requestNewDefaults(USER_1, COMPONENT_NAME_1, false) + // the same request should be skipped. This leads to 2 result in assertions + underTest.requestNewDefaults(USER_1, COMPONENT_NAME_1, false) + runCurrent() + + underTest.requestNewDefaults(USER_1, COMPONENT_NAME_1, true) + runCurrent() + + assertThat(defaults).hasSize(2) + assertThat(defaults.last().label).isEqualTo(APP_LABEL_1) + assertThat(defaults.last().icon.resId).isEqualTo(SERVICE_ICON_1) + assertThat(defaults.last().icon.resPackage).isEqualTo(COMPONENT_NAME_1.packageName) + } + + @Test + fun userChangeForcesTheNewEmit() = + testScope.runTest { + underTest.requestNewDefaults(USER_1, COMPONENT_NAME_1, false) + underTest.requestNewDefaults(USER_1, COMPONENT_NAME_1, false) + runCurrent() + + underTest.requestNewDefaults(USER_2, COMPONENT_NAME_2, false) + runCurrent() + + val default = underTest.defaults(USER_2).first() as CustomTileDefaults.Result + assertThat(default.label).isEqualTo(APP_LABEL_2) + assertThat(default.icon.resId).isEqualTo(SERVICE_ICON_2) + assertThat(default.icon.resPackage).isEqualTo(COMPONENT_NAME_2.packageName) + } + + @Test + fun componentNameChangeForcesTheNewEmit() = + testScope.runTest { + packageManager1.setupApp2(false) + underTest.requestNewDefaults(USER_1, COMPONENT_NAME_1, false) + underTest.requestNewDefaults(USER_1, COMPONENT_NAME_1, false) + runCurrent() + + underTest.requestNewDefaults(USER_1, COMPONENT_NAME_2, false) + runCurrent() + + val default = underTest.defaults(USER_1).first() as CustomTileDefaults.Result + assertThat(default.label).isEqualTo(APP_LABEL_2) + assertThat(default.icon.resId).isEqualTo(SERVICE_ICON_2) + assertThat(default.icon.resPackage).isEqualTo(COMPONENT_NAME_2.packageName) + } + + @Test + fun noIconIsAnError() = + testScope.runTest { + packageManager1.setupApp( + componentName = COMPONENT_NAME_1, + appLabel = "", + serviceIcon = 0, + appInfoIcon = 0, + isSystemApp = false, + ) + underTest.requestNewDefaults(USER_1, COMPONENT_NAME_1, false) + + runCurrent() + + assertThat(underTest.defaults(USER_1).first()) + .isInstanceOf(CustomTileDefaults.Error::class.java) + } + + @Test + fun applicationScopeIsFreedWhileNotSubscribed() = + testScope.runTest { + val listenJob = underTest.defaults(USER_1).launchIn(backgroundScope) + listenJob.cancel() + assertThat(this.coroutineContext[Job]!!.children.toList()).isEmpty() + } + + private fun PackageManager.setupApp1(isSystemApp: Boolean = false) = + setupApp( + componentName = COMPONENT_NAME_1, + serviceIcon = SERVICE_ICON_1, + appLabel = APP_LABEL_1, + appInfoIcon = APP_INFO_ICON_1, + isSystemApp = isSystemApp, + ) + private fun PackageManager.setupApp2(isSystemApp: Boolean = false) = + setupApp( + componentName = COMPONENT_NAME_2, + serviceIcon = SERVICE_ICON_2, + appLabel = APP_LABEL_2, + appInfoIcon = APP_INFO_ICON_2, + isSystemApp = isSystemApp, + ) + + private fun PackageManager.setupApp( + componentName: ComponentName, + serviceIcon: Int, + appLabel: CharSequence, + appInfoIcon: Int = serviceIcon, + isSystemApp: Boolean = false, + ) { + val appInfo = + object : ApplicationInfo() { + override fun isSystemApp(): Boolean = isSystemApp + } + .apply { icon = appInfoIcon } + whenever(getApplicationInfo(eq(componentName.packageName), any<Int>())).thenReturn(appInfo) + + // set of desired flags is different for system and a regular app. + var serviceFlags = + (PackageManager.MATCH_DIRECT_BOOT_UNAWARE or PackageManager.MATCH_DIRECT_BOOT_AWARE) + if (isSystemApp) { + serviceFlags = serviceFlags or PackageManager.MATCH_DISABLED_COMPONENTS + } + + val serviceInfo = + object : ServiceInfo() { + override fun loadLabel(pm: PackageManager): CharSequence = appLabel + } + .apply { + applicationInfo = appInfo + icon = serviceIcon + } + whenever(getServiceInfo(eq(componentName), eq(serviceFlags))).thenReturn(serviceInfo) + } + + private companion object { + val USER_1 = UserHandle(1) + val USER_2 = UserHandle(2) + + val COMPONENT_NAME_1 = ComponentName("pkg.test_1", "cls") + const val SERVICE_ICON_1 = 11 + const val APP_INFO_ICON_1 = 12 + const val APP_LABEL_1 = "app_1" + + val COMPONENT_NAME_2 = ComponentName("pkg.test_2", "cls") + const val SERVICE_ICON_2 = 21 + const val APP_INFO_ICON_2 = 22 + const val APP_LABEL_2 = "app_2" + } +} diff --git a/packages/SystemUI/tests/src/com/android/systemui/shade/NotificationPanelViewControllerBaseTest.java b/packages/SystemUI/tests/src/com/android/systemui/shade/NotificationPanelViewControllerBaseTest.java index 2ce4b04b037a..446a0b8116a6 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/shade/NotificationPanelViewControllerBaseTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/shade/NotificationPanelViewControllerBaseTest.java @@ -99,7 +99,6 @@ import com.android.systemui.keyguard.domain.interactor.KeyguardFaceAuthInteracto import com.android.systemui.keyguard.domain.interactor.KeyguardInteractor; import com.android.systemui.keyguard.domain.interactor.KeyguardInteractorFactory; import com.android.systemui.keyguard.domain.interactor.KeyguardTransitionInteractor; -import com.android.systemui.keyguard.ui.view.KeyguardRootView; import com.android.systemui.keyguard.ui.viewmodel.DreamingToLockscreenTransitionViewModel; import com.android.systemui.keyguard.ui.viewmodel.GoneToDreamingLockscreenHostedTransitionViewModel; import com.android.systemui.keyguard.ui.viewmodel.GoneToDreamingTransitionViewModel; @@ -148,7 +147,6 @@ import com.android.systemui.statusbar.notification.NotificationWakeUpCoordinator import com.android.systemui.statusbar.notification.row.NotificationGutsManager; import com.android.systemui.statusbar.notification.stack.AmbientState; import com.android.systemui.statusbar.notification.stack.NotificationListContainer; -import com.android.systemui.statusbar.notification.stack.NotificationRoundnessManager; import com.android.systemui.statusbar.notification.stack.NotificationStackScrollLayout; import com.android.systemui.statusbar.notification.stack.NotificationStackScrollLayoutController; import com.android.systemui.statusbar.notification.stack.NotificationStackSizeCalculator; @@ -335,7 +333,6 @@ public class NotificationPanelViewControllerBaseTest extends SysuiTestCase { @Mock protected KeyguardFaceAuthInteractor mKeyguardFaceAuthInteractor; @Mock private JavaAdapter mJavaAdapter; @Mock private CastController mCastController; - @Mock private KeyguardRootView mKeyguardRootView; @Mock private SharedNotificationContainerInteractor mSharedNotificationContainerInteractor; @Mock private KeyguardClockPositionAlgorithm mKeyguardClockPositionAlgorithm; @@ -575,14 +572,13 @@ public class NotificationPanelViewControllerBaseTest extends SysuiTestCase { PulseExpansionHandler expansionHandler = new PulseExpansionHandler( mContext, coordinator, - mKeyguardBypassController, mHeadsUpManager, - mock(NotificationRoundnessManager.class), + mKeyguardBypassController, + mHeadsUpManager, mConfigurationController, mStatusBarStateController, mFalsingManager, - mShadeExpansionStateManager, + mShadeInteractor, mLockscreenShadeTransitionController, - new FalsingCollectorFake(), mDumpManager); when(mKeyguardStatusViewComponentFactory.build(any(), any())) .thenReturn(mKeyguardStatusViewComponent); diff --git a/packages/SystemUI/tests/src/com/android/systemui/shade/NotificationShadeWindowControllerImplTest.java b/packages/SystemUI/tests/src/com/android/systemui/shade/NotificationShadeWindowControllerImplTest.java index 4ba850c570c4..8e0cf7d7f695 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/shade/NotificationShadeWindowControllerImplTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/shade/NotificationShadeWindowControllerImplTest.java @@ -254,7 +254,6 @@ public class NotificationShadeWindowControllerImplTest extends SysuiTestCase { mKeyguardStateController, mScreenOffAnimationController, mAuthController, - mShadeExpansionStateManager, () -> mShadeInteractor, mShadeWindowLogger, () -> mSelectedUserInteractor) { diff --git a/packages/SystemUI/tests/src/com/android/systemui/shade/NotificationsQSContainerControllerLegacyTest.kt b/packages/SystemUI/tests/src/com/android/systemui/shade/NotificationsQSContainerControllerLegacyTest.kt index e70dbc7f4fda..778cfa67cad7 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/shade/NotificationsQSContainerControllerLegacyTest.kt +++ b/packages/SystemUI/tests/src/com/android/systemui/shade/NotificationsQSContainerControllerLegacyTest.kt @@ -18,7 +18,6 @@ package com.android.systemui.shade import android.testing.AndroidTestingRunner import android.testing.TestableLooper -import android.testing.TestableResources import android.view.View import android.view.ViewGroup import android.view.WindowInsets @@ -27,7 +26,6 @@ import androidx.annotation.IdRes import androidx.constraintlayout.widget.ConstraintLayout import androidx.constraintlayout.widget.ConstraintSet import androidx.test.filters.SmallTest -import com.android.systemui.res.R import com.android.systemui.SysuiTestCase import com.android.systemui.flags.FakeFeatureFlags import com.android.systemui.flags.Flags @@ -38,6 +36,8 @@ import com.android.systemui.navigationbar.NavigationModeController.ModeChangedLi import com.android.systemui.plugins.qs.QS import com.android.systemui.recents.OverviewProxyService import com.android.systemui.recents.OverviewProxyService.OverviewProxyListener +import com.android.systemui.res.R +import com.android.systemui.shade.domain.interactor.ShadeInteractor import com.android.systemui.statusbar.notification.stack.NotificationStackScrollLayoutController import com.android.systemui.statusbar.policy.ResourcesSplitShadeStateController import com.android.systemui.util.concurrency.FakeExecutor @@ -46,6 +46,7 @@ import com.android.systemui.util.mockito.whenever import com.android.systemui.util.time.FakeSystemClock import com.google.common.truth.Truth.assertThat import java.util.function.Consumer +import kotlinx.coroutines.flow.MutableStateFlow import org.junit.Before import org.junit.Test import org.junit.runner.RunWith @@ -66,7 +67,7 @@ import org.mockito.MockitoAnnotations /** Uses Flags.MIGRATE_NSSL set to false. If all goes well, this set of tests will be deleted. */ @RunWith(AndroidTestingRunner::class) -@TestableLooper.RunWithLooper +@TestableLooper.RunWithLooper(setAsMainLooper = true) @SmallTest class NotificationsQSContainerControllerLegacyTest : SysuiTestCase() { @@ -74,7 +75,7 @@ class NotificationsQSContainerControllerLegacyTest : SysuiTestCase() { @Mock lateinit var navigationModeController: NavigationModeController @Mock lateinit var overviewProxyService: OverviewProxyService @Mock lateinit var shadeHeaderController: ShadeHeaderController - @Mock lateinit var shadeExpansionStateManager: ShadeExpansionStateManager + @Mock lateinit var shadeInteractor: ShadeInteractor @Mock lateinit var fragmentService: FragmentService @Mock lateinit var fragmentHostManager: FragmentHostManager @Mock @@ -88,7 +89,6 @@ class NotificationsQSContainerControllerLegacyTest : SysuiTestCase() { lateinit var underTest: NotificationsQSContainerController - private lateinit var fakeResources: TestableResources private lateinit var featureFlags: FakeFeatureFlags private lateinit var navigationModeCallback: ModeChangedListener private lateinit var taskbarVisibilityCallback: OverviewProxyListener @@ -111,6 +111,7 @@ class NotificationsQSContainerControllerLegacyTest : SysuiTestCase() { whenever(view.resources).thenReturn(mContext.resources) whenever(fragmentService.getFragmentHostManager(any())).thenReturn(fragmentHostManager) + whenever(shadeInteractor.isQsExpanded).thenReturn(MutableStateFlow(false)) underTest = NotificationsQSContainerController( @@ -118,7 +119,7 @@ class NotificationsQSContainerControllerLegacyTest : SysuiTestCase() { navigationModeController, overviewProxyService, shadeHeaderController, - shadeExpansionStateManager, + shadeInteractor, fragmentService, delayableExecutor, featureFlags, @@ -475,7 +476,7 @@ class NotificationsQSContainerControllerLegacyTest : SysuiTestCase() { navigationModeController, overviewProxyService, shadeHeaderController, - shadeExpansionStateManager, + shadeInteractor, fragmentService, delayableExecutor, featureFlags, diff --git a/packages/SystemUI/tests/src/com/android/systemui/shade/NotificationsQSContainerControllerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/shade/NotificationsQSContainerControllerTest.kt index ac8c924fe689..23420037e233 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/shade/NotificationsQSContainerControllerTest.kt +++ b/packages/SystemUI/tests/src/com/android/systemui/shade/NotificationsQSContainerControllerTest.kt @@ -18,7 +18,6 @@ package com.android.systemui.shade import android.testing.AndroidTestingRunner import android.testing.TestableLooper -import android.testing.TestableResources import android.view.View import android.view.ViewGroup import android.view.WindowInsets @@ -27,7 +26,6 @@ import androidx.annotation.IdRes import androidx.constraintlayout.widget.ConstraintLayout import androidx.constraintlayout.widget.ConstraintSet import androidx.test.filters.SmallTest -import com.android.systemui.res.R import com.android.systemui.SysuiTestCase import com.android.systemui.flags.FakeFeatureFlags import com.android.systemui.flags.Flags @@ -38,6 +36,8 @@ import com.android.systemui.navigationbar.NavigationModeController.ModeChangedLi import com.android.systemui.plugins.qs.QS import com.android.systemui.recents.OverviewProxyService import com.android.systemui.recents.OverviewProxyService.OverviewProxyListener +import com.android.systemui.res.R +import com.android.systemui.shade.domain.interactor.ShadeInteractor import com.android.systemui.statusbar.notification.stack.NotificationStackScrollLayoutController import com.android.systemui.statusbar.policy.ResourcesSplitShadeStateController import com.android.systemui.util.concurrency.FakeExecutor @@ -46,6 +46,7 @@ import com.android.systemui.util.mockito.whenever import com.android.systemui.util.time.FakeSystemClock import com.google.common.truth.Truth.assertThat import java.util.function.Consumer +import kotlinx.coroutines.flow.MutableStateFlow import org.junit.Before import org.junit.Test import org.junit.runner.RunWith @@ -65,7 +66,7 @@ import org.mockito.Mockito.verify import org.mockito.MockitoAnnotations @RunWith(AndroidTestingRunner::class) -@TestableLooper.RunWithLooper +@TestableLooper.RunWithLooper(setAsMainLooper = true) @SmallTest class NotificationsQSContainerControllerTest : SysuiTestCase() { @@ -73,7 +74,7 @@ class NotificationsQSContainerControllerTest : SysuiTestCase() { @Mock lateinit var navigationModeController: NavigationModeController @Mock lateinit var overviewProxyService: OverviewProxyService @Mock lateinit var shadeHeaderController: ShadeHeaderController - @Mock lateinit var shadeExpansionStateManager: ShadeExpansionStateManager + @Mock lateinit var shadeInteractor: ShadeInteractor @Mock lateinit var fragmentService: FragmentService @Mock lateinit var fragmentHostManager: FragmentHostManager @Mock @@ -87,7 +88,6 @@ class NotificationsQSContainerControllerTest : SysuiTestCase() { lateinit var underTest: NotificationsQSContainerController - private lateinit var fakeResources: TestableResources private lateinit var featureFlags: FakeFeatureFlags private lateinit var navigationModeCallback: ModeChangedListener private lateinit var taskbarVisibilityCallback: OverviewProxyListener @@ -111,13 +111,15 @@ class NotificationsQSContainerControllerTest : SysuiTestCase() { whenever(fragmentService.getFragmentHostManager(any())).thenReturn(fragmentHostManager) + whenever(shadeInteractor.isQsExpanded).thenReturn(MutableStateFlow(false)) + underTest = NotificationsQSContainerController( view, navigationModeController, overviewProxyService, shadeHeaderController, - shadeExpansionStateManager, + shadeInteractor, fragmentService, delayableExecutor, featureFlags, @@ -458,7 +460,7 @@ class NotificationsQSContainerControllerTest : SysuiTestCase() { navigationModeController, overviewProxyService, shadeHeaderController, - shadeExpansionStateManager, + shadeInteractor, fragmentService, delayableExecutor, featureFlags, diff --git a/packages/SystemUI/tests/src/com/android/systemui/shade/data/repository/ShadeRepositoryImplTest.kt b/packages/SystemUI/tests/src/com/android/systemui/shade/data/repository/ShadeRepositoryImplTest.kt index 6eeafefd0ac1..e920687753fd 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/shade/data/repository/ShadeRepositoryImplTest.kt +++ b/packages/SystemUI/tests/src/com/android/systemui/shade/data/repository/ShadeRepositoryImplTest.kt @@ -189,4 +189,13 @@ class ShadeRepositoryImplTest : SysuiTestCase() { underTest.setUdfpsTransitionToFullShadeProgress(1f) assertThat(underTest.udfpsTransitionToFullShadeProgress.value).isEqualTo(1f) } + + @Test + fun updateLegacyIsQsExpanded() = + testScope.runTest { + assertThat(underTest.legacyIsQsExpanded.value).isEqualTo(false) + + underTest.setLegacyIsQsExpanded(true) + assertThat(underTest.legacyIsQsExpanded.value).isEqualTo(true) + } } diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/PulseExpansionHandlerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/PulseExpansionHandlerTest.kt index 20e5c43cba19..49e5c456e645 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/PulseExpansionHandlerTest.kt +++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/PulseExpansionHandlerTest.kt @@ -21,18 +21,17 @@ import android.testing.AndroidTestingRunner import android.testing.TestableLooper import androidx.test.filters.SmallTest import com.android.systemui.SysuiTestCase -import com.android.systemui.classifier.FalsingCollector import com.android.systemui.dump.DumpManager import com.android.systemui.plugins.FalsingManager import com.android.systemui.plugins.statusbar.StatusBarStateController -import com.android.systemui.shade.ShadeExpansionStateManager +import com.android.systemui.shade.domain.interactor.ShadeInteractor import com.android.systemui.statusbar.notification.NotificationWakeUpCoordinator import com.android.systemui.statusbar.notification.row.ExpandableView -import com.android.systemui.statusbar.notification.stack.NotificationRoundnessManager import com.android.systemui.statusbar.phone.KeyguardBypassController import com.android.systemui.statusbar.policy.ConfigurationController import com.android.systemui.statusbar.policy.HeadsUpManager import com.android.systemui.util.mockito.mock +import kotlinx.coroutines.flow.MutableStateFlow import org.junit.Before import org.junit.Test import org.junit.runner.RunWith @@ -53,19 +52,18 @@ class PulseExpansionHandlerTest : SysuiTestCase() { private val wakeUpCoordinator: NotificationWakeUpCoordinator = mock() private val bypassController: KeyguardBypassController = mock() private val headsUpManager: HeadsUpManager = mock() - private val roundnessManager: NotificationRoundnessManager = mock() private val configurationController: ConfigurationController = mock() private val statusBarStateController: StatusBarStateController = mock() private val falsingManager: FalsingManager = mock() - private val shadeExpansionStateManager: ShadeExpansionStateManager = mock() + private val shadeInteractor: ShadeInteractor = mock() private val lockscreenShadeTransitionController: LockscreenShadeTransitionController = mock() - private val falsingCollector: FalsingCollector = mock() private val dumpManager: DumpManager = mock() private val expandableView: ExpandableView = mock() @Before fun setUp() { whenever(expandableView.collapsedHeight).thenReturn(collapsedHeight) + whenever(shadeInteractor.isQsExpanded).thenReturn(MutableStateFlow(false)) pulseExpansionHandler = PulseExpansionHandler( @@ -73,13 +71,11 @@ class PulseExpansionHandlerTest : SysuiTestCase() { wakeUpCoordinator, bypassController, headsUpManager, - roundnessManager, configurationController, statusBarStateController, falsingManager, - shadeExpansionStateManager, + shadeInteractor, lockscreenShadeTransitionController, - falsingCollector, dumpManager ) } diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/events/SystemEventChipAnimationControllerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/events/SystemEventChipAnimationControllerTest.kt index 2e223f6d8c1f..df257ab113b3 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/events/SystemEventChipAnimationControllerTest.kt +++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/events/SystemEventChipAnimationControllerTest.kt @@ -27,7 +27,6 @@ import android.widget.FrameLayout import androidx.test.filters.SmallTest import com.android.systemui.SysuiTestCase import com.android.systemui.animation.AnimatorTestRule -import com.android.systemui.flags.FakeFeatureFlags import com.android.systemui.statusbar.phone.StatusBarContentInsetsChangedListener import com.android.systemui.statusbar.phone.StatusBarContentInsetsProvider import com.android.systemui.statusbar.window.StatusBarWindowController @@ -88,8 +87,7 @@ class SystemEventChipAnimationControllerTest : SysuiTestCase() { SystemEventChipAnimationController( context = mContext, statusBarWindowController = sbWindowController, - contentInsetsProvider = insetsProvider, - featureFlags = FakeFeatureFlags(), + contentInsetsProvider = insetsProvider ) } diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/events/SystemEventCoordinatorTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/events/SystemEventCoordinatorTest.kt index c289ff3bc19d..bbc63f2009b9 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/events/SystemEventCoordinatorTest.kt +++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/events/SystemEventCoordinatorTest.kt @@ -21,7 +21,7 @@ import androidx.test.filters.SmallTest import com.android.systemui.SysuiTestCase import com.android.systemui.display.domain.interactor.ConnectedDisplayInteractor import com.android.systemui.display.domain.interactor.ConnectedDisplayInteractor.PendingDisplay -import com.android.systemui.flags.FakeFeatureFlags +import com.android.systemui.display.domain.interactor.ConnectedDisplayInteractor.State.CONNECTED import com.android.systemui.privacy.PrivacyItemController import com.android.systemui.statusbar.policy.BatteryController import com.android.systemui.util.mockito.any @@ -48,7 +48,6 @@ import org.mockito.MockitoAnnotations class SystemEventCoordinatorTest : SysuiTestCase() { private val fakeSystemClock = FakeSystemClock() - private val featureFlags = FakeFeatureFlags() private val testScope = TestScope(UnconfinedTestDispatcher()) private val connectedDisplayInteractor = FakeConnectedDisplayInteractor() @@ -66,7 +65,6 @@ class SystemEventCoordinatorTest : SysuiTestCase() { batteryController, privacyController, context, - featureFlags, TestScope(UnconfinedTestDispatcher()), connectedDisplayInteractor ) diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/events/SystemStatusAnimationSchedulerImplTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/events/SystemStatusAnimationSchedulerImplTest.kt index fee8b82a3038..5f01b5a56e4c 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/events/SystemStatusAnimationSchedulerImplTest.kt +++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/events/SystemStatusAnimationSchedulerImplTest.kt @@ -26,8 +26,6 @@ import androidx.test.filters.SmallTest import com.android.systemui.SysuiTestCase import com.android.systemui.animation.AnimatorTestRule import com.android.systemui.dump.DumpManager -import com.android.systemui.flags.FakeFeatureFlags -import com.android.systemui.flags.Flags import com.android.systemui.privacy.OngoingPrivacyChip import com.android.systemui.statusbar.BatteryStatusChip import com.android.systemui.statusbar.phone.StatusBarContentInsetsProvider @@ -76,7 +74,6 @@ class SystemStatusAnimationSchedulerImplTest : SysuiTestCase() { private lateinit var systemClock: FakeSystemClock private lateinit var chipAnimationController: SystemEventChipAnimationController private lateinit var systemStatusAnimationScheduler: SystemStatusAnimationScheduler - private val fakeFeatureFlags = FakeFeatureFlags() @get:Rule val animatorTestRule = AnimatorTestRule() @@ -84,15 +81,12 @@ class SystemStatusAnimationSchedulerImplTest : SysuiTestCase() { fun setup() { MockitoAnnotations.initMocks(this) - fakeFeatureFlags.set(Flags.PLUG_IN_STATUS_BAR_CHIP, true) - systemClock = FakeSystemClock() chipAnimationController = SystemEventChipAnimationController( mContext, statusBarWindowController, - statusBarContentInsetProvider, - fakeFeatureFlags + statusBarContentInsetProvider ) // StatusBarContentInsetProvider is mocked. Ensure that it returns some mocked values. diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/icon/ui/viewmodel/NotificationIconContainerAlwaysOnDisplayViewModelTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/icon/ui/viewmodel/NotificationIconContainerAlwaysOnDisplayViewModelTest.kt index 14d188c69525..49e1493f642f 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/icon/ui/viewmodel/NotificationIconContainerAlwaysOnDisplayViewModelTest.kt +++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/icon/ui/viewmodel/NotificationIconContainerAlwaysOnDisplayViewModelTest.kt @@ -25,7 +25,6 @@ import com.android.systemui.SysuiTestCase import com.android.systemui.biometrics.domain.BiometricsDomainLayerModule import com.android.systemui.coroutines.collectLastValue import com.android.systemui.dagger.SysUISingleton -import com.android.systemui.deviceentry.data.repository.FakeDeviceEntryRepository import com.android.systemui.flags.FakeFeatureFlagsClassicModule import com.android.systemui.flags.Flags import com.android.systemui.keyguard.data.repository.FakeKeyguardRepository @@ -38,7 +37,6 @@ import com.android.systemui.keyguard.shared.model.TransitionStep import com.android.systemui.power.data.repository.FakePowerRepository import com.android.systemui.power.shared.model.WakeSleepReason import com.android.systemui.power.shared.model.WakefulnessState -import com.android.systemui.statusbar.notification.data.repository.FakeNotificationsKeyguardViewStateRepository import com.android.systemui.statusbar.phone.DozeParameters import com.android.systemui.statusbar.phone.ScreenOffAnimationController import com.android.systemui.statusbar.policy.data.repository.FakeDeviceProvisioningRepository @@ -70,16 +68,12 @@ class NotificationIconContainerAlwaysOnDisplayViewModelTest : SysuiTestCase() { private lateinit var testComponent: TestComponent private val underTest: NotificationIconContainerAlwaysOnDisplayViewModel get() = testComponent.underTest - private val deviceEntryRepository: FakeDeviceEntryRepository - get() = testComponent.deviceEntryRepository private val deviceProvisioningRepository: FakeDeviceProvisioningRepository get() = testComponent.deviceProvisioningRepository private val keyguardRepository: FakeKeyguardRepository get() = testComponent.keyguardRepository private val keyguardTransitionRepository: FakeKeyguardTransitionRepository get() = testComponent.keyguardTransitionRepository - private val notifsKeyguardRepository: FakeNotificationsKeyguardViewStateRepository - get() = testComponent.notifsKeyguardRepository private val powerRepository: FakePowerRepository get() = testComponent.powerRepository private val scope: TestScope @@ -354,137 +348,6 @@ class NotificationIconContainerAlwaysOnDisplayViewModelTest : SysuiTestCase() { assertThat(isDozing?.isAnimating).isEqualTo(false) } - @Test - fun isNotVisible_pulseExpanding() = - scope.runTest { - val isVisible by collectLastValue(underTest.isVisible) - runCurrent() - notifsKeyguardRepository.setPulseExpanding(true) - runCurrent() - - assertThat(isVisible?.value).isFalse() - } - - @Test - fun isNotVisible_notOnKeyguard_dontShowAodIconsWhenShade() = - scope.runTest { - val isVisible by collectLastValue(underTest.isVisible) - runCurrent() - keyguardTransitionRepository.sendTransitionSteps( - from = KeyguardState.OFF, - to = KeyguardState.GONE, - scope, - ) - whenever(screenOffAnimController.shouldShowAodIconsWhenShade()).thenReturn(false) - runCurrent() - - assertThat(isVisible?.value).isFalse() - assertThat(isVisible?.isAnimating).isFalse() - } - - @Test - fun isVisible_bypassEnabled() = - scope.runTest { - val isVisible by collectLastValue(underTest.isVisible) - runCurrent() - deviceEntryRepository.setBypassEnabled(true) - runCurrent() - - assertThat(isVisible?.value).isTrue() - } - - @Test - fun isNotVisible_pulseExpanding_notBypassing() = - scope.runTest { - val isVisible by collectLastValue(underTest.isVisible) - runCurrent() - notifsKeyguardRepository.setPulseExpanding(true) - deviceEntryRepository.setBypassEnabled(false) - runCurrent() - - assertThat(isVisible?.value).isEqualTo(false) - } - - @Test - fun isVisible_notifsFullyHidden_bypassEnabled() = - scope.runTest { - val isVisible by collectLastValue(underTest.isVisible) - runCurrent() - notifsKeyguardRepository.setPulseExpanding(false) - deviceEntryRepository.setBypassEnabled(true) - notifsKeyguardRepository.setNotificationsFullyHidden(true) - runCurrent() - - assertThat(isVisible?.value).isTrue() - assertThat(isVisible?.isAnimating).isTrue() - } - - @Test - fun isVisible_notifsFullyHidden_bypassDisabled_aodDisabled() = - scope.runTest { - val isVisible by collectLastValue(underTest.isVisible) - runCurrent() - notifsKeyguardRepository.setPulseExpanding(false) - deviceEntryRepository.setBypassEnabled(false) - whenever(dozeParams.alwaysOn).thenReturn(false) - notifsKeyguardRepository.setNotificationsFullyHidden(true) - runCurrent() - - assertThat(isVisible?.value).isTrue() - assertThat(isVisible?.isAnimating).isFalse() - } - - @Test - fun isVisible_notifsFullyHidden_bypassDisabled_displayNeedsBlanking() = - scope.runTest { - val isVisible by collectLastValue(underTest.isVisible) - runCurrent() - notifsKeyguardRepository.setPulseExpanding(false) - deviceEntryRepository.setBypassEnabled(false) - whenever(dozeParams.alwaysOn).thenReturn(true) - whenever(dozeParams.displayNeedsBlanking).thenReturn(true) - notifsKeyguardRepository.setNotificationsFullyHidden(true) - runCurrent() - - assertThat(isVisible?.value).isTrue() - assertThat(isVisible?.isAnimating).isFalse() - } - - @Test - fun isVisible_notifsFullyHidden_bypassDisabled() = - scope.runTest { - val isVisible by collectLastValue(underTest.isVisible) - runCurrent() - notifsKeyguardRepository.setPulseExpanding(false) - deviceEntryRepository.setBypassEnabled(false) - whenever(dozeParams.alwaysOn).thenReturn(true) - whenever(dozeParams.displayNeedsBlanking).thenReturn(false) - notifsKeyguardRepository.setNotificationsFullyHidden(true) - runCurrent() - - assertThat(isVisible?.value).isTrue() - assertThat(isVisible?.isAnimating).isTrue() - } - - @Test - fun isVisible_stopAnimation() = - scope.runTest { - val isVisible by collectLastValue(underTest.isVisible) - runCurrent() - notifsKeyguardRepository.setPulseExpanding(false) - deviceEntryRepository.setBypassEnabled(false) - whenever(dozeParams.alwaysOn).thenReturn(true) - whenever(dozeParams.displayNeedsBlanking).thenReturn(false) - notifsKeyguardRepository.setNotificationsFullyHidden(true) - runCurrent() - - assertThat(isVisible?.isAnimating).isEqualTo(true) - isVisible?.stopAnimating() - runCurrent() - - assertThat(isVisible?.isAnimating).isEqualTo(false) - } - @SysUISingleton @Component( modules = @@ -498,11 +361,9 @@ class NotificationIconContainerAlwaysOnDisplayViewModelTest : SysuiTestCase() { val underTest: NotificationIconContainerAlwaysOnDisplayViewModel - val deviceEntryRepository: FakeDeviceEntryRepository val deviceProvisioningRepository: FakeDeviceProvisioningRepository val keyguardRepository: FakeKeyguardRepository val keyguardTransitionRepository: FakeKeyguardTransitionRepository - val notifsKeyguardRepository: FakeNotificationsKeyguardViewStateRepository val powerRepository: FakePowerRepository val scope: TestScope diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/interruption/NotificationInterruptStateProviderImplTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/interruption/NotificationInterruptStateProviderImplTest.java index 50ce265b67d1..1c621613c403 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/interruption/NotificationInterruptStateProviderImplTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/interruption/NotificationInterruptStateProviderImplTest.java @@ -13,8 +13,8 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package com.android.systemui.statusbar.notification.interruption; +package com.android.systemui.statusbar.notification.interruption; import static android.app.Notification.FLAG_BUBBLE; import static android.app.Notification.FLAG_FOREGROUND_SERVICE; @@ -27,6 +27,8 @@ import static android.app.NotificationManager.Policy.SUPPRESSED_EFFECT_AMBIENT; import static android.app.NotificationManager.Policy.SUPPRESSED_EFFECT_FULL_SCREEN_INTENT; import static android.app.NotificationManager.Policy.SUPPRESSED_EFFECT_PEEK; import static android.app.NotificationManager.VISIBILITY_NO_OVERRIDE; +import static android.provider.Settings.Global.HEADS_UP_NOTIFICATIONS_ENABLED; +import static android.provider.Settings.Global.HEADS_UP_ON; import static com.android.systemui.statusbar.NotificationEntryHelper.modifyRanking; import static com.android.systemui.statusbar.StatusBarState.KEYGUARD; @@ -61,9 +63,9 @@ import android.testing.AndroidTestingRunner; import androidx.test.filters.SmallTest; import com.android.internal.logging.testing.UiEventLoggerFake; -import com.android.systemui.res.R; import com.android.systemui.SysuiTestCase; import com.android.systemui.plugins.statusbar.StatusBarStateController; +import com.android.systemui.res.R; import com.android.systemui.settings.UserTracker; import com.android.systemui.statusbar.notification.NotifPipelineFlags; import com.android.systemui.statusbar.notification.collection.NotificationEntry; @@ -74,6 +76,8 @@ import com.android.systemui.statusbar.policy.BatteryController; import com.android.systemui.statusbar.policy.DeviceProvisionedController; import com.android.systemui.statusbar.policy.HeadsUpManager; import com.android.systemui.statusbar.policy.KeyguardStateController; +import com.android.systemui.util.settings.FakeGlobalSettings; +import com.android.systemui.util.time.FakeSystemClock; import org.junit.Before; import org.junit.Test; @@ -120,6 +124,8 @@ public class NotificationInterruptStateProviderImplTest extends SysuiTestCase { UserTracker mUserTracker; @Mock DeviceProvisionedController mDeviceProvisionedController; + FakeSystemClock mSystemClock; + FakeGlobalSettings mGlobalSettings; private NotificationInterruptStateProviderImpl mNotifInterruptionStateProvider; @@ -129,10 +135,12 @@ public class NotificationInterruptStateProviderImplTest extends SysuiTestCase { when(mUserTracker.getUserId()).thenReturn(ActivityManager.getCurrentUser()); mUiEventLoggerFake = new UiEventLoggerFake(); + mSystemClock = new FakeSystemClock(); + mGlobalSettings = new FakeGlobalSettings(); + mGlobalSettings.putInt(HEADS_UP_NOTIFICATIONS_ENABLED, HEADS_UP_ON); mNotifInterruptionStateProvider = new NotificationInterruptStateProviderImpl( - mContext.getContentResolver(), mPowerManager, mAmbientDisplayConfiguration, mBatteryController, @@ -145,7 +153,9 @@ public class NotificationInterruptStateProviderImplTest extends SysuiTestCase { mKeyguardNotificationVisibilityProvider, mUiEventLoggerFake, mUserTracker, - mDeviceProvisionedController); + mDeviceProvisionedController, + mSystemClock, + mGlobalSettings); mNotifInterruptionStateProvider.mUseHeadsUp = true; } @@ -426,7 +436,7 @@ public class NotificationInterruptStateProviderImplTest extends SysuiTestCase { } private long makeWhenHoursAgo(long hoursAgo) { - return System.currentTimeMillis() - (1000 * 60 * 60 * hoursAgo); + return mSystemClock.currentTimeMillis() - (1000 * 60 * 60 * hoursAgo); } @Test diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/interruption/NotificationInterruptStateProviderWrapperTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/interruption/NotificationInterruptStateProviderWrapperTest.kt index 947bcfb5011b..1d2055ec2e30 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/interruption/NotificationInterruptStateProviderWrapperTest.kt +++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/interruption/NotificationInterruptStateProviderWrapperTest.kt @@ -1,3 +1,19 @@ +/* + * Copyright (C) 2023 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + package com.android.systemui.statusbar.notification.interruption import android.testing.AndroidTestingRunner @@ -19,27 +35,27 @@ import org.junit.runner.RunWith @SmallTest @RunWith(AndroidTestingRunner::class) class NotificationInterruptStateProviderWrapperTest : VisualInterruptionDecisionProviderTestBase() { - override val provider: VisualInterruptionDecisionProvider - get() = - NotificationInterruptStateProviderWrapper( - NotificationInterruptStateProviderImpl( - context.contentResolver, - powerManager, - ambientDisplayConfiguration, - batteryController, - statusBarStateController, - keyguardStateController, - headsUpManager, - logger, - mainHandler, - flags, - keyguardNotificationVisibilityProvider, - uiEventLogger, - userTracker, - deviceProvisionedController - ) - .also { it.mUseHeadsUp = true } + override val provider by lazy { + NotificationInterruptStateProviderWrapper( + NotificationInterruptStateProviderImpl( + powerManager, + ambientDisplayConfiguration, + batteryController, + statusBarStateController, + keyguardStateController, + headsUpManager, + logger, + mainHandler, + flags, + keyguardNotificationVisibilityProvider, + uiEventLogger, + userTracker, + deviceProvisionedController, + systemClock, + globalSettings, ) + ) + } // Tests of internals of the wrapper: diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/interruption/VisualInterruptionDecisionProviderImplTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/interruption/VisualInterruptionDecisionProviderImplTest.kt new file mode 100644 index 000000000000..ff89bdb6dbde --- /dev/null +++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/interruption/VisualInterruptionDecisionProviderImplTest.kt @@ -0,0 +1,40 @@ +/* + * Copyright (C) 2023 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.systemui.statusbar.notification.interruption + +import android.testing.AndroidTestingRunner +import androidx.test.filters.SmallTest +import org.junit.runner.RunWith + +@SmallTest +@RunWith(AndroidTestingRunner::class) +class VisualInterruptionDecisionProviderImplTest : VisualInterruptionDecisionProviderTestBase() { + override val provider by lazy { + VisualInterruptionDecisionProviderImpl( + ambientDisplayConfiguration, + batteryController, + globalSettings, + headsUpManager, + logger, + mainHandler, + powerManager, + statusBarStateController, + systemClock, + userTracker, + ) + } +} diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/interruption/VisualInterruptionDecisionProviderTestBase.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/interruption/VisualInterruptionDecisionProviderTestBase.kt index 6f4bbd5e21fc..df1228965749 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/interruption/VisualInterruptionDecisionProviderTestBase.kt +++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/interruption/VisualInterruptionDecisionProviderTestBase.kt @@ -1,20 +1,45 @@ +/* + * Copyright (C) 2023 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + package com.android.systemui.statusbar.notification.interruption import android.app.ActivityManager import android.app.Notification import android.app.Notification.BubbleMetadata +import android.app.Notification.FLAG_BUBBLE +import android.app.Notification.VISIBILITY_PRIVATE import android.app.NotificationChannel import android.app.NotificationManager.IMPORTANCE_DEFAULT import android.app.NotificationManager.IMPORTANCE_HIGH +import android.app.NotificationManager.IMPORTANCE_LOW +import android.app.NotificationManager.Policy.SUPPRESSED_EFFECT_AMBIENT +import android.app.NotificationManager.Policy.SUPPRESSED_EFFECT_PEEK import android.app.NotificationManager.VISIBILITY_NO_OVERRIDE import android.app.PendingIntent import android.app.PendingIntent.FLAG_MUTABLE +import android.content.Context import android.content.Intent import android.content.pm.UserInfo import android.graphics.drawable.Icon import android.hardware.display.FakeAmbientDisplayConfiguration -import android.os.Handler +import android.os.Looper import android.os.PowerManager +import android.provider.Settings.Global.HEADS_UP_NOTIFICATIONS_ENABLED +import android.provider.Settings.Global.HEADS_UP_OFF +import android.provider.Settings.Global.HEADS_UP_ON import com.android.internal.logging.testing.UiEventLoggerFake import com.android.systemui.SysuiTestCase import com.android.systemui.res.R @@ -23,16 +48,22 @@ import com.android.systemui.statusbar.FakeStatusBarStateController import com.android.systemui.statusbar.NotificationEntryHelper.modifyRanking import com.android.systemui.statusbar.StatusBarState.KEYGUARD import com.android.systemui.statusbar.StatusBarState.SHADE +import com.android.systemui.statusbar.StatusBarState.SHADE_LOCKED import com.android.systemui.statusbar.notification.NotifPipelineFlags import com.android.systemui.statusbar.notification.collection.NotificationEntry import com.android.systemui.statusbar.notification.collection.NotificationEntryBuilder +import com.android.systemui.statusbar.notification.interruption.NotificationInterruptStateProviderImpl.MAX_HUN_WHEN_AGE_MS import com.android.systemui.statusbar.policy.DeviceProvisionedController import com.android.systemui.statusbar.policy.HeadsUpManager import com.android.systemui.statusbar.policy.KeyguardStateController import com.android.systemui.util.mockito.any import com.android.systemui.util.mockito.mock +import com.android.systemui.util.settings.FakeGlobalSettings +import com.android.systemui.util.time.FakeSystemClock import com.android.systemui.utils.leaks.FakeBatteryController import com.android.systemui.utils.leaks.LeakCheckedTest +import com.android.systemui.utils.os.FakeHandler +import junit.framework.Assert.assertFalse import junit.framework.Assert.assertTrue import org.junit.Before import org.junit.Test @@ -45,172 +76,503 @@ abstract class VisualInterruptionDecisionProviderTestBase : SysuiTestCase() { protected val batteryController = FakeBatteryController(leakCheck) protected val deviceProvisionedController: DeviceProvisionedController = mock() protected val flags: NotifPipelineFlags = mock() + protected val globalSettings = FakeGlobalSettings() protected val headsUpManager: HeadsUpManager = mock() protected val keyguardNotificationVisibilityProvider: KeyguardNotificationVisibilityProvider = mock() protected val keyguardStateController: KeyguardStateController = mock() protected val logger: NotificationInterruptLogger = mock() - protected val mainHandler: Handler = mock() + protected val mainHandler = FakeHandler(Looper.getMainLooper()) protected val powerManager: PowerManager = mock() protected val statusBarStateController = FakeStatusBarStateController() + protected val systemClock = FakeSystemClock() protected val uiEventLogger = UiEventLoggerFake() protected val userTracker = FakeUserTracker() protected abstract val provider: VisualInterruptionDecisionProvider + private val neverSuppresses = object : NotificationInterruptSuppressor {} + + private val alwaysSuppressesInterruptions = + object : NotificationInterruptSuppressor { + override fun suppressInterruptions(entry: NotificationEntry?) = true + } + + private val alwaysSuppressesAwakeInterruptions = + object : NotificationInterruptSuppressor { + override fun suppressAwakeInterruptions(entry: NotificationEntry?) = true + } + + private val alwaysSuppressesAwakeHeadsUp = + object : NotificationInterruptSuppressor { + override fun suppressAwakeHeadsUp(entry: NotificationEntry?) = true + } + @Before fun setUp() { + globalSettings.putInt(HEADS_UP_NOTIFICATIONS_ENABLED, HEADS_UP_ON) + val user = UserInfo(ActivityManager.getCurrentUser(), "Current user", /* flags = */ 0) userTracker.set(listOf(user), /* currentUserIndex = */ 0) - whenever(headsUpManager.isSnoozed(any())).thenReturn(false) whenever(keyguardNotificationVisibilityProvider.shouldHideNotification(any())) .thenReturn(false) + + provider.start() } @Test fun testShouldPeek() { - ensureStateForPeek() + ensurePeekState() + assertShouldHeadsUp(buildPeekEntry()) + } + + @Test + fun testShouldNotPeek_settingDisabled() { + ensurePeekState { hunSettingEnabled = false } + assertShouldNotHeadsUp(buildPeekEntry()) + } + + @Test + fun testShouldNotPeek_packageSnoozed() { + ensurePeekState { hunSnoozed = true } + assertShouldNotHeadsUp(buildPeekEntry()) + } + + @Test + fun testShouldPeek_packageSnoozedButFsi() { + ensurePeekState { hunSnoozed = true } + assertShouldHeadsUp(buildFsiEntry()) + } + + @Test + fun testShouldNotPeek_alreadyBubbled() { + ensurePeekState { statusBarState = SHADE } + assertShouldNotHeadsUp(buildPeekEntry { isBubble = true }) + } + + @Test + fun testShouldPeek_isBubble_shadeLocked() { + ensurePeekState { statusBarState = SHADE_LOCKED } + assertShouldHeadsUp(buildPeekEntry { isBubble = true }) + } + + @Test + fun testShouldPeek_isBubble_keyguard() { + ensurePeekState { statusBarState = KEYGUARD } + assertShouldHeadsUp(buildPeekEntry { isBubble = true }) + } + + @Test + fun testShouldNotPeek_dnd() { + ensurePeekState() + assertShouldNotHeadsUp(buildPeekEntry { suppressedVisualEffects = SUPPRESSED_EFFECT_PEEK }) + } - assertTrue(provider.makeUnloggedHeadsUpDecision(createPeekEntry()).shouldInterrupt) + @Test + fun testShouldNotPeek_notImportant() { + ensurePeekState() + assertShouldNotHeadsUp(buildPeekEntry { importance = IMPORTANCE_DEFAULT }) + } + + @Test + fun testShouldNotPeek_screenOff() { + ensurePeekState { isScreenOn = false } + assertShouldNotHeadsUp(buildPeekEntry()) + } + + @Test + fun testShouldNotPeek_dreaming() { + ensurePeekState { isDreaming = true } + assertShouldNotHeadsUp(buildPeekEntry()) + } + + @Test + fun testShouldNotPeek_oldWhen() { + ensurePeekState() + assertShouldNotHeadsUp(buildPeekEntry { whenMs = whenAgo(MAX_HUN_WHEN_AGE_MS) }) + } + + @Test + fun testShouldPeek_notQuiteOldEnoughWhen() { + ensurePeekState() + assertShouldHeadsUp(buildPeekEntry { whenMs = whenAgo(MAX_HUN_WHEN_AGE_MS - 1) }) + } + + @Test + fun testShouldPeek_zeroWhen() { + ensurePeekState() + assertShouldHeadsUp(buildPeekEntry { whenMs = 0L }) + } + + @Test + fun testShouldPeek_oldWhenButFsi() { + ensurePeekState() + assertShouldHeadsUp(buildFsiEntry { whenMs = whenAgo(MAX_HUN_WHEN_AGE_MS) }) + } + + @Test + fun testShouldPeek_defaultLegacySuppressor() { + ensurePeekState() + provider.addLegacySuppressor(neverSuppresses) + assertShouldHeadsUp(buildPeekEntry()) + } + + @Test + fun testShouldNotPeek_legacySuppressInterruptions() { + ensurePeekState() + provider.addLegacySuppressor(alwaysSuppressesInterruptions) + assertShouldNotHeadsUp(buildPeekEntry()) + } + + @Test + fun testShouldNotPeek_legacySuppressAwakeInterruptions() { + ensurePeekState() + provider.addLegacySuppressor(alwaysSuppressesAwakeInterruptions) + assertShouldNotHeadsUp(buildPeekEntry()) + } + + @Test + fun testShouldNotPeek_legacySuppressAwakeHeadsUp() { + ensurePeekState() + provider.addLegacySuppressor(alwaysSuppressesAwakeHeadsUp) + assertShouldNotHeadsUp(buildPeekEntry()) } @Test fun testShouldPulse() { - ensureStateForPulse() + ensurePulseState() + assertShouldHeadsUp(buildPulseEntry()) + } - assertTrue(provider.makeUnloggedHeadsUpDecision(createPulseEntry()).shouldInterrupt) + @Test + fun testShouldPulse_defaultLegacySuppressor() { + ensurePulseState() + provider.addLegacySuppressor(neverSuppresses) + assertShouldHeadsUp(buildPulseEntry()) } @Test - fun testShouldFsi_awake() { - ensureStateForAwakeFsi() + fun testShouldNotPulse_legacySuppressInterruptions() { + ensurePulseState() + provider.addLegacySuppressor(alwaysSuppressesInterruptions) + assertShouldNotHeadsUp(buildPulseEntry()) + } - assertTrue(provider.makeUnloggedFullScreenIntentDecision(createFsiEntry()).shouldInterrupt) + @Test + fun testShouldPulse_legacySuppressAwakeInterruptions() { + ensurePulseState() + provider.addLegacySuppressor(alwaysSuppressesAwakeInterruptions) + assertShouldHeadsUp(buildPulseEntry()) } @Test - fun testShouldFsi_dreaming() { - ensureStateForDreamingFsi() + fun testShouldPulse_legacySuppressAwakeHeadsUp() { + ensurePulseState() + provider.addLegacySuppressor(alwaysSuppressesAwakeHeadsUp) + assertShouldHeadsUp(buildPulseEntry()) + } - assertTrue(provider.makeUnloggedFullScreenIntentDecision(createFsiEntry()).shouldInterrupt) + @Test + fun testShouldNotPulse_disabled() { + ensurePulseState { pulseOnNotificationsEnabled = false } + assertShouldNotHeadsUp(buildPulseEntry()) } @Test - fun testShouldFsi_keyguard() { - ensureStateForKeyguardFsi() + fun testShouldNotPulse_batterySaver() { + ensurePulseState { isAodPowerSave = true } + assertShouldNotHeadsUp(buildPulseEntry()) + } + + @Test + fun testShouldNotPulse_effectSuppressed() { + ensurePulseState() + assertShouldNotHeadsUp( + buildPulseEntry { suppressedVisualEffects = SUPPRESSED_EFFECT_AMBIENT } + ) + } - assertTrue(provider.makeUnloggedFullScreenIntentDecision(createFsiEntry()).shouldInterrupt) + @Test + fun testShouldNotPulse_visibilityOverridePrivate() { + ensurePulseState() + assertShouldNotHeadsUp(buildPulseEntry { visibilityOverride = VISIBILITY_PRIVATE }) + } + + @Test + fun testShouldNotPulse_importanceLow() { + ensurePulseState() + assertShouldNotHeadsUp(buildPulseEntry { importance = IMPORTANCE_LOW }) } @Test fun testShouldBubble() { - assertTrue(provider.makeAndLogBubbleDecision(createBubbleEntry()).shouldInterrupt) + ensureBubbleState() + assertShouldBubble(buildBubbleEntry()) } - private fun ensureStateForPeek() { - whenever(powerManager.isScreenOn).thenReturn(true) - statusBarStateController.dozing = false - statusBarStateController.dreaming = false + @Test + fun testShouldBubble_defaultLegacySuppressor() { + ensureBubbleState() + provider.addLegacySuppressor(neverSuppresses) + assertShouldBubble(buildBubbleEntry()) } - private fun ensureStateForPulse() { - ambientDisplayConfiguration.fakePulseOnNotificationEnabled = true - batteryController.setIsAodPowerSave(false) - statusBarStateController.dozing = true + @Test + fun testShouldNotBubble_legacySuppressInterruptions() { + ensureBubbleState() + provider.addLegacySuppressor(alwaysSuppressesInterruptions) + assertShouldNotBubble(buildBubbleEntry()) } - private fun ensureStateForAwakeFsi() { - whenever(powerManager.isInteractive).thenReturn(false) - statusBarStateController.dreaming = false - statusBarStateController.state = SHADE + @Test + fun testShouldNotBubble_legacySuppressAwakeInterruptions() { + ensureBubbleState() + provider.addLegacySuppressor(alwaysSuppressesAwakeInterruptions) + assertShouldNotBubble(buildBubbleEntry()) } - private fun ensureStateForDreamingFsi() { - whenever(powerManager.isInteractive).thenReturn(true) - statusBarStateController.dreaming = true - statusBarStateController.state = SHADE + @Test + fun testShouldBubble_legacySuppressAwakeHeadsUp() { + ensureBubbleState() + provider.addLegacySuppressor(alwaysSuppressesAwakeHeadsUp) + assertShouldBubble(buildBubbleEntry()) } - private fun ensureStateForKeyguardFsi() { - whenever(powerManager.isInteractive).thenReturn(true) - statusBarStateController.dreaming = false - statusBarStateController.state = KEYGUARD + @Test + fun testShouldFsi_notInteractive() { + ensureNotInteractiveFsiState() + assertShouldFsi(buildFsiEntry()) } - private fun createNotif( - hasFsi: Boolean = false, - bubbleMetadata: BubbleMetadata? = null - ): Notification { - return Notification.Builder(context, TEST_CHANNEL_ID) - .apply { - setContentTitle(TEST_CONTENT_TITLE) - setContentText(TEST_CONTENT_TEXT) + @Test + fun testShouldFsi_dreaming() { + ensureDreamingFsiState() + assertShouldFsi(buildFsiEntry()) + } - if (hasFsi) { - setFullScreenIntent(mock(), /* highPriority = */ true) - } + @Test + fun testShouldFsi_keyguard() { + ensureKeyguardFsiState() + assertShouldFsi(buildFsiEntry()) + } - if (bubbleMetadata != null) { - setBubbleMetadata(bubbleMetadata) - } + private data class State( + var hunSettingEnabled: Boolean? = null, + var hunSnoozed: Boolean? = null, + var isAodPowerSave: Boolean? = null, + var isDozing: Boolean? = null, + var isDreaming: Boolean? = null, + var isInteractive: Boolean? = null, + var isScreenOn: Boolean? = null, + var keyguardShouldHideNotification: Boolean? = null, + var pulseOnNotificationsEnabled: Boolean? = null, + var statusBarState: Int? = null, + ) + + private fun setState(state: State): Unit = + state.run { + hunSettingEnabled?.let { + val newSetting = if (it) HEADS_UP_ON else HEADS_UP_OFF + globalSettings.putInt(HEADS_UP_NOTIFICATIONS_ENABLED, newSetting) } - .setContentTitle(TEST_CONTENT_TITLE) - .setContentText(TEST_CONTENT_TEXT) - .build() - } - private fun createBubbleMetadata(): BubbleMetadata { - val pendingIntent = - PendingIntent.getActivity( - context, - /* requestCode = */ 0, - Intent().setPackage(context.packageName), - FLAG_MUTABLE - ) + hunSnoozed?.let { whenever(headsUpManager.isSnoozed(TEST_PACKAGE)).thenReturn(it) } - val icon = Icon.createWithResource(context.resources, R.drawable.android) + isAodPowerSave?.let { batteryController.setIsAodPowerSave(it) } - return BubbleMetadata.Builder(pendingIntent, icon).build() - } + isDozing?.let { statusBarStateController.dozing = it } + + isDreaming?.let { statusBarStateController.dreaming = it } + + isInteractive?.let { whenever(powerManager.isInteractive).thenReturn(it) } - private fun createEntry( - notif: Notification, - importance: Int = IMPORTANCE_DEFAULT, - canBubble: Boolean? = null - ): NotificationEntry { - return NotificationEntryBuilder() + isScreenOn?.let { whenever(powerManager.isScreenOn).thenReturn(it) } + + keyguardShouldHideNotification?.let { + whenever(keyguardNotificationVisibilityProvider.shouldHideNotification(any())) + .thenReturn(it) + } + + pulseOnNotificationsEnabled?.let { + ambientDisplayConfiguration.fakePulseOnNotificationEnabled = it + } + + statusBarState?.let { statusBarStateController.state = it } + } + + private fun ensureState(block: State.() -> Unit) = + State() .apply { - setPkg(TEST_PACKAGE) - setOpPkg(TEST_PACKAGE) - setTag(TEST_TAG) - setChannel(NotificationChannel(TEST_CHANNEL_ID, TEST_CHANNEL_NAME, importance)) - setNotification(notif) - setImportance(importance) - - if (canBubble != null) { - setCanBubble(canBubble) - } + keyguardShouldHideNotification = false + apply(block) } - .build() + .run(this::setState) + + private fun ensurePeekState(block: State.() -> Unit = {}) = ensureState { + hunSettingEnabled = true + hunSnoozed = false + isDozing = false + isDreaming = false + isScreenOn = true + run(block) } - private fun createPeekEntry() = createEntry(notif = createNotif(), importance = IMPORTANCE_HIGH) + private fun ensurePulseState(block: State.() -> Unit = {}) = ensureState { + isAodPowerSave = false + isDozing = true + pulseOnNotificationsEnabled = true + run(block) + } + + private fun ensureBubbleState(block: State.() -> Unit = {}) = ensureState(block) + + private fun ensureNotInteractiveFsiState(block: State.() -> Unit = {}) = ensureState { + isDreaming = false + isInteractive = false + statusBarState = SHADE + run(block) + } + + private fun ensureDreamingFsiState(block: State.() -> Unit = {}) = ensureState { + isDreaming = true + isInteractive = true + statusBarState = SHADE + run(block) + } + + private fun ensureKeyguardFsiState(block: State.() -> Unit = {}) = ensureState { + isDreaming = false + isInteractive = true + statusBarState = KEYGUARD + run(block) + } + + private fun assertShouldHeadsUp(entry: NotificationEntry) = + provider.makeUnloggedHeadsUpDecision(entry).let { + assertTrue("unexpected suppressed HUN: ${it.logReason}", it.shouldInterrupt) + } - private fun createPulseEntry() = - createEntry(notif = createNotif(), importance = IMPORTANCE_HIGH).also { - modifyRanking(it).setVisibilityOverride(VISIBILITY_NO_OVERRIDE).build() + private fun assertShouldNotHeadsUp(entry: NotificationEntry) = + provider.makeUnloggedHeadsUpDecision(entry).let { + assertFalse("unexpected unsuppressed HUN: ${it.logReason}", it.shouldInterrupt) } - private fun createFsiEntry() = - createEntry(notif = createNotif(hasFsi = true), importance = IMPORTANCE_HIGH) + private fun assertShouldBubble(entry: NotificationEntry) = + provider.makeAndLogBubbleDecision(entry).let { + assertTrue("unexpected suppressed bubble: ${it.logReason}", it.shouldInterrupt) + } - private fun createBubbleEntry() = - createEntry( - notif = createNotif(bubbleMetadata = createBubbleMetadata()), - importance = IMPORTANCE_HIGH, - canBubble = true - ) + private fun assertShouldNotBubble(entry: NotificationEntry) = + provider.makeAndLogBubbleDecision(entry).let { + assertFalse("unexpected unsuppressed bubble: ${it.logReason}", it.shouldInterrupt) + } + + private fun assertShouldFsi(entry: NotificationEntry) = + provider.makeUnloggedFullScreenIntentDecision(entry).let { + assertTrue("unexpected suppressed FSI: ${it.logReason}", it.shouldInterrupt) + } + + private fun assertShouldNotFsi(entry: NotificationEntry) = + provider.makeUnloggedFullScreenIntentDecision(entry).let { + assertFalse("unexpected unsuppressed FSI: ${it.logReason}", it.shouldInterrupt) + } + + private class EntryBuilder(val context: Context) { + var importance = IMPORTANCE_DEFAULT + var suppressedVisualEffects: Int? = null + var whenMs: Long? = null + var visibilityOverride: Int? = null + var hasFsi = false + var canBubble: Boolean? = null + var isBubble = false + var hasBubbleMetadata = false + var bubbleSuppressNotification: Boolean? = null + + private fun buildBubbleMetadata() = + BubbleMetadata.Builder( + PendingIntent.getActivity( + context, + /* requestCode = */ 0, + Intent().setPackage(context.packageName), + FLAG_MUTABLE + ), + Icon.createWithResource(context.resources, R.drawable.android) + ) + .apply { bubbleSuppressNotification?.let { setSuppressNotification(it) } } + .build() + + fun build() = + Notification.Builder(context, TEST_CHANNEL_ID) + .apply { + setContentTitle(TEST_CONTENT_TITLE) + setContentText(TEST_CONTENT_TEXT) + + if (hasFsi) { + setFullScreenIntent(mock(), /* highPriority = */ true) + } + + whenMs?.let { setWhen(it) } + + if (hasBubbleMetadata) { + setBubbleMetadata(buildBubbleMetadata()) + } + } + .build() + .apply { + if (isBubble) { + flags = flags or FLAG_BUBBLE + } + } + .let { NotificationEntryBuilder().setNotification(it) } + .apply { + setPkg(TEST_PACKAGE) + setOpPkg(TEST_PACKAGE) + setTag(TEST_TAG) + + setImportance(importance) + setChannel(NotificationChannel(TEST_CHANNEL_ID, TEST_CHANNEL_NAME, importance)) + + canBubble?.let { setCanBubble(it) } + } + .build()!! + .also { + modifyRanking(it) + .apply { + suppressedVisualEffects?.let { setSuppressedVisualEffects(it) } + visibilityOverride?.let { setVisibilityOverride(it) } + } + .build() + } + } + + private fun buildEntry(block: EntryBuilder.() -> Unit) = + EntryBuilder(context).also(block).build() + + private fun buildPeekEntry(block: EntryBuilder.() -> Unit = {}) = buildEntry { + importance = IMPORTANCE_HIGH + run(block) + } + + private fun buildPulseEntry(block: EntryBuilder.() -> Unit = {}) = buildEntry { + importance = IMPORTANCE_DEFAULT + visibilityOverride = VISIBILITY_NO_OVERRIDE + run(block) + } + + private fun buildBubbleEntry(block: EntryBuilder.() -> Unit = {}) = buildEntry { + canBubble = true + hasBubbleMetadata = true + run(block) + } + + private fun buildFsiEntry(block: EntryBuilder.() -> Unit = {}) = buildEntry { + importance = IMPORTANCE_HIGH + hasFsi = true + run(block) + } + + private fun whenAgo(whenAgeMs: Long) = systemClock.currentTimeMillis() - whenAgeMs } private const val TEST_CONTENT_TITLE = "Test Content Title" diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/ui/viewmodel/SharedNotificationContainerViewModelTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/ui/viewmodel/SharedNotificationContainerViewModelTest.kt index 60421c981e6d..3a9d111bacf7 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/ui/viewmodel/SharedNotificationContainerViewModelTest.kt +++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/ui/viewmodel/SharedNotificationContainerViewModelTest.kt @@ -314,7 +314,26 @@ class SharedNotificationContainerViewModelTest : SysuiTestCase() { sharedNotificationContainerInteractor.setTopPosition(10f) assertThat(position) - .isEqualTo(SharedNotificationContainerPosition(top = 10f, bottom = 0f)) + .isEqualTo( + SharedNotificationContainerPosition(top = 10f, bottom = 0f, animate = true) + ) + } + + @Test + fun positionOnQS() = + testScope.runTest { + val position by collectLastValue(underTest.position) + + // Start on lockscreen with shade expanded + showLockscreenWithQSExpanded() + + // When not in split shade + sharedNotificationContainerInteractor.setTopPosition(10f) + + assertThat(position) + .isEqualTo( + SharedNotificationContainerPosition(top = 10f, bottom = 0f, animate = false) + ) } @Test @@ -390,6 +409,17 @@ class SharedNotificationContainerViewModelTest : SysuiTestCase() { ) } + private suspend fun TestScope.showLockscreenWithQSExpanded() { + shadeRepository.setLockscreenShadeExpansion(0f) + shadeRepository.setQsExpansion(1f) + keyguardRepository.setStatusBarState(StatusBarState.SHADE_LOCKED) + keyguardTransitionRepository.sendTransitionSteps( + from = KeyguardState.AOD, + to = KeyguardState.LOCKSCREEN, + this, + ) + } + @SysUISingleton @Component( modules = diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/CentralSurfacesImplTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/CentralSurfacesImplTest.java index 05fd6d22f961..4a20f831a781 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/CentralSurfacesImplTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/CentralSurfacesImplTest.java @@ -20,6 +20,8 @@ import static android.app.NotificationManager.IMPORTANCE_HIGH; import static android.app.NotificationManager.Policy.SUPPRESSED_EFFECT_PEEK; import static android.app.StatusBarManager.WINDOW_STATE_HIDDEN; import static android.app.StatusBarManager.WINDOW_STATE_SHOWING; +import static android.provider.Settings.Global.HEADS_UP_NOTIFICATIONS_ENABLED; +import static android.provider.Settings.Global.HEADS_UP_ON; import static com.android.systemui.statusbar.StatusBarState.KEYGUARD; import static com.android.systemui.statusbar.StatusBarState.SHADE; @@ -51,7 +53,6 @@ import android.app.NotificationChannel; import android.app.WallpaperManager; import android.app.trust.TrustManager; import android.content.BroadcastReceiver; -import android.content.ContentResolver; import android.content.IntentFilter; import android.hardware.devicestate.DeviceStateManager; import android.hardware.display.AmbientDisplayConfiguration; @@ -180,11 +181,16 @@ import com.android.systemui.util.WallpaperController; import com.android.systemui.util.concurrency.FakeExecutor; import com.android.systemui.util.concurrency.MessageRouterImpl; import com.android.systemui.util.kotlin.JavaAdapter; +import com.android.systemui.util.settings.FakeGlobalSettings; +import com.android.systemui.util.settings.GlobalSettings; import com.android.systemui.util.time.FakeSystemClock; +import com.android.systemui.util.time.SystemClock; import com.android.systemui.volume.VolumeComponent; import com.android.wm.shell.bubbles.Bubbles; import com.android.wm.shell.startingsurface.StartingSurface; +import dagger.Lazy; + import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; @@ -198,8 +204,6 @@ import java.util.Optional; import javax.inject.Provider; -import dagger.Lazy; - @SmallTest @RunWith(AndroidTestingRunner.class) @RunWithLooper(setAsMainLooper = true) @@ -319,6 +323,7 @@ public class CentralSurfacesImplTest extends SysuiTestCase { private ShadeController mShadeController; private final FakeSystemClock mFakeSystemClock = new FakeSystemClock(); + private final FakeGlobalSettings mFakeGlobalSettings = new FakeGlobalSettings(); private final FakeExecutor mMainExecutor = new FakeExecutor(mFakeSystemClock); private final FakeExecutor mUiBgExecutor = new FakeExecutor(mFakeSystemClock); private final FakeFeatureFlags mFeatureFlags = new FakeFeatureFlags(); @@ -349,8 +354,10 @@ public class CentralSurfacesImplTest extends SysuiTestCase { mPowerManager = new PowerManager(mContext, mPowerManagerService, thermalService, Handler.createAsync(Looper.myLooper())); + mFakeGlobalSettings.putInt(HEADS_UP_NOTIFICATIONS_ENABLED, HEADS_UP_ON); + mNotificationInterruptStateProvider = - new TestableNotificationInterruptStateProviderImpl(mContext.getContentResolver(), + new TestableNotificationInterruptStateProviderImpl( mPowerManager, mAmbientDisplayConfiguration, mStatusBarStateController, @@ -363,7 +370,9 @@ public class CentralSurfacesImplTest extends SysuiTestCase { mock(KeyguardNotificationVisibilityProvider.class), mock(UiEventLogger.class), mUserTracker, - mDeviceProvisionedController); + mDeviceProvisionedController, + mFakeSystemClock, + mFakeGlobalSettings); mContext.addMockSystemService(TrustManager.class, mock(TrustManager.class)); mContext.addMockSystemService(FingerprintManager.class, mock(FingerprintManager.class)); @@ -1162,7 +1171,6 @@ public class CentralSurfacesImplTest extends SysuiTestCase { NotificationInterruptStateProviderImpl { TestableNotificationInterruptStateProviderImpl( - ContentResolver contentResolver, PowerManager powerManager, AmbientDisplayConfiguration ambientDisplayConfiguration, StatusBarStateController controller, @@ -1175,9 +1183,10 @@ public class CentralSurfacesImplTest extends SysuiTestCase { KeyguardNotificationVisibilityProvider keyguardNotificationVisibilityProvider, UiEventLogger uiEventLogger, UserTracker userTracker, - DeviceProvisionedController deviceProvisionedController) { + DeviceProvisionedController deviceProvisionedController, + SystemClock systemClock, + GlobalSettings globalSettings) { super( - contentResolver, powerManager, ambientDisplayConfiguration, batteryController, @@ -1190,7 +1199,9 @@ public class CentralSurfacesImplTest extends SysuiTestCase { keyguardNotificationVisibilityProvider, uiEventLogger, userTracker, - deviceProvisionedController + deviceProvisionedController, + systemClock, + globalSettings ); mUseHeadsUp = true; } diff --git a/packages/SystemUI/tests/src/com/android/systemui/wmshell/BubblesTest.java b/packages/SystemUI/tests/src/com/android/systemui/wmshell/BubblesTest.java index ec808c796d46..8309b85620bd 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/wmshell/BubblesTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/wmshell/BubblesTest.java @@ -18,6 +18,8 @@ package com.android.systemui.wmshell; import static android.app.Notification.FLAG_BUBBLE; import static android.app.PendingIntent.FLAG_MUTABLE; +import static android.provider.Settings.Global.HEADS_UP_NOTIFICATIONS_ENABLED; +import static android.provider.Settings.Global.HEADS_UP_ON; import static android.service.notification.NotificationListenerService.NOTIFICATION_CHANNEL_OR_GROUP_DELETED; import static android.service.notification.NotificationListenerService.NOTIFICATION_CHANNEL_OR_GROUP_UPDATED; import static android.service.notification.NotificationListenerService.REASON_APP_CANCEL; @@ -157,6 +159,8 @@ import com.android.systemui.statusbar.policy.ZenModeController; import com.android.systemui.statusbar.policy.data.repository.FakeDeviceProvisioningRepository; import com.android.systemui.user.domain.interactor.SelectedUserInteractor; import com.android.systemui.user.domain.interactor.UserSwitcherInteractor; +import com.android.systemui.util.settings.FakeGlobalSettings; +import com.android.systemui.util.time.SystemClock; import com.android.wm.shell.ShellTaskOrganizer; import com.android.wm.shell.WindowManagerShellWrapper; import com.android.wm.shell.bubbles.Bubble; @@ -476,7 +480,6 @@ public class BubblesTest extends SysuiTestCase { mKeyguardStateController, mScreenOffAnimationController, mAuthController, - mShadeExpansionStateManager, () -> mShadeInteractor, mShadeWindowLogger, () -> mSelectedUserInteractor @@ -507,8 +510,11 @@ public class BubblesTest extends SysuiTestCase { when(mUserManager.getProfiles(ActivityManager.getCurrentUser())).thenReturn( Collections.singletonList(mock(UserInfo.class))); + final FakeGlobalSettings fakeGlobalSettings = new FakeGlobalSettings(); + fakeGlobalSettings.putInt(HEADS_UP_NOTIFICATIONS_ENABLED, HEADS_UP_ON); + TestableNotificationInterruptStateProviderImpl interruptionStateProvider = - new TestableNotificationInterruptStateProviderImpl(mContext.getContentResolver(), + new TestableNotificationInterruptStateProviderImpl( mock(PowerManager.class), mock(AmbientDisplayConfiguration.class), mock(StatusBarStateController.class), @@ -521,7 +527,9 @@ public class BubblesTest extends SysuiTestCase { mock(KeyguardNotificationVisibilityProvider.class), mock(UiEventLogger.class), mock(UserTracker.class), - mock(DeviceProvisionedController.class) + mock(DeviceProvisionedController.class), + mock(SystemClock.class), + fakeGlobalSettings ); mShellTaskOrganizer = new ShellTaskOrganizer(mock(ShellInit.class), diff --git a/packages/SystemUI/tests/src/com/android/systemui/wmshell/TestableNotificationInterruptStateProviderImpl.java b/packages/SystemUI/tests/src/com/android/systemui/wmshell/TestableNotificationInterruptStateProviderImpl.java index 0df235dd2416..975555c1a46b 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/wmshell/TestableNotificationInterruptStateProviderImpl.java +++ b/packages/SystemUI/tests/src/com/android/systemui/wmshell/TestableNotificationInterruptStateProviderImpl.java @@ -16,7 +16,6 @@ package com.android.systemui.wmshell; -import android.content.ContentResolver; import android.hardware.display.AmbientDisplayConfiguration; import android.os.Handler; import android.os.PowerManager; @@ -32,12 +31,13 @@ import com.android.systemui.statusbar.policy.BatteryController; import com.android.systemui.statusbar.policy.DeviceProvisionedController; import com.android.systemui.statusbar.policy.HeadsUpManager; import com.android.systemui.statusbar.policy.KeyguardStateController; +import com.android.systemui.util.settings.GlobalSettings; +import com.android.systemui.util.time.SystemClock; public class TestableNotificationInterruptStateProviderImpl extends NotificationInterruptStateProviderImpl { TestableNotificationInterruptStateProviderImpl( - ContentResolver contentResolver, PowerManager powerManager, AmbientDisplayConfiguration ambientDisplayConfiguration, StatusBarStateController statusBarStateController, @@ -50,8 +50,10 @@ public class TestableNotificationInterruptStateProviderImpl KeyguardNotificationVisibilityProvider keyguardNotificationVisibilityProvider, UiEventLogger uiEventLogger, UserTracker userTracker, - DeviceProvisionedController deviceProvisionedController) { - super(contentResolver, + DeviceProvisionedController deviceProvisionedController, + SystemClock systemClock, + GlobalSettings globalSettings) { + super( powerManager, ambientDisplayConfiguration, batteryController, @@ -64,7 +66,9 @@ public class TestableNotificationInterruptStateProviderImpl keyguardNotificationVisibilityProvider, uiEventLogger, userTracker, - deviceProvisionedController); + deviceProvisionedController, + systemClock, + globalSettings); mUseHeadsUp = true; } } diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/qs/tiles/impl/custom/data/repository/FakeCustomTileDefaultsRepository.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/qs/tiles/impl/custom/data/repository/FakeCustomTileDefaultsRepository.kt new file mode 100644 index 000000000000..13910fd5c564 --- /dev/null +++ b/packages/SystemUI/tests/utils/src/com/android/systemui/qs/tiles/impl/custom/data/repository/FakeCustomTileDefaultsRepository.kt @@ -0,0 +1,75 @@ +/* + * Copyright (C) 2023 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.systemui.qs.tiles.impl.custom.data.repository + +import android.content.ComponentName +import android.os.UserHandle +import com.android.systemui.qs.tiles.impl.custom.data.entity.CustomTileDefaults +import kotlinx.coroutines.flow.Flow +import kotlinx.coroutines.flow.MutableSharedFlow +import kotlinx.coroutines.flow.distinctUntilChanged +import kotlinx.coroutines.flow.map + +class FakeCustomTileDefaultsRepository : CustomTileDefaultsRepository { + + private val defaults: MutableMap<DefaultsKey, CustomTileDefaults> = mutableMapOf() + private val defaultsFlow = MutableSharedFlow<DefaultsRequest>() + + private val mutableDefaultsRequests: MutableList<DefaultsRequest> = mutableListOf() + val defaultsRequests: List<DefaultsRequest> = mutableDefaultsRequests + + override fun defaults(user: UserHandle): Flow<CustomTileDefaults> = + defaultsFlow + .distinctUntilChanged { old, new -> + if (new.force) { + false + } else { + old == new + } + } + .map { defaults[DefaultsKey(it.user, it.componentName)]!! } + + override fun requestNewDefaults( + user: UserHandle, + componentName: ComponentName, + force: Boolean + ) { + val request = DefaultsRequest(user, componentName, force) + mutableDefaultsRequests.add(request) + defaultsFlow.tryEmit(request) + } + + fun putDefaults( + user: UserHandle, + componentName: ComponentName, + customTileDefaults: CustomTileDefaults, + ) { + defaults[DefaultsKey(user, componentName)] = customTileDefaults + } + + fun removeDefaults(user: UserHandle, componentName: ComponentName) { + defaults.remove(DefaultsKey(user, componentName)) + } + + data class DefaultsRequest( + val user: UserHandle, + val componentName: ComponentName, + val force: Boolean = false, + ) + + private data class DefaultsKey(val user: UserHandle, val componentName: ComponentName) +} diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/shade/data/repository/FakeShadeRepository.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/shade/data/repository/FakeShadeRepository.kt index 3c49c58580cc..800593fe61a1 100644 --- a/packages/SystemUI/tests/utils/src/com/android/systemui/shade/data/repository/FakeShadeRepository.kt +++ b/packages/SystemUI/tests/utils/src/com/android/systemui/shade/data/repository/FakeShadeRepository.kt @@ -56,6 +56,14 @@ class FakeShadeRepository @Inject constructor() : ShadeRepository { @Deprecated("Use ShadeInteractor instead") override val legacyExpandedOrAwaitingInputTransfer = _legacyExpandedOrAwaitingInputTransfer + private val _legacyIsQsExpanded = MutableStateFlow(false) + @Deprecated("Use ShadeInteractor instead") override val legacyIsQsExpanded = _legacyIsQsExpanded + + @Deprecated("Use ShadeInteractor instead") + override fun setLegacyIsQsExpanded(legacyIsQsExpanded: Boolean) { + _legacyIsQsExpanded.value = legacyIsQsExpanded + } + @Deprecated("Use ShadeInteractor instead") override fun setLegacyExpandedOrAwaitingInputTransfer( legacyExpandedOrAwaitingInputTransfer: Boolean diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/FakeStatusBarStateController.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/FakeStatusBarStateController.kt index 19fdb6ddad02..a65813abd49f 100644 --- a/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/FakeStatusBarStateController.kt +++ b/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/FakeStatusBarStateController.kt @@ -104,7 +104,7 @@ class FakeStatusBarStateController : SysuiStatusBarStateController { override fun isDreaming() = dreaming - override fun setIsDreaming(drreaming: Boolean): Boolean { + override fun setIsDreaming(dreaming: Boolean): Boolean { dreaming != this.dreaming || return false this.dreaming = dreaming callbacks.forEach { it.onDreamingChanged(dreaming) } diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/util/mockito/KotlinMockitoHelpers.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/util/mockito/KotlinMockitoHelpers.kt index 7e0632bddcf9..efccafc95a11 100644 --- a/packages/SystemUI/tests/utils/src/com/android/systemui/util/mockito/KotlinMockitoHelpers.kt +++ b/packages/SystemUI/tests/utils/src/com/android/systemui/util/mockito/KotlinMockitoHelpers.kt @@ -22,47 +22,47 @@ package com.android.systemui.util.mockito * be null"). To fix this, we can use methods that modify the return type to be nullable. This * causes Kotlin to skip the null checks. */ - import org.mockito.ArgumentCaptor import org.mockito.ArgumentMatcher +import org.mockito.MockSettings import org.mockito.Mockito import org.mockito.Mockito.`when` +import org.mockito.Mockito.withSettings import org.mockito.stubbing.OngoingStubbing import org.mockito.stubbing.Stubber /** - * Returns Mockito.eq() as nullable type to avoid java.lang.IllegalStateException when - * null is returned. + * Returns Mockito.eq() as nullable type to avoid java.lang.IllegalStateException when null is + * returned. * * Generic T is nullable because implicitly bounded by Any?. */ fun <T> eq(obj: T): T = Mockito.eq<T>(obj) ?: obj /** - * Returns Mockito.any() as nullable type to avoid java.lang.IllegalStateException when - * null is returned. + * Returns Mockito.any() as nullable type to avoid java.lang.IllegalStateException when null is + * returned. * * Generic T is nullable because implicitly bounded by Any?. */ fun <T> any(type: Class<T>): T = Mockito.any<T>(type) + inline fun <reified T> any(): T = any(T::class.java) /** - * Returns Mockito.argThat() as nullable type to avoid java.lang.IllegalStateException when - * null is returned. + * Returns Mockito.argThat() as nullable type to avoid java.lang.IllegalStateException when null is + * returned. * * Generic T is nullable because implicitly bounded by Any?. */ fun <T> argThat(matcher: ArgumentMatcher<T>): T = Mockito.argThat(matcher) -/** - * Kotlin type-inferred version of Mockito.nullable() - */ +/** Kotlin type-inferred version of Mockito.nullable() */ inline fun <reified T> nullable(): T? = Mockito.nullable(T::class.java) /** - * Returns ArgumentCaptor.capture() as nullable type to avoid java.lang.IllegalStateException - * when null is returned. + * Returns ArgumentCaptor.capture() as nullable type to avoid java.lang.IllegalStateException when + * null is returned. * * Generic T is nullable because implicitly bounded by Any?. */ @@ -74,7 +74,7 @@ fun <T> capture(argumentCaptor: ArgumentCaptor<T>): T = argumentCaptor.capture() * Generic T is nullable because implicitly bounded by Any?. */ inline fun <reified T : Any> argumentCaptor(): ArgumentCaptor<T> = - ArgumentCaptor.forClass(T::class.java) + ArgumentCaptor.forClass(T::class.java) /** * Helper function for creating new mocks, without the need to pass in a [Class] instance. @@ -83,8 +83,8 @@ inline fun <reified T : Any> argumentCaptor(): ArgumentCaptor<T> = * * @param apply builder function to simplify stub configuration by improving type inference. */ -inline fun <reified T : Any> mock(apply: T.() -> Unit = {}): T = Mockito.mock(T::class.java) - .apply(apply) +inline fun <reified T : Any> mock(settings: MockSettings? = null, apply: T.() -> Unit = {}): T = + Mockito.mock(T::class.java, settings ?: withSettings()).apply(apply) /** * Helper function for stubbing methods without the need to use backticks. @@ -92,6 +92,7 @@ inline fun <reified T : Any> mock(apply: T.() -> Unit = {}): T = Mockito.mock(T: * @see Mockito.when */ fun <T> whenever(methodCall: T): OngoingStubbing<T> = `when`(methodCall) + fun <T> Stubber.whenever(mock: T): T = `when`(mock) /** @@ -115,34 +116,32 @@ class KotlinArgumentCaptor<T> constructor(clazz: Class<T>) { * Generic T is nullable because implicitly bounded by Any?. */ inline fun <reified T : Any> kotlinArgumentCaptor(): KotlinArgumentCaptor<T> = - KotlinArgumentCaptor(T::class.java) + KotlinArgumentCaptor(T::class.java) /** * Helper function for creating and using a single-use ArgumentCaptor in kotlin. * - * val captor = argumentCaptor<Foo>() - * verify(...).someMethod(captor.capture()) - * val captured = captor.value + * val captor = argumentCaptor<Foo>() verify(...).someMethod(captor.capture()) val captured = + * captor.value * * becomes: * - * val captured = withArgCaptor<Foo> { verify(...).someMethod(capture()) } + * val captured = withArgCaptor<Foo> { verify(...).someMethod(capture()) } * * NOTE: this uses the KotlinArgumentCaptor to avoid the NullPointerException. */ inline fun <reified T : Any> withArgCaptor(block: KotlinArgumentCaptor<T>.() -> Unit): T = - kotlinArgumentCaptor<T>().apply { block() }.value + kotlinArgumentCaptor<T>().apply { block() }.value /** * Variant of [withArgCaptor] for capturing multiple arguments. * - * val captor = argumentCaptor<Foo>() - * verify(...).someMethod(captor.capture()) - * val captured: List<Foo> = captor.allValues + * val captor = argumentCaptor<Foo>() verify(...).someMethod(captor.capture()) val captured: + * List<Foo> = captor.allValues * * becomes: * - * val capturedList = captureMany<Foo> { verify(...).someMethod(capture()) } + * val capturedList = captureMany<Foo> { verify(...).someMethod(capture()) } */ inline fun <reified T : Any> captureMany(block: KotlinArgumentCaptor<T>.() -> Unit): List<T> = - kotlinArgumentCaptor<T>().apply{ block() }.allValues + kotlinArgumentCaptor<T>().apply { block() }.allValues diff --git a/packages/SystemUI/tools/lint/baseline.xml b/packages/SystemUI/tools/lint/baseline.xml index 301c9b831c3b..43f830006504 100644 --- a/packages/SystemUI/tools/lint/baseline.xml +++ b/packages/SystemUI/tools/lint/baseline.xml @@ -1271,17 +1271,6 @@ </issue> <issue - id="MergeRootFrame" - message="This `<FrameLayout>` can be replaced with a `<merge>` tag" - errorLine1="<FrameLayout" - errorLine2="^"> - <location - file="res/layout/volume_dnd_icon.xml" - line="16" - column="1"/> - </issue> - - <issue id="InefficientWeight" message="Use a `layout_height` of `0dp` instead of `wrap_content` for better performance" errorLine1=" android:layout_height="wrap_content"" @@ -88853,17 +88842,6 @@ errorLine1=" <ImageView" errorLine2=" ^"> <location - file="res/layout/volume_dnd_icon.xml" - line="23" - column="5"/> - </issue> - - <issue - id="ContentDescription" - message="[Accessibility] Missing `contentDescription` attribute on image" - errorLine1=" <ImageView" - errorLine2=" ^"> - <location file="res/layout/wireless_charging_layout.xml" line="26" column="5"/> @@ -89783,15 +89761,4 @@ column="22"/> </issue> - <issue - id="RtlHardcoded" - message="Use "`end`" instead of "`right`" to ensure correct behavior in right-to-left locales" - errorLine1=" android:layout_gravity="right|top"" - errorLine2=" ~~~~~~~~~"> - <location - file="res/layout/volume_dnd_icon.xml" - line="26" - column="33"/> - </issue> - </issues> diff --git a/services/Android.bp b/services/Android.bp index aca8409c284f..f1534b461607 100644 --- a/services/Android.bp +++ b/services/Android.bp @@ -41,7 +41,10 @@ soong_config_module_type { name: "system_optimized_java_defaults", module_type: "java_defaults", config_namespace: "ANDROID", - bool_variables: ["SYSTEM_OPTIMIZE_JAVA"], + bool_variables: [ + "SYSTEM_OPTIMIZE_JAVA", + "FULL_SYSTEM_OPTIMIZE_JAVA", + ], properties: [ "optimize", "dxflags", @@ -56,6 +59,7 @@ system_optimized_java_defaults { enabled: true, // TODO(b/210510433): Enable optimizations after improving // retracing infra. + // See also FULL_SYSTEM_OPTIMIZE_JAVA. optimize: false, shrink: true, ignore_warnings: false, @@ -81,6 +85,12 @@ system_optimized_java_defaults { dxflags: ["--debug"], }, }, + // Allow form factors to opt-in full system java optimization + FULL_SYSTEM_OPTIMIZE_JAVA: { + optimize: { + optimize: true, + }, + }, }, } diff --git a/services/accessibility/java/com/android/server/accessibility/AccessibilityManagerService.java b/services/accessibility/java/com/android/server/accessibility/AccessibilityManagerService.java index 32666e76372b..bb50a991d9c1 100644 --- a/services/accessibility/java/com/android/server/accessibility/AccessibilityManagerService.java +++ b/services/accessibility/java/com/android/server/accessibility/AccessibilityManagerService.java @@ -3406,7 +3406,8 @@ public class AccessibilityManagerService extends IAccessibilityManager.Stub // displays in one display. It's not a real display and there's no input events for it. final ArrayList<Display> displays = getValidDisplayList(); if (userState.isMagnificationSingleFingerTripleTapEnabledLocked() - || userState.isMagnificationTwoFingerTripleTapEnabledLocked() + || (Flags.enableMagnificationMultipleFingerMultipleTapGesture() + && userState.isMagnificationTwoFingerTripleTapEnabledLocked()) || userState.isShortcutMagnificationEnabledLocked()) { for (int i = 0; i < displays.size(); i++) { final Display display = displays.get(i); @@ -3435,7 +3436,9 @@ public class AccessibilityManagerService extends IAccessibilityManager.Stub return; } final boolean connect = (userState.isShortcutMagnificationEnabledLocked() - || userState.isMagnificationSingleFingerTripleTapEnabledLocked()) + || userState.isMagnificationSingleFingerTripleTapEnabledLocked() + || (Flags.enableMagnificationMultipleFingerMultipleTapGesture() + && userState.isMagnificationTwoFingerTripleTapEnabledLocked())) && (userState.getMagnificationCapabilitiesLocked() != Settings.Secure.ACCESSIBILITY_MAGNIFICATION_MODE_FULLSCREEN) || userHasMagnificationServicesLocked(userState); @@ -5133,6 +5136,8 @@ public class AccessibilityManagerService extends IAccessibilityManager.Stub // Remove magnification button UI when the magnification capability is not all mode or // magnification is disabled. if (!(userState.isMagnificationSingleFingerTripleTapEnabledLocked() + || (Flags.enableMagnificationMultipleFingerMultipleTapGesture() + && userState.isMagnificationTwoFingerTripleTapEnabledLocked()) || userState.isShortcutMagnificationEnabledLocked()) || userState.getMagnificationCapabilitiesLocked() != Settings.Secure.ACCESSIBILITY_MAGNIFICATION_MODE_ALL) { diff --git a/services/companion/java/com/android/server/companion/virtual/VirtualDeviceImpl.java b/services/companion/java/com/android/server/companion/virtual/VirtualDeviceImpl.java index a0363833914a..ae8fddfd35ef 100644 --- a/services/companion/java/com/android/server/companion/virtual/VirtualDeviceImpl.java +++ b/services/companion/java/com/android/server/companion/virtual/VirtualDeviceImpl.java @@ -23,6 +23,7 @@ import static android.companion.virtual.VirtualDeviceParams.ACTIVITY_POLICY_DEFA import static android.companion.virtual.VirtualDeviceParams.DEVICE_POLICY_DEFAULT; import static android.companion.virtual.VirtualDeviceParams.NAVIGATION_POLICY_DEFAULT_ALLOWED; import static android.companion.virtual.VirtualDeviceParams.POLICY_TYPE_ACTIVITY; +import static android.companion.virtual.VirtualDeviceParams.POLICY_TYPE_CLIPBOARD; import static android.companion.virtual.VirtualDeviceParams.POLICY_TYPE_RECENTS; import static android.content.pm.PackageManager.ACTION_REQUEST_PERMISSIONS; import static android.view.WindowManager.LayoutParams.FLAG_SECURE; @@ -665,6 +666,13 @@ final class VirtualDeviceImpl extends IVirtualDevice.Stub } } break; + case POLICY_TYPE_CLIPBOARD: + if (Flags.crossDeviceClipboard()) { + synchronized (mVirtualDeviceLock) { + mDevicePolicies.put(policyType, devicePolicy); + } + } + break; default: throw new IllegalArgumentException("Device policy " + policyType + " cannot be changed at runtime. "); diff --git a/services/contentcapture/java/com/android/server/contentprotection/ContentProtectionAllowlistManager.java b/services/contentcapture/java/com/android/server/contentprotection/ContentProtectionAllowlistManager.java index f77430dae26b..bfb3a381b44c 100644 --- a/services/contentcapture/java/com/android/server/contentprotection/ContentProtectionAllowlistManager.java +++ b/services/contentcapture/java/com/android/server/contentprotection/ContentProtectionAllowlistManager.java @@ -22,6 +22,8 @@ import android.annotation.NonNull; import android.annotation.Nullable; import android.os.Handler; import android.os.UserHandle; +import android.service.contentcapture.IContentProtectionAllowlistCallback; +import android.util.Slog; import com.android.internal.annotations.GuardedBy; import com.android.internal.annotations.VisibleForTesting; @@ -52,6 +54,10 @@ public class ContentProtectionAllowlistManager { @NonNull final PackageMonitor mPackageMonitor; + @VisibleForTesting(visibility = VisibleForTesting.Visibility.PRIVATE) + @NonNull + final IContentProtectionAllowlistCallback mAllowlistCallback; + private final Object mHandlerToken = new Object(); private final Object mLock = new Object(); @@ -74,6 +80,7 @@ public class ContentProtectionAllowlistManager { mHandler = handler; mTimeoutMs = timeoutMs; mPackageMonitor = createPackageMonitor(); + mAllowlistCallback = createAllowlistCallback(); } /** Starts the manager. */ @@ -107,7 +114,7 @@ public class ContentProtectionAllowlistManager { return allowedPackages.contains(packageName); } - private void setAllowlist(@NonNull List<String> packages) { + private void handleUpdateAllowlistResponse(@NonNull List<String> packages) { synchronized (mLock) { mAllowedPackages = packages.stream().collect(Collectors.toUnmodifiableSet()); } @@ -115,14 +122,14 @@ public class ContentProtectionAllowlistManager { } private void handleInitialUpdate() { - handleUpdate(); + handlePackagesChanged(); // Initial update done, start listening to package updates now mPackageMonitor.register( mContentCaptureManagerService.getContext(), UserHandle.ALL, mHandler); } - private void handleUpdate() { + private void handlePackagesChanged() { if (!blocklistUpdateEnabled()) { return; } @@ -145,6 +152,12 @@ public class ContentProtectionAllowlistManager { // If there are any pending updates queued already, they can be removed immediately mHandler.removeCallbacksAndMessages(mHandlerToken); mUpdatePendingUntil = Instant.now().plusMillis(mTimeoutMs); + + try { + remoteContentProtectionService.onUpdateAllowlistRequest(mAllowlistCallback); + } catch (Exception ex) { + Slog.e(TAG, "Failed to call remote service", ex); + } } /** @hide */ @@ -154,12 +167,28 @@ public class ContentProtectionAllowlistManager { return new ContentProtectionPackageMonitor(); } + /** @hide */ + @NonNull + @VisibleForTesting(visibility = VisibleForTesting.Visibility.PRIVATE) + protected IContentProtectionAllowlistCallback createAllowlistCallback() { + return new ContentProtectionAllowlistCallback(); + } + private final class ContentProtectionPackageMonitor extends PackageMonitor { // This callback might be invoked multiple times, for more info refer to the comment above @Override public void onSomePackagesChanged() { - handleUpdate(); + handlePackagesChanged(); + } + } + + private final class ContentProtectionAllowlistCallback + extends IContentProtectionAllowlistCallback.Stub { + + @Override + public void setAllowlist(List<String> packages) { + mHandler.post(() -> handleUpdateAllowlistResponse(packages)); } } } diff --git a/services/core/java/com/android/server/accounts/AccountManagerService.java b/services/core/java/com/android/server/accounts/AccountManagerService.java index bdda95ef58c8..8a801d8f6860 100644 --- a/services/core/java/com/android/server/accounts/AccountManagerService.java +++ b/services/core/java/com/android/server/accounts/AccountManagerService.java @@ -93,6 +93,7 @@ import android.os.StrictMode; import android.os.SystemClock; import android.os.UserHandle; import android.os.UserManager; +import android.provider.Settings; import android.stats.devicepolicy.DevicePolicyEnums; import android.text.TextUtils; import android.util.EventLog; @@ -2346,6 +2347,18 @@ public class AccountManagerService } return; } + if (isFirstAccountRemovalDisabled(account)) { + try { + response.onError( + AccountManager.ERROR_CODE_MANAGEMENT_DISABLED_FOR_ACCOUNT_TYPE, + "User cannot remove the first " + + account.type + + " account on the device."); + } catch (RemoteException re) { + Log.w(TAG, "RemoteException while removing account", re); + } + return; + } final long identityToken = clearCallingIdentity(); UserAccounts accounts = getUserAccounts(userId); cancelNotification(getSigninRequiredNotificationId(accounts, account), accounts); @@ -2395,6 +2408,10 @@ public class AccountManagerService account.type); throw new SecurityException(msg); } + if (isFirstAccountRemovalDisabled(account)) { + Log.e(TAG, "Cannot remove the first " + account.type + " account on the device."); + return false; + } UserAccounts accounts = getUserAccountsForCaller(); final long accountId = accounts.accountsDb.findDeAccountId(account); logRecord( @@ -6426,6 +6443,48 @@ public class AccountManagerService } } + /** + * Returns true if the config_canRemoveOrRenameFirstUser is false, and the given account type + * matches the one provided by config_accountTypeToKeepFirstUser. + */ + private boolean isFirstAccountRemovalDisabled(Account account) { + // Skip if not targeting the first user. + int userId = UserHandle.getCallingUserId(); + if (userId != 0) { + return false; + } + + // Skip if we are allowed to remove/rename first account. + if (mContext.getResources() + .getBoolean(com.android.internal.R.bool.config_canRemoveFirstAccount)) { + return false; + } + + // Skip if needed for testing. + if (Settings.Secure.getIntForUser( + mContext.getContentResolver(), + Settings.Secure.ALLOW_PRIMARY_GAIA_ACCOUNT_REMOVAL_FOR_TESTS, + 0 /* default */, + 0 /* userHandle */) != 0) { + return false; + } + + // Skip if not targeting desired account. + String typeToKeep = + mContext.getResources() + .getString( + com.android.internal.R.string.config_accountTypeToKeepFirstAccount); + if (typeToKeep.isEmpty() || !typeToKeep.equals(account.type)) { + return false; + } + + // Only restrict first account. + UserAccounts accounts = getUserAccounts(0 /* userId */); + Account[] accountsOfType = getAccountsFromCache(accounts, typeToKeep, + Process.SYSTEM_UID, "android" /* packageName */, false); + return accountsOfType.length > 0 && accountsOfType[0].equals(account); + } + private final class AccountManagerInternalImpl extends AccountManagerInternal { private final Object mLock = new Object(); diff --git a/services/core/java/com/android/server/am/ActivityManagerShellCommand.java b/services/core/java/com/android/server/am/ActivityManagerShellCommand.java index 26b23ff72d9d..a95ddf38e659 100644 --- a/services/core/java/com/android/server/am/ActivityManagerShellCommand.java +++ b/services/core/java/com/android/server/am/ActivityManagerShellCommand.java @@ -205,7 +205,7 @@ final class ActivityManagerShellCommand extends ShellCommand { private boolean mAsync; private BroadcastOptions mBroadcastOptions; private boolean mShowSplashScreen; - private boolean mDismissKeyguard; + private boolean mDismissKeyguardIfInsecure; final boolean mDumping; @@ -552,8 +552,8 @@ final class ActivityManagerShellCommand extends ShellCommand { mAsync = true; } else if (opt.equals("--splashscreen-show-icon")) { mShowSplashScreen = true; - } else if (opt.equals("--dismiss-keyguard")) { - mDismissKeyguard = true; + } else if (opt.equals("--dismiss-keyguard-if-insecure")) { + mDismissKeyguardIfInsecure = true; } else { return false; } @@ -714,11 +714,11 @@ final class ActivityManagerShellCommand extends ShellCommand { } options.setSplashScreenStyle(SplashScreen.SPLASH_SCREEN_STYLE_ICON); } - if (mDismissKeyguard) { + if (mDismissKeyguardIfInsecure) { if (options == null) { options = ActivityOptions.makeBasic(); } - options.setDismissKeyguard(); + options.setDismissKeyguardIfInsecure(); } if (mWaitOption) { result = mInternal.startActivityAndWait(null, SHELL_PACKAGE_NAME, null, intent, diff --git a/services/core/java/com/android/server/am/LmkdStatsReporter.java b/services/core/java/com/android/server/am/LmkdStatsReporter.java index 4380b42ee54c..1e4dd648cab5 100644 --- a/services/core/java/com/android/server/am/LmkdStatsReporter.java +++ b/services/core/java/com/android/server/am/LmkdStatsReporter.java @@ -44,6 +44,7 @@ public final class LmkdStatsReporter { private static final int DIRECT_RECL_AND_THRASHING = 5; private static final int LOW_MEM_AND_SWAP_UTIL = 6; private static final int LOW_FILECACHE_AFTER_THRASHING = 7; + private static final int LOW_MEM = 8; /** * Processes the LMK_KILL_OCCURRED packet data diff --git a/services/core/java/com/android/server/am/ProcessList.java b/services/core/java/com/android/server/am/ProcessList.java index 614caffe2f57..7c0797020f03 100644 --- a/services/core/java/com/android/server/am/ProcessList.java +++ b/services/core/java/com/android/server/am/ProcessList.java @@ -36,6 +36,7 @@ import static android.os.Process.killProcessQuiet; import static android.os.Process.startWebView; import static android.system.OsConstants.*; +import static com.android.sdksandbox.flags.Flags.selinuxSdkSandboxAudit; import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_LRU; import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_NETWORK; import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_PROCESSES; @@ -183,6 +184,7 @@ public final class ProcessList { static final String ANDROID_VOLD_APP_DATA_ISOLATION_ENABLED_PROPERTY = "persist.sys.vold_app_data_isolation_enabled"; + private static final String APPLY_SDK_SANDBOX_AUDIT_RESTRICTIONS = ":isSdkSandboxAudit"; private static final String APPLY_SDK_SANDBOX_NEXT_RESTRICTIONS = ":isSdkSandboxNext"; // OOM adjustments for processes in various states: @@ -549,6 +551,10 @@ public final class ProcessList { ActivityManagerGlobalLock mProcLock; + private static final String PROPERTY_APPLY_SDK_SANDBOX_AUDIT_RESTRICTIONS = + "apply_sdk_sandbox_audit_restrictions"; + private static final boolean DEFAULT_APPLY_SDK_SANDBOX_AUDIT_RESTRICTIONS = false; + private static final String PROPERTY_APPLY_SDK_SANDBOX_NEXT_RESTRICTIONS = "apply_sdk_sandbox_next_restrictions"; private static final boolean DEFAULT_APPLY_SDK_SANDBOX_NEXT_RESTRICTIONS = false; @@ -573,6 +579,13 @@ public final class ProcessList { private final Object mLock = new Object(); @GuardedBy("mLock") + private boolean mSdkSandboxApplyRestrictionsAudit = + DeviceConfig.getBoolean( + DeviceConfig.NAMESPACE_ADSERVICES, + PROPERTY_APPLY_SDK_SANDBOX_AUDIT_RESTRICTIONS, + DEFAULT_APPLY_SDK_SANDBOX_AUDIT_RESTRICTIONS); + + @GuardedBy("mLock") private boolean mSdkSandboxApplyRestrictionsNext = DeviceConfig.getBoolean( DeviceConfig.NAMESPACE_ADSERVICES, @@ -593,6 +606,12 @@ public final class ProcessList { DeviceConfig.removeOnPropertiesChangedListener(this); } + boolean applySdkSandboxRestrictionsAudit() { + synchronized (mLock) { + return mSdkSandboxApplyRestrictionsAudit; + } + } + boolean applySdkSandboxRestrictionsNext() { synchronized (mLock) { return mSdkSandboxApplyRestrictionsNext; @@ -608,6 +627,12 @@ public final class ProcessList { } switch (name) { + case PROPERTY_APPLY_SDK_SANDBOX_AUDIT_RESTRICTIONS: + mSdkSandboxApplyRestrictionsAudit = + properties.getBoolean( + PROPERTY_APPLY_SDK_SANDBOX_AUDIT_RESTRICTIONS, + DEFAULT_APPLY_SDK_SANDBOX_AUDIT_RESTRICTIONS); + break; case PROPERTY_APPLY_SDK_SANDBOX_NEXT_RESTRICTIONS: mSdkSandboxApplyRestrictionsNext = properties.getBoolean( @@ -2025,10 +2050,14 @@ public final class ProcessList { String updateSeInfo(ProcessRecord app) { String extraInfo = ""; // By the time the first the SDK sandbox process is started, device config service - // should be available. - if (app.isSdkSandbox - && getProcessListSettingsListener().applySdkSandboxRestrictionsNext()) { - extraInfo = APPLY_SDK_SANDBOX_NEXT_RESTRICTIONS; + // should be available. If both Next and Audit are enabled, Next takes precedence. + if (app.isSdkSandbox) { + if (getProcessListSettingsListener().applySdkSandboxRestrictionsNext()) { + extraInfo = APPLY_SDK_SANDBOX_NEXT_RESTRICTIONS; + } else if (selinuxSdkSandboxAudit() + && getProcessListSettingsListener().applySdkSandboxRestrictionsAudit()) { + extraInfo = APPLY_SDK_SANDBOX_AUDIT_RESTRICTIONS; + } } return app.info.seInfo @@ -2414,6 +2443,18 @@ public final class ProcessList { allowlistedAppDataInfoMap = null; } + boolean bindOverrideSysprops = false; + String[] syspropOverridePkgNames = DeviceConfig.getString( + DeviceConfig.NAMESPACE_APP_COMPAT, + "appcompat_sysprop_override_pkgs", "").split(","); + String[] pkgs = app.getPackageList(); + for (int i = 0; i < pkgs.length; i++) { + if (ArrayUtils.contains(syspropOverridePkgNames, pkgs[i])) { + bindOverrideSysprops = true; + break; + } + } + AppStateTracker ast = mService.mServices.mAppStateTracker; if (ast != null) { final boolean inBgRestricted = ast.isAppBackgroundRestricted( @@ -2436,6 +2477,7 @@ public final class ProcessList { app.info.targetSdkVersion, seInfo, requiredAbi, instructionSet, app.info.dataDir, null, app.info.packageName, app.getDisabledCompatChanges(), + bindOverrideSysprops, new String[]{PROC_START_SEQ_IDENT + app.getStartSeq()}); } else if (hostingRecord.usesAppZygote()) { final AppZygote appZygote = createAppZygoteForProcessIfNeeded(app); @@ -2447,7 +2489,7 @@ public final class ProcessList { app.info.dataDir, null, app.info.packageName, /*zygotePolicyFlags=*/ ZYGOTE_POLICY_FLAG_EMPTY, isTopApp, app.getDisabledCompatChanges(), pkgDataInfoMap, allowlistedAppDataInfoMap, - false, false, + false, false, bindOverrideSysprops, new String[]{PROC_START_SEQ_IDENT + app.getStartSeq()}); } else { regularZygote = true; @@ -2457,6 +2499,7 @@ public final class ProcessList { app.info.dataDir, invokeWith, app.info.packageName, zygotePolicyFlags, isTopApp, app.getDisabledCompatChanges(), pkgDataInfoMap, allowlistedAppDataInfoMap, bindMountAppsData, bindMountAppStorageDirs, + bindOverrideSysprops, new String[]{PROC_START_SEQ_IDENT + app.getStartSeq()}); // By now the process group should have been created by zygote. app.mProcessGroupCreated = true; @@ -3265,12 +3308,17 @@ public final class ProcessList { // Check if we should mark the processrecord for first launch after force-stopping if ((r.getApplicationInfo().flags & ApplicationInfo.FLAG_STOPPED) != 0) { - final boolean wasPackageEverLaunched = mService.getPackageManagerInternal() - .wasPackageEverLaunched(r.getApplicationInfo().packageName, r.userId); - // If the package was launched in the past but is currently stopped, only then it - // should be considered as stopped after use. Do not mark it if it's the first launch. - if (wasPackageEverLaunched) { - r.setWasForceStopped(true); + try { + final boolean wasPackageEverLaunched = mService.getPackageManagerInternal() + .wasPackageEverLaunched(r.getApplicationInfo().packageName, r.userId); + // If the package was launched in the past but is currently stopped, only then it + // should be considered as stopped after use. Do not mark it if it's the + // first launch. + if (wasPackageEverLaunched) { + r.setWasForceStopped(true); + } + } catch (IllegalArgumentException e) { + // App doesn't have state yet, so wasn't forcestopped } } diff --git a/services/core/java/com/android/server/am/UserController.java b/services/core/java/com/android/server/am/UserController.java index 728bacea3380..c5dd01fb8791 100644 --- a/services/core/java/com/android/server/am/UserController.java +++ b/services/core/java/com/android/server/am/UserController.java @@ -1999,25 +1999,26 @@ class UserController implements Handler.Callback { EventLog.writeEvent(EventLogTags.UC_SWITCH_USER, targetUserId); int currentUserId = getCurrentUserId(); UserInfo targetUserInfo = getUserInfo(targetUserId); - if (targetUserId == currentUserId) { - Slogf.i(TAG, "user #" + targetUserId + " is already the current user"); - return true; - } - if (targetUserInfo == null) { - Slogf.w(TAG, "No user info for user #" + targetUserId); - return false; - } - if (!targetUserInfo.supportsSwitchTo()) { - Slogf.w(TAG, "Cannot switch to User #" + targetUserId + ": not supported"); - return false; - } - if (FactoryResetter.isFactoryResetting()) { - Slogf.w(TAG, "Cannot switch to User #" + targetUserId + ": factory reset in progress"); - return false; - } - boolean userSwitchUiEnabled; synchronized (mLock) { + if (targetUserId == currentUserId && mTargetUserId == UserHandle.USER_NULL) { + Slogf.i(TAG, "user #" + targetUserId + " is already the current user"); + return true; + } + if (targetUserInfo == null) { + Slogf.w(TAG, "No user info for user #" + targetUserId); + return false; + } + if (!targetUserInfo.supportsSwitchTo()) { + Slogf.w(TAG, "Cannot switch to User #" + targetUserId + ": not supported"); + return false; + } + if (FactoryResetter.isFactoryResetting()) { + Slogf.w(TAG, "Cannot switch to User #" + targetUserId + + ": factory reset in progress"); + return false; + } + if (!mInitialized) { Slogf.e(TAG, "Cannot switch to User #" + targetUserId + ": UserController not ready yet"); diff --git a/services/core/java/com/android/server/audio/AudioDeviceBroker.java b/services/core/java/com/android/server/audio/AudioDeviceBroker.java index 2336753c88f9..28970750a5ac 100644 --- a/services/core/java/com/android/server/audio/AudioDeviceBroker.java +++ b/services/core/java/com/android/server/audio/AudioDeviceBroker.java @@ -1765,6 +1765,14 @@ public class AudioDeviceBroker { synchronized (mSetModeLock) { synchronized (mDeviceStateLock) { final BtDeviceInfo btInfo = (BtDeviceInfo) msg.obj; + if (btInfo.mState == BluetoothProfile.STATE_CONNECTED + && !mBtHelper.isProfilePoxyConnected(btInfo.mProfile)) { + AudioService.sDeviceLogger.enqueue((new EventLogger.StringEvent( + "msg: MSG_L_SET_BT_ACTIVE_DEVICE " + + "received with null profile proxy: " + + btInfo)).printLog(TAG)); + return; + } @AudioSystem.AudioFormatNativeEnumForBtCodec final int codec = mBtHelper.getA2dpCodecWithFallbackToSBC( btInfo.mDevice, "MSG_L_SET_BT_ACTIVE_DEVICE"); @@ -1909,7 +1917,7 @@ public class AudioDeviceBroker { final BtDeviceInfo btInfo = (BtDeviceInfo) msg.obj; if (btInfo.mDevice == null) break; AudioService.sDeviceLogger.enqueue((new EventLogger.StringEvent( - "msg: onBluetoothActiveDeviceChange " + btInfo)).printLog(TAG)); + "msg: MSG_L_BT_ACTIVE_DEVICE_CHANGE_EXT " + btInfo)).printLog(TAG)); synchronized (mDeviceStateLock) { mDeviceInventory.setBluetoothActiveDevice(btInfo); } diff --git a/services/core/java/com/android/server/audio/AudioDeviceInventory.java b/services/core/java/com/android/server/audio/AudioDeviceInventory.java index d7076899fcb6..e59fd77919c5 100644 --- a/services/core/java/com/android/server/audio/AudioDeviceInventory.java +++ b/services/core/java/com/android/server/audio/AudioDeviceInventory.java @@ -1628,11 +1628,6 @@ public class AudioDeviceInventory { Log.i(TAG, "setBluetoothActiveDevice " + info.toString() + " delay(ms): " + delay); } mDeviceBroker.postBluetoothActiveDevice(info, delay); - if (info.mProfile == BluetoothProfile.HEARING_AID - && info.mState == BluetoothProfile.STATE_CONNECTED) { - mDeviceBroker.setForceUse_Async(AudioSystem.FOR_MEDIA, AudioSystem.FORCE_NONE, - "HEARING_AID set to CONNECTED"); - } } return delay; } @@ -2013,6 +2008,9 @@ public class AudioDeviceInventory { final int hearingAidVolIndex = mDeviceBroker.getVssVolumeForDevice(streamType, AudioSystem.DEVICE_OUT_HEARING_AID); mDeviceBroker.postSetHearingAidVolumeIndex(hearingAidVolIndex, streamType); + + mDeviceBroker.setBluetoothA2dpOnInt(true, false /*fromA2dp*/, eventSource); + AudioDeviceAttributes ada = new AudioDeviceAttributes( AudioSystem.DEVICE_OUT_HEARING_AID, address, name); mAudioSystem.setDeviceConnectionState(ada, diff --git a/services/core/java/com/android/server/audio/BtHelper.java b/services/core/java/com/android/server/audio/BtHelper.java index 7d7e6d000f62..cce6bd2938d1 100644 --- a/services/core/java/com/android/server/audio/BtHelper.java +++ b/services/core/java/com/android/server/audio/BtHelper.java @@ -43,7 +43,6 @@ import com.android.internal.annotations.GuardedBy; import com.android.server.utils.EventLogger; import java.io.PrintWriter; -import java.util.Collections; import java.util.HashMap; import java.util.List; import java.util.Map; @@ -288,6 +287,13 @@ public class BtHelper { if (action.equals(BluetoothHeadset.ACTION_ACTIVE_DEVICE_CHANGED)) { BluetoothDevice btDevice = intent.getParcelableExtra(BluetoothDevice.EXTRA_DEVICE, android.bluetooth.BluetoothDevice.class); + if (btDevice != null && !isProfilePoxyConnected(BluetoothProfile.HEADSET)) { + AudioService.sDeviceLogger.enqueue((new EventLogger.StringEvent( + "onReceiveBtEvent ACTION_ACTIVE_DEVICE_CHANGED " + + "received with null profile proxy for device: " + + btDevice)).printLog(TAG)); + return; + } onSetBtScoActiveDevice(btDevice); } else if (action.equals(BluetoothHeadset.ACTION_AUDIO_STATE_CHANGED)) { int btState = intent.getIntExtra(BluetoothProfile.EXTRA_STATE, -1); @@ -465,7 +471,8 @@ public class BtHelper { @GuardedBy("AudioDeviceBroker.this.mDeviceStateLock") /*package*/ synchronized void onBtProfileDisconnected(int profile) { AudioService.sDeviceLogger.enqueue(new EventLogger.StringEvent( - "BT profile " + BluetoothProfile.getProfileName(profile) + " disconnected")); + "BT profile " + BluetoothProfile.getProfileName(profile) + + " disconnected").printLog(TAG)); switch (profile) { case BluetoothProfile.HEADSET: mBluetoothHeadset = null; @@ -496,7 +503,11 @@ public class BtHelper { /*package*/ synchronized void onBtProfileConnected(int profile, BluetoothProfile proxy) { AudioService.sDeviceLogger.enqueue(new EventLogger.StringEvent( "BT profile " + BluetoothProfile.getProfileName(profile) + " connected to proxy " - + proxy)); + + proxy).printLog(TAG)); + if (proxy == null) { + Log.e(TAG, "onBtProfileConnected: null proxy for profile: " + profile); + return; + } switch (profile) { case BluetoothProfile.HEADSET: onHeadsetProfileConnected((BluetoothHeadset) proxy); @@ -522,36 +533,64 @@ public class BtHelper { } // this part is only for A2DP, LE Audio unicast and Hearing aid - final List<BluetoothDevice> deviceList = proxy.getConnectedDevices(); - if (deviceList.isEmpty()) { + BluetoothAdapter adapter = BluetoothAdapter.getDefaultAdapter(); + if (adapter == null) { + Log.e(TAG, "onBtProfileConnected: Null BluetoothAdapter when connecting profile: " + + BluetoothProfile.getProfileName(profile)); return; } - final BluetoothDevice btDevice = deviceList.get(0); - if (proxy.getConnectionState(btDevice) == BluetoothProfile.STATE_CONNECTED) { - mDeviceBroker.queueOnBluetoothActiveDeviceChanged( - new AudioDeviceBroker.BtDeviceChangedData(btDevice, null, - new BluetoothProfileConnectionInfo(profile), - "mBluetoothProfileServiceListener")); - } else { - mDeviceBroker.queueOnBluetoothActiveDeviceChanged( - new AudioDeviceBroker.BtDeviceChangedData(null, btDevice, - new BluetoothProfileConnectionInfo(profile), - "mBluetoothProfileServiceListener")); + List<BluetoothDevice> activeDevices = adapter.getActiveDevices(profile); + if (activeDevices.isEmpty() || activeDevices.get(0) == null) { + return; + } + AudioDeviceBroker.BtDeviceChangedData data = new AudioDeviceBroker.BtDeviceChangedData( + activeDevices.get(0), null, new BluetoothProfileConnectionInfo(profile), + "mBluetoothProfileServiceListener"); + AudioDeviceBroker.BtDeviceInfo info = + mDeviceBroker.createBtDeviceInfo(data, activeDevices.get(0), + BluetoothProfile.STATE_CONNECTED); + mDeviceBroker.postBluetoothActiveDevice(info, 0 /* delay */); + } + + // @GuardedBy("mDeviceBroker.mSetModeLock") + @GuardedBy("AudioDeviceBroker.this.mDeviceStateLock") + /*package*/ synchronized boolean isProfilePoxyConnected(int profile) { + switch (profile) { + case BluetoothProfile.HEADSET: + return mBluetoothHeadset != null; + case BluetoothProfile.A2DP: + return mA2dp != null; + case BluetoothProfile.HEARING_AID: + return mHearingAid != null; + case BluetoothProfile.LE_AUDIO: + return mLeAudio != null; + case BluetoothProfile.A2DP_SINK: + case BluetoothProfile.LE_AUDIO_BROADCAST: + default: + // return true for profiles that are not managed by the BtHelper because + // the fact that the profile proxy is not connected does not affect + // the device connection handling. + return true; } } // @GuardedBy("mDeviceBroker.mSetModeLock") @GuardedBy("AudioDeviceBroker.this.mDeviceStateLock") - private void onHeadsetProfileConnected(BluetoothHeadset headset) { + private void onHeadsetProfileConnected(@NonNull BluetoothHeadset headset) { // Discard timeout message mDeviceBroker.handleCancelFailureToConnectToBtHeadsetService(); mBluetoothHeadset = headset; BluetoothAdapter adapter = BluetoothAdapter.getDefaultAdapter(); - List<BluetoothDevice> activeDevices = Collections.emptyList(); if (adapter != null) { - activeDevices = adapter.getActiveDevices(BluetoothProfile.HEADSET); + List<BluetoothDevice> activeDevices = + adapter.getActiveDevices(BluetoothProfile.HEADSET); + if (activeDevices.size() > 0 && activeDevices.get(0) != null) { + onSetBtScoActiveDevice(activeDevices.get(0)); + } + } else { + Log.e(TAG, "onHeadsetProfileConnected: Null BluetoothAdapter"); } - onSetBtScoActiveDevice((activeDevices.size() > 0) ? activeDevices.get(0) : null); + // Refresh SCO audio state checkScoAudioState(); if (mScoAudioState != SCO_STATE_ACTIVATE_REQ @@ -559,7 +598,7 @@ public class BtHelper { return; } boolean status = false; - if (mBluetoothHeadset != null && mBluetoothHeadsetDevice != null) { + if (mBluetoothHeadsetDevice != null) { switch (mScoAudioState) { case SCO_STATE_ACTIVATE_REQ: status = connectBluetoothScoAudioHelper( @@ -715,7 +754,8 @@ public class BtHelper { case BluetoothProfile.LE_AUDIO_BROADCAST: AudioService.sDeviceLogger.enqueue(new EventLogger.StringEvent( "BT profile service: connecting " - + BluetoothProfile.getProfileName(profile) + " profile")); + + BluetoothProfile.getProfileName(profile) + + " profile").printLog(TAG)); mDeviceBroker.postBtProfileConnected(profile, proxy); break; @@ -734,7 +774,8 @@ public class BtHelper { case BluetoothProfile.LE_AUDIO_BROADCAST: AudioService.sDeviceLogger.enqueue(new EventLogger.StringEvent( "BT profile service: disconnecting " - + BluetoothProfile.getProfileName(profile) + " profile")); + + BluetoothProfile.getProfileName(profile) + + " profile").printLog(TAG)); mDeviceBroker.postBtProfileDisconnected(profile); break; diff --git a/services/core/java/com/android/server/clipboard/ClipboardService.java b/services/core/java/com/android/server/clipboard/ClipboardService.java index e3c0cf7365ce..b394fb5b3afe 100644 --- a/services/core/java/com/android/server/clipboard/ClipboardService.java +++ b/services/core/java/com/android/server/clipboard/ClipboardService.java @@ -19,6 +19,8 @@ package com.android.server.clipboard; import static android.app.ActivityManagerInternal.ALLOW_FULL_ONLY; import static android.companion.virtual.VirtualDeviceManager.ACTION_VIRTUAL_DEVICE_REMOVED; import static android.companion.virtual.VirtualDeviceManager.EXTRA_VIRTUAL_DEVICE_ID; +import static android.companion.virtual.VirtualDeviceParams.DEVICE_POLICY_CUSTOM; +import static android.companion.virtual.VirtualDeviceParams.POLICY_TYPE_CLIPBOARD; import static android.content.Context.DEVICE_ID_DEFAULT; import static android.content.Context.DEVICE_ID_INVALID; @@ -409,7 +411,7 @@ public class ClipboardService extends SystemService { /** * Determines which deviceId to use for selecting a Clipboard, depending on where a given app - * is running. + * is running and the device's clipboard policy. * * @param requestedDeviceId the requested deviceId passed in from the client side * @param uid the intended app uid @@ -431,28 +433,47 @@ public class ClipboardService extends SystemService { } } - if (requestedDeviceId != DEVICE_ID_DEFAULT) { - // Privileged apps that own the VirtualDevices, or regular apps running on it, can - // request it by id. - if (mVdmInternal.getDeviceOwnerUid(requestedDeviceId) == uid - || virtualDeviceIds.contains(requestedDeviceId)) { - return requestedDeviceId; + // If an app is running on any VirtualDevice, it isn't clear which clipboard they + // should use, unless all of the devices share the default device's clipboard. + boolean allDevicesHaveDefaultClipboard = true; + for (int deviceId : virtualDeviceIds) { + if (!deviceUsesDefaultClipboard(deviceId)) { + allDevicesHaveDefaultClipboard = false; + break; } - return DEVICE_ID_INVALID; } - // The common case is apps running normally (not on a VirtualDevice). - if (virtualDeviceIds.isEmpty()) { - return DEVICE_ID_DEFAULT; + // Apps running on a virtual device may get the default clipboard if all the devices the app + // runs on share that clipboard. Otherwise it's not clear which clipboard to use. + if (requestedDeviceId == DEVICE_ID_DEFAULT) { + return allDevicesHaveDefaultClipboard ? DEVICE_ID_DEFAULT : DEVICE_ID_INVALID; } - // If an app is running on more than one VirtualDevice, it isn't clear which clipboard they - // should use. - if (virtualDeviceIds.size() > 1) { - return DEVICE_ID_INVALID; + // At this point the app wants to access a virtual device clipboard. It may do so if: + // 1. The app owns the VirtualDevice + // 2. The app is present on the VirtualDevice + // 3. The VirtualDevice shares the default device clipboard and all virtual devices that + // the app is running on do the same. + int clipboardDeviceId = deviceUsesDefaultClipboard(requestedDeviceId) + ? DEVICE_ID_DEFAULT + : requestedDeviceId; + + if (mVdmInternal.getDeviceOwnerUid(requestedDeviceId) == uid + || virtualDeviceIds.contains(requestedDeviceId) + || (clipboardDeviceId == DEVICE_ID_DEFAULT && allDevicesHaveDefaultClipboard)) { + return clipboardDeviceId; } - return virtualDeviceIds.valueAt(0); + // Fallback to the device where the app is running, unless it uses the default clipboard. + int fallbackDeviceId = virtualDeviceIds.valueAt(0); + return deviceUsesDefaultClipboard(fallbackDeviceId) ? DEVICE_ID_DEFAULT : fallbackDeviceId; + } + + private boolean deviceUsesDefaultClipboard(int deviceId) { + if (deviceId == DEVICE_ID_DEFAULT || mVdm == null) { + return true; + } + return mVdm.getDevicePolicy(deviceId, POLICY_TYPE_CLIPBOARD) == DEVICE_POLICY_CUSTOM; } /** diff --git a/services/core/java/com/android/server/display/DisplayPowerController.java b/services/core/java/com/android/server/display/DisplayPowerController.java index 915f5db2898b..d8ac52eb8c79 100644 --- a/services/core/java/com/android/server/display/DisplayPowerController.java +++ b/services/core/java/com/android/server/display/DisplayPowerController.java @@ -1978,6 +1978,11 @@ final class DisplayPowerController implements AutomaticBrightnessController.Call || !isDisplayContentVisible || brightnessIsTemporary; if (!skipAnimation && BrightnessSynchronizer.floatEquals( sdrAnimateValue, currentSdrBrightness)) { + // SDR brightness is unchanged, so animate quickly as this is only impacting + // a likely minority amount of display content + // ie, the highlights of an HDR video or UltraHDR image + slowChange = false; + // Going from HDR to no HDR; visually this should be a "no-op" anyway // as the remaining SDR content's brightness should be holding steady // due to the sdr brightness not shifting diff --git a/services/core/java/com/android/server/display/DisplayPowerController2.java b/services/core/java/com/android/server/display/DisplayPowerController2.java index fc596dce8189..a6155da86f9a 100644 --- a/services/core/java/com/android/server/display/DisplayPowerController2.java +++ b/services/core/java/com/android/server/display/DisplayPowerController2.java @@ -1601,6 +1601,11 @@ final class DisplayPowerController2 implements AutomaticBrightnessController.Cal || !isDisplayContentVisible || brightnessIsTemporary; if (!skipAnimation && BrightnessSynchronizer.floatEquals( sdrAnimateValue, currentSdrBrightness)) { + // SDR brightness is unchanged, so animate quickly as this is only impacting + // a likely minority amount of display content + // ie, the highlights of an HDR video or UltraHDR image + slowChange = false; + // Going from HDR to no HDR; visually this should be a "no-op" anyway // as the remaining SDR content's brightness should be holding steady // due to the sdr brightness not shifting diff --git a/services/core/java/com/android/server/inputmethod/InputMethodManagerInternal.java b/services/core/java/com/android/server/inputmethod/InputMethodManagerInternal.java index 08503cb2e9f8..3e46ee29346e 100644 --- a/services/core/java/com/android/server/inputmethod/InputMethodManagerInternal.java +++ b/services/core/java/com/android/server/inputmethod/InputMethodManagerInternal.java @@ -50,6 +50,8 @@ public abstract class InputMethodManagerInternal { /** * Called by the power manager to tell the input method manager whether it * should start watching for wake events. + * + * @param interactive the interactive mode parameter */ public abstract void setInteractive(boolean interactive); @@ -61,16 +63,16 @@ public abstract class InputMethodManagerInternal { /** * Returns the list of installed input methods for the specified user. * - * @param userId The user ID to be queried. - * @return A list of {@link InputMethodInfo}. VR-only IMEs are already excluded. + * @param userId the user ID to be queried + * @return a list of {@link InputMethodInfo}. VR-only IMEs are already excluded */ public abstract List<InputMethodInfo> getInputMethodListAsUser(@UserIdInt int userId); /** * Returns the list of installed input methods that are enabled for the specified user. * - * @param userId The user ID to be queried. - * @return A list of {@link InputMethodInfo} that are enabled for {@code userId}. + * @param userId the user ID to be queried + * @return a list of {@link InputMethodInfo} that are enabled for {@code userId} */ public abstract List<InputMethodInfo> getEnabledInputMethodListAsUser(@UserIdInt int userId); @@ -78,8 +80,10 @@ public abstract class InputMethodManagerInternal { * Called by the Autofill Frameworks to request an {@link InlineSuggestionsRequest} from * the input method. * + * @param userId the user ID to be queried * @param requestInfo information needed to create an {@link InlineSuggestionsRequest}. - * @param cb {@link IInlineSuggestionsRequestCallback} used to pass back the request object. + * @param cb {@link IInlineSuggestionsRequestCallback} used to pass back the request + * object */ public abstract void onCreateInlineSuggestionsRequest(@UserIdInt int userId, InlineSuggestionsRequestInfo requestInfo, IInlineSuggestionsRequestCallback cb); @@ -88,8 +92,8 @@ public abstract class InputMethodManagerInternal { * Force switch to the enabled input method by {@code imeId} for current user. If the input * method with {@code imeId} is not enabled or not installed, do nothing. * - * @param imeId The input method ID to be switched to. - * @param userId The user ID to be queried. + * @param imeId the input method ID to be switched to + * @param userId the user ID to be queried * @return {@code true} if the current input method was successfully switched to the input * method by {@code imeId}; {@code false} the input method with {@code imeId} is not available * to be switched. @@ -100,28 +104,30 @@ public abstract class InputMethodManagerInternal { * Force enable or disable the input method associated with {@code imeId} for given user. If * the input method associated with {@code imeId} is not installed, do nothing. * - * @param imeId The input method ID to be enabled or disabled. + * @param imeId the input method ID to be enabled or disabled * @param enabled {@code true} if the input method associated with {@code imeId} should be - * enabled. - * @param userId The user ID to be queried. + * enabled + * @param userId the user ID to be queried * @return {@code true} if the input method associated with {@code imeId} was successfully - * enabled or disabled, {@code false} if the input method specified is not installed - * or was unable to be enabled/disabled for some other reason. + * enabled or disabled, {@code false} if the input method specified is not installed + * or was unable to be enabled/disabled for some other reason. */ public abstract boolean setInputMethodEnabled(String imeId, boolean enabled, @UserIdInt int userId); /** * Registers a new {@link InputMethodListListener}. + * + * @param listener the listener to add */ public abstract void registerInputMethodListListener(InputMethodListListener listener); /** * Transfers input focus from a given input token to that of the IME window. * - * @param sourceInputToken The source token. - * @param displayId The display hosting the IME window. - * @return {@code true} if the transfer is successful. + * @param sourceInputToken the source token. + * @param displayId the display hosting the IME window + * @return {@code true} if the transfer is successful */ public abstract boolean transferTouchFocusToImeWindow(@NonNull IBinder sourceInputToken, int displayId); @@ -132,7 +138,7 @@ public abstract class InputMethodManagerInternal { * or SystemUI). * * @param windowToken the window token that is now in control, or {@code null} if no client - * window is in control of the IME. + * window is in control of the IME */ public abstract void reportImeControl(@Nullable IBinder windowToken); @@ -163,8 +169,8 @@ public abstract class InputMethodManagerInternal { * Callback when the IInputMethodSession from the accessibility service with the specified * accessibilityConnectionId is created. * - * @param accessibilityConnectionId The connection id of the accessibility service. - * @param session The session passed back from the accessibility service. + * @param accessibilityConnectionId the connection id of the accessibility service + * @param session the session passed back from the accessibility service */ public abstract void onSessionForAccessibilityCreated(int accessibilityConnectionId, IAccessibilityInputMethodSession session); @@ -173,7 +179,7 @@ public abstract class InputMethodManagerInternal { * Unbind the accessibility service with the specified accessibilityConnectionId from current * client. * - * @param accessibilityConnectionId The connection id of the accessibility service. + * @param accessibilityConnectionId the connection id of the accessibility service */ public abstract void unbindAccessibilityFromCurrentClient(int accessibilityConnectionId); @@ -181,7 +187,7 @@ public abstract class InputMethodManagerInternal { * Switch the keyboard layout in response to a keyboard shortcut. * * @param direction {@code 1} to switch to the next subtype, {@code -1} to switch to the - * previous subtype. + * previous subtype */ public abstract void switchKeyboardLayout(int direction); @@ -192,7 +198,7 @@ public abstract class InputMethodManagerInternal { public abstract boolean isAnyInputConnectionActive(); /** - * Fake implementation of {@link InputMethodManagerInternal}. All the methods do nothing. + * Fake implementation of {@link InputMethodManagerInternal}. All the methods do nothing. */ private static final InputMethodManagerInternal NOP = new InputMethodManagerInternal() { @@ -282,7 +288,7 @@ public abstract class InputMethodManagerInternal { }; /** - * @return Global instance if exists. Otherwise, a fallback no-op instance. + * @return Global instance if exists. Otherwise, a fallback no-op instance. */ @NonNull public static InputMethodManagerInternal get() { diff --git a/services/core/java/com/android/server/media/MediaRouter2ServiceImpl.java b/services/core/java/com/android/server/media/MediaRouter2ServiceImpl.java index 744238f9c5eb..d456a7478551 100644 --- a/services/core/java/com/android/server/media/MediaRouter2ServiceImpl.java +++ b/services/core/java/com/android/server/media/MediaRouter2ServiceImpl.java @@ -192,6 +192,7 @@ class MediaRouter2ServiceImpl { // Start of methods that implement MediaRouter2 operations. + @RequiresPermission(Manifest.permission.MEDIA_CONTENT_CONTROL) @NonNull public boolean verifyPackageExists(@NonNull String clientPackageName) { final int pid = Binder.getCallingPid(); @@ -199,11 +200,7 @@ class MediaRouter2ServiceImpl { final long token = Binder.clearCallingIdentity(); try { - mContext.enforcePermission( - Manifest.permission.MEDIA_CONTENT_CONTROL, - pid, - uid, - "Must hold MEDIA_CONTENT_CONTROL permission."); + enforcePrivilegedRoutingPermissions(uid, pid); PackageManager pm = mContext.getPackageManager(); pm.getPackageInfo(clientPackageName, PackageManager.PackageInfoFlags.of(0)); return true; @@ -482,6 +479,7 @@ class MediaRouter2ServiceImpl { } } + @RequiresPermission(Manifest.permission.MEDIA_CONTENT_CONTROL) public void registerManager(@NonNull IMediaRouter2Manager manager, @NonNull String callerPackageName) { Objects.requireNonNull(manager, "manager must not be null"); @@ -729,6 +727,15 @@ class MediaRouter2ServiceImpl { return hasBluetoothRoutingPermission; } + @RequiresPermission(Manifest.permission.MEDIA_CONTENT_CONTROL) + private void enforcePrivilegedRoutingPermissions(int callerUid, int callerPid) { + mContext.enforcePermission( + Manifest.permission.MEDIA_CONTENT_CONTROL, + callerPid, + callerUid, + "Must hold MEDIA_CONTENT_CONTROL permission."); + } + // End of methods that implements operations for both MediaRouter2 and MediaRouter2Manager. public void dump(@NonNull PrintWriter pw, @NonNull String prefix) { @@ -1164,6 +1171,7 @@ class MediaRouter2ServiceImpl { return sessionInfos; } + @RequiresPermission(Manifest.permission.MEDIA_CONTENT_CONTROL) @GuardedBy("mLock") private void registerManagerLocked( @NonNull IMediaRouter2Manager manager, @@ -1187,8 +1195,7 @@ class MediaRouter2ServiceImpl { + " callerUserId: %d", callerUid, callerPid, callerPackageName, callerUserId)); - mContext.enforcePermission(Manifest.permission.MEDIA_CONTENT_CONTROL, callerPid, callerUid, - "Must hold MEDIA_CONTENT_CONTROL permission."); + enforcePrivilegedRoutingPermissions(callerUid, callerPid); UserRecord userRecord = getOrCreateUserRecordLocked(callerUserId); managerRecord = new ManagerRecord( diff --git a/services/core/java/com/android/server/media/MediaRouterService.java b/services/core/java/com/android/server/media/MediaRouterService.java index 44719f88351b..6df4a95f8b8c 100644 --- a/services/core/java/com/android/server/media/MediaRouterService.java +++ b/services/core/java/com/android/server/media/MediaRouterService.java @@ -409,6 +409,7 @@ public final class MediaRouterService extends IMediaRouterService.Stub } // Binder call + @RequiresPermission(Manifest.permission.MEDIA_CONTENT_CONTROL) @Override public boolean verifyPackageExists(String clientPackageName) { return mService2.verifyPackageExists(clientPackageName); @@ -536,6 +537,7 @@ public final class MediaRouterService extends IMediaRouterService.Stub } // Binder call + @RequiresPermission(Manifest.permission.MEDIA_CONTENT_CONTROL) @Override public void registerManager(IMediaRouter2Manager manager, String callerPackageName) { final int uid = Binder.getCallingUid(); diff --git a/services/core/java/com/android/server/notification/NotificationManagerService.java b/services/core/java/com/android/server/notification/NotificationManagerService.java index 4b5d52f0a8de..b2f00a246c23 100755 --- a/services/core/java/com/android/server/notification/NotificationManagerService.java +++ b/services/core/java/com/android/server/notification/NotificationManagerService.java @@ -291,6 +291,7 @@ import com.android.internal.annotations.VisibleForTesting; import com.android.internal.compat.IPlatformCompat; import com.android.internal.config.sysui.SystemUiDeviceConfigFlags; import com.android.internal.config.sysui.SystemUiSystemPropertiesFlags; +import com.android.internal.config.sysui.SystemUiSystemPropertiesFlags.NotificationFlags; import com.android.internal.logging.InstanceId; import com.android.internal.logging.InstanceIdSequence; import com.android.internal.logging.MetricsLogger; @@ -2909,7 +2910,16 @@ public class NotificationManagerService extends SystemService { mPreferencesHelper.updateFixedImportance(mUm.getUsers()); mPreferencesHelper.migrateNotificationPermissions(mUm.getUsers()); } else if (phase == SystemService.PHASE_BOOT_COMPLETED) { - if (expireBitmaps()) { + if (mFlagResolver.isEnabled(NotificationFlags.DEBUG_SHORT_BITMAP_DURATION)) { + new Thread(() -> { + while (true) { + try { + Thread.sleep(5000); + } catch (InterruptedException e) { } + mInternalService.removeBitmaps(); + } + }).start(); + } else if (expireBitmaps()) { NotificationBitmapJobService.scheduleJob(getContext()); } } @@ -6765,7 +6775,14 @@ public class NotificationManagerService extends SystemService { final long timePostedMs = r.getSbn().getPostTime(); final long timeNowMs = System.currentTimeMillis(); - if (isBitmapExpired(timePostedMs, timeNowMs, BITMAP_DURATION.toMillis())) { + final long bitmapDuration; + if (mFlagResolver.isEnabled(NotificationFlags.DEBUG_SHORT_BITMAP_DURATION)) { + bitmapDuration = Duration.ofSeconds(5).toMillis(); + } else { + bitmapDuration = BITMAP_DURATION.toMillis(); + } + + if (isBitmapExpired(timePostedMs, timeNowMs, bitmapDuration)) { removeBitmapAndRepost(r); } } diff --git a/services/core/java/com/android/server/pm/PackageArchiver.java b/services/core/java/com/android/server/pm/PackageArchiver.java index 5cd62872e07b..d5dacce3c8ce 100644 --- a/services/core/java/com/android/server/pm/PackageArchiver.java +++ b/services/core/java/com/android/server/pm/PackageArchiver.java @@ -16,6 +16,7 @@ package com.android.server.pm; +import static android.app.AppOpsManager.MODE_IGNORED; import static android.app.ComponentOptions.MODE_BACKGROUND_ACTIVITY_START_DENIED; import static android.content.pm.ArchivedActivityInfo.bytesFromBitmap; import static android.content.pm.ArchivedActivityInfo.drawableToBitmap; @@ -106,6 +107,9 @@ public class PackageArchiver { @Nullable private LauncherApps mLauncherApps; + @Nullable + private AppOpsManager mAppOpsManager; + PackageArchiver(Context context, PackageManagerService mPm) { this.mContext = context; this.mPm = mPm; @@ -178,6 +182,8 @@ public class PackageArchiver { Binder.getCallingUid(), userId); String responsibleInstallerPackage = getResponsibleInstallerPackage(ps); verifyInstaller(responsibleInstallerPackage, userId); + verifyOptOutStatus(packageName, + UserHandle.getUid(userId, UserHandle.getUid(userId, ps.getAppId()))); List<LauncherActivityInfo> mainActivities = getLauncherActivityInfos(ps.getPackageName(), userId); @@ -308,6 +314,59 @@ public class PackageArchiver { return intentReceivers != null && !intentReceivers.getList().isEmpty(); } + /** + * Returns true if the app is archivable. + */ + // TODO(b/299299569) Exclude system apps + public boolean isAppArchivable(@NonNull String packageName, @NonNull UserHandle user) { + Objects.requireNonNull(packageName); + Objects.requireNonNull(user); + + Computer snapshot = mPm.snapshotComputer(); + int userId = user.getIdentifier(); + int binderUid = Binder.getCallingUid(); + snapshot.enforceCrossUserPermission(binderUid, userId, true, true, + "isAppArchivable"); + PackageStateInternal ps; + try { + ps = getPackageState(packageName, mPm.snapshotComputer(), + Binder.getCallingUid(), userId); + } catch (PackageManager.NameNotFoundException e) { + throw new ParcelableException(e); + } + + if (isAppOptedOutOfArchiving(packageName, ps.getAppId())) { + return false; + } + + try { + verifyInstaller(getResponsibleInstallerPackage(ps), userId); + getLauncherActivityInfos(packageName, userId); + } catch (PackageManager.NameNotFoundException e) { + return false; + } + + return true; + } + + /** + * Returns true if user has opted the app out of archiving through system settings. + */ + // TODO(b/304256918) Switch this to a separate OP code for archiving. + private boolean isAppOptedOutOfArchiving(String packageName, int uid) { + return Binder.withCleanCallingIdentity(() -> + getAppOpsManager().checkOp(AppOpsManager.OP_AUTO_REVOKE_PERMISSIONS_IF_UNUSED, + uid, packageName) == MODE_IGNORED); + } + + private void verifyOptOutStatus(String packageName, int uid) + throws PackageManager.NameNotFoundException { + if (isAppOptedOutOfArchiving(packageName, uid)) { + throw new PackageManager.NameNotFoundException( + TextUtils.formatSimple("The app %s is opted out of archiving.", packageName)); + } + } + void requestUnarchive( @NonNull String packageName, @NonNull String callerPackageName, @@ -510,6 +569,13 @@ public class PackageArchiver { return mLauncherApps; } + private AppOpsManager getAppOpsManager() { + if (mAppOpsManager == null) { + mAppOpsManager = mContext.getSystemService(AppOpsManager.class); + } + return mAppOpsManager; + } + private void storeArchiveState(String packageName, ArchiveState archiveState, int userId) throws PackageManager.NameNotFoundException { synchronized (mPm.mLock) { diff --git a/services/core/java/com/android/server/pm/PackageManagerService.java b/services/core/java/com/android/server/pm/PackageManagerService.java index c9303f2b30a2..638bcbe5822c 100644 --- a/services/core/java/com/android/server/pm/PackageManagerService.java +++ b/services/core/java/com/android/server/pm/PackageManagerService.java @@ -6310,6 +6310,11 @@ public class PackageManagerService implements PackageSender, TestUtilityService return mInstallerService.mPackageArchiver.getArchivedAppIcon(packageName, user); } + @Override + public boolean isAppArchivable(@NonNull String packageName, @NonNull UserHandle user) { + return mInstallerService.mPackageArchiver.isAppArchivable(packageName, user); + } + /** * Wait for the handler to finish handling all pending messages. * @param timeoutMillis Maximum time in milliseconds to wait. diff --git a/services/core/java/com/android/server/pm/UserManagerService.java b/services/core/java/com/android/server/pm/UserManagerService.java index 534f17601b86..c97fbdad9bf4 100644 --- a/services/core/java/com/android/server/pm/UserManagerService.java +++ b/services/core/java/com/android/server/pm/UserManagerService.java @@ -3836,7 +3836,8 @@ public class UserManagerService extends IUserManager.Stub { if (type == XmlPullParser.START_TAG) { final String name = parser.getName(); if (name.equals(TAG_USER)) { - UserData userData = readUserLP(parser.getAttributeInt(null, ATTR_ID)); + UserData userData = readUserLP(parser.getAttributeInt(null, ATTR_ID), + mUserVersion); if (userData != null) { synchronized (mUsersLock) { @@ -4555,7 +4556,7 @@ public class UserManagerService extends IUserManager.Stub { } @GuardedBy({"mPackagesLock"}) - private UserData readUserLP(int id) { + private UserData readUserLP(int id, int userVersion) { try (ResilientAtomicFile file = getUserFile(id)) { FileInputStream fis = null; try { @@ -4564,19 +4565,19 @@ public class UserManagerService extends IUserManager.Stub { Slog.e(LOG_TAG, "User info not found, returning null, user id: " + id); return null; } - return readUserLP(id, fis); + return readUserLP(id, fis, userVersion); } catch (Exception e) { // Remove corrupted file and retry. Slog.e(LOG_TAG, "Error reading user info, user id: " + id); file.failRead(fis, e); - return readUserLP(id); + return readUserLP(id, userVersion); } } } @GuardedBy({"mPackagesLock"}) @VisibleForTesting - UserData readUserLP(int id, InputStream is) throws IOException, + UserData readUserLP(int id, InputStream is, int userVersion) throws IOException, XmlPullParserException { int flags = 0; String userType = null; @@ -4669,7 +4670,17 @@ public class UserManagerService extends IUserManager.Stub { } else if (TAG_DEVICE_POLICY_RESTRICTIONS.equals(tag)) { legacyLocalRestrictions = UserRestrictionsUtils.readRestrictions(parser); } else if (TAG_DEVICE_POLICY_LOCAL_RESTRICTIONS.equals(tag)) { - localRestrictions = UserRestrictionsUtils.readRestrictions(parser); + if (userVersion < 10) { + // Prior to version 10, the local user restrictions were stored as sub tags + // grouped by the user id of the source user. The source is no longer stored + // on versions 10+ as this is now stored in the DevicePolicyEngine. + RestrictionsSet oldLocalRestrictions = + RestrictionsSet.readRestrictions( + parser, TAG_DEVICE_POLICY_LOCAL_RESTRICTIONS); + localRestrictions = oldLocalRestrictions.mergeAll(); + } else { + localRestrictions = UserRestrictionsUtils.readRestrictions(parser); + } } else if (TAG_DEVICE_POLICY_GLOBAL_RESTRICTIONS.equals(tag)) { globalRestrictions = UserRestrictionsUtils.readRestrictions(parser); } else if (TAG_GUEST_RESTRICTIONS.equals(tag)) { diff --git a/services/core/java/com/android/server/policy/PhoneWindowManager.java b/services/core/java/com/android/server/policy/PhoneWindowManager.java index 077812b49cdd..45ca690ba20f 100644 --- a/services/core/java/com/android/server/policy/PhoneWindowManager.java +++ b/services/core/java/com/android/server/policy/PhoneWindowManager.java @@ -19,6 +19,7 @@ package com.android.server.policy; import static android.Manifest.permission.INTERNAL_SYSTEM_WINDOW; import static android.Manifest.permission.SYSTEM_ALERT_WINDOW; import static android.Manifest.permission.SYSTEM_APPLICATION_OVERLAY; +import static android.app.AppOpsManager.OP_CREATE_ACCESSIBILITY_OVERLAY; import static android.app.AppOpsManager.OP_SYSTEM_ALERT_WINDOW; import static android.app.AppOpsManager.OP_TOAST_WINDOW; import static android.content.pm.PackageManager.FEATURE_AUTOMOTIVE; @@ -31,6 +32,7 @@ import static android.os.Build.VERSION_CODES.M; import static android.os.Build.VERSION_CODES.O; import static android.os.IInputConstants.INVALID_INPUT_DEVICE_ID; import static android.provider.Settings.Secure.VOLUME_HUSH_OFF; +import static android.view.contentprotection.flags.Flags.createAccessibilityOverlayAppOpEnabled; import static android.view.Display.DEFAULT_DISPLAY; import static android.view.Display.INVALID_DISPLAY; import static android.view.Display.STATE_OFF; @@ -2992,12 +2994,16 @@ public class PhoneWindowManager implements WindowManagerPolicy { // Window manager does the checking for this. outAppOp[0] = OP_TOAST_WINDOW; return ADD_OKAY; + case TYPE_ACCESSIBILITY_OVERLAY: + if (createAccessibilityOverlayAppOpEnabled()) { + outAppOp[0] = OP_CREATE_ACCESSIBILITY_OVERLAY; + return ADD_OKAY; + } case TYPE_INPUT_METHOD: case TYPE_WALLPAPER: case TYPE_PRESENTATION: case TYPE_PRIVATE_PRESENTATION: case TYPE_VOICE_INTERACTION: - case TYPE_ACCESSIBILITY_OVERLAY: case TYPE_QS_DIALOG: case TYPE_NAVIGATION_BAR_PANEL: // The window manager will check these. diff --git a/services/core/java/com/android/server/wm/ActivityClientController.java b/services/core/java/com/android/server/wm/ActivityClientController.java index 3c8e630dba2b..26f0d34a6261 100644 --- a/services/core/java/com/android/server/wm/ActivityClientController.java +++ b/services/core/java/com/android/server/wm/ActivityClientController.java @@ -1585,7 +1585,7 @@ class ActivityClientController extends IActivityClientController.Stub { * the Activities in the Task should be finished when it finishes. Otherwise, return {@code * false}. */ - private boolean isRelativeTaskRootActivity(ActivityRecord r, ActivityRecord taskRoot) { + private static boolean isRelativeTaskRootActivity(ActivityRecord r, ActivityRecord taskRoot) { // Not a relative root if the given Activity is not the root Activity of its TaskFragment. final TaskFragment taskFragment = r.getTaskFragment(); if (r != taskFragment.getActivity(ar -> !ar.finishing || ar == r, @@ -1598,7 +1598,7 @@ class ActivityClientController extends IActivityClientController.Stub { return taskRoot.getTaskFragment().getCompanionTaskFragment() == taskFragment; } - private boolean isTopActivityInTaskFragment(ActivityRecord activity) { + private static boolean isTopActivityInTaskFragment(ActivityRecord activity) { return activity.getTaskFragment().topRunningActivity() == activity; } @@ -1614,9 +1614,6 @@ class ActivityClientController extends IActivityClientController.Stub { public void onBackPressed(IBinder token, IRequestFinishCallback callback) { final long origId = Binder.clearCallingIdentity(); try { - final Intent baseActivityIntent; - final boolean launchedFromHome; - final boolean isLastRunningActivity; synchronized (mGlobalLock) { final ActivityRecord r = ActivityRecord.isInRootTaskLocked(token); if (r == null) return; @@ -1624,39 +1621,16 @@ class ActivityClientController extends IActivityClientController.Stub { final Task task = r.getTask(); final ActivityRecord root = task.getRootActivity(false /*ignoreRelinquishIdentity*/, true /*setToBottomIfNone*/); - final boolean isTaskRoot = r == root; - if (isTaskRoot) { - if (mService.mWindowOrganizerController.mTaskOrganizerController + if (r == root && mService.mWindowOrganizerController.mTaskOrganizerController .handleInterceptBackPressedOnTaskRoot(r.getRootTask())) { - // This task is handled by a task organizer that has requested the back - // pressed callback. - return; - } - } else if (!isRelativeTaskRootActivity(r, root)) { - // Finish the Activity if the activity is not the task root or relative root. - requestCallbackFinish(callback); + // This task is handled by a task organizer that has requested the back + // pressed callback. + return; + } + if (shouldMoveTaskToBack(r, root)) { + moveActivityTaskToBack(token, true /* nonRoot */); return; } - - isLastRunningActivity = isTopActivityInTaskFragment(isTaskRoot ? root : r); - - final boolean isBaseActivity = root.mActivityComponent.equals(task.realActivity); - baseActivityIntent = isBaseActivity ? root.intent : null; - - launchedFromHome = root.isLaunchSourceType(ActivityRecord.LAUNCH_SOURCE_TYPE_HOME); - } - - // If the activity was launched directly from the home screen, then we should - // refrain from finishing the activity and instead move it to the back to keep it in - // memory. The requirements for this are: - // 1. The activity is the last running activity in the task. - // 2. The current activity is the base activity for the task. - // 3. The activity was launched by the home process, and is one of the main entry - // points for the application. - if (baseActivityIntent != null && isLastRunningActivity - && launchedFromHome && ActivityRecord.isMainIntent(baseActivityIntent)) { - moveActivityTaskToBack(token, true /* nonRoot */); - return; } // The default option for handling the back button is to finish the Activity. @@ -1666,6 +1640,27 @@ class ActivityClientController extends IActivityClientController.Stub { } } + static boolean shouldMoveTaskToBack(ActivityRecord r, ActivityRecord rootActivity) { + if (r != rootActivity && !isRelativeTaskRootActivity(r, rootActivity)) { + return false; + } + final boolean isBaseActivity = rootActivity.mActivityComponent.equals( + r.getTask().realActivity); + final Intent baseActivityIntent = isBaseActivity ? rootActivity.intent : null; + + // If the activity was launched directly from the home screen, then we should + // refrain from finishing the activity and instead move it to the back to keep it in + // memory. The requirements for this are: + // 1. The activity is the last running activity in the task. + // 2. The current activity is the base activity for the task. + // 3. The activity was launched by the home process, and is one of the main entry + // points for the application. + return baseActivityIntent != null + && isTopActivityInTaskFragment(r) + && rootActivity.isLaunchSourceType(ActivityRecord.LAUNCH_SOURCE_TYPE_HOME) + && ActivityRecord.isMainIntent(baseActivityIntent); + } + @Override public void enableTaskLocaleOverride(IBinder token) { if (UserHandle.getAppId(Binder.getCallingUid()) != SYSTEM_UID) { diff --git a/services/core/java/com/android/server/wm/ActivityRecord.java b/services/core/java/com/android/server/wm/ActivityRecord.java index bdab4d483872..b428ed22f94e 100644 --- a/services/core/java/com/android/server/wm/ActivityRecord.java +++ b/services/core/java/com/android/server/wm/ActivityRecord.java @@ -913,7 +913,7 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A boolean mEnteringAnimation; boolean mOverrideTaskTransition; - boolean mDismissKeyguard; + boolean mDismissKeyguardIfInsecure; boolean mShareIdentity; /** True if the activity has reported stopped; False if the activity becomes visible. */ @@ -2098,7 +2098,7 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A } mOverrideTaskTransition = options.getOverrideTaskTransition(); - mDismissKeyguard = options.getDismissKeyguard(); + mDismissKeyguardIfInsecure = options.getDismissKeyguardIfInsecure(); mShareIdentity = options.isShareIdentityEnabled(); } @@ -2887,7 +2887,6 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A } final StartingSurfaceController.StartingSurface surface; - final WindowState startingWindow = mStartingWindow; final boolean animate; if (mStartingData != null) { if (mStartingData.mWaitForSyncTransactionCommit @@ -4545,7 +4544,7 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A mTransitionChangeFlags |= FLAG_STARTING_WINDOW_TRANSFER_RECIPIENT; } // Post cleanup after the visibility and animation are transferred. - fromActivity.postWindowRemoveStartingWindowCleanup(); + fromActivity.postWindowRemoveStartingWindowCleanup(tStartingWindow); fromActivity.mVisibleSetFromTransferredStartingWindow = false; mWmService.updateFocusedWindowLocked( @@ -7461,7 +7460,12 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A } } - void postWindowRemoveStartingWindowCleanup() { + void postWindowRemoveStartingWindowCleanup(@NonNull WindowState win) { + if (mStartingWindow == win) { + // This could only happen when the window is removed from hierarchy. So do not keep its + // reference anymore. + mStartingWindow = null; + } if (mChildren.size() == 0 && mVisibleSetFromTransferredStartingWindow) { // We set the visible state to true for the token from a transferred starting // window. We now reset it back to false since the starting window was the last diff --git a/services/core/java/com/android/server/wm/BackNavigationController.java b/services/core/java/com/android/server/wm/BackNavigationController.java index d1728d6b55e0..2d37b9b2745d 100644 --- a/services/core/java/com/android/server/wm/BackNavigationController.java +++ b/services/core/java/com/android/server/wm/BackNavigationController.java @@ -43,6 +43,7 @@ import android.os.IBinder; import android.os.RemoteCallback; import android.os.RemoteException; import android.os.SystemProperties; +import android.text.TextUtils; import android.util.ArraySet; import android.util.Slog; import android.util.proto.ProtoOutputStream; @@ -64,6 +65,7 @@ import com.android.server.wm.utils.InsetUtils; import java.io.PrintWriter; import java.util.ArrayList; +import java.util.Arrays; import java.util.Objects; /** @@ -141,10 +143,6 @@ class BackNavigationController { // multiple Activities in the Stack. Task prevTask = null; - // The previous activity we're going back to. This can be either a child of currentTask - // if there are more than one Activity in currentTask, or a child of prevTask, if - // currentActivity is the last child of currentTask. - ActivityRecord prevActivity; WindowContainer<?> removedWindowContainer = null; WindowState window; @@ -264,14 +262,21 @@ class BackNavigationController { return infoBuilder.build(); } + // The previous activity we're going back to. This can be either a child of currentTask + // if there are more than one Activity in currentTask, or a child of prevTask, if + // currentActivity is the last child of currentTask. // We don't have an application callback, let's find the destination of the back gesture // The search logic should align with ActivityClientController#finishActivity - prevActivity = currentTask.topRunningActivity(currentActivity.token, INVALID_TASK_ID); + final ArrayList<ActivityRecord> prevActivities = new ArrayList<>(); + final boolean canAnimate = getAnimatablePrevActivities(currentTask, currentActivity, + prevActivities); final boolean isOccluded = isKeyguardOccluded(window); - // TODO Dialog window does not need to attach on activity, check - // window.mAttrs.type != TYPE_BASE_APPLICATION - if ((window.getParent().getChildCount() > 1 + if (!canAnimate) { + backType = BackNavigationInfo.TYPE_CALLBACK; + } else if ((window.getParent().getChildCount() > 1 && window.getParent().getChildAt(0) != window)) { + // TODO Dialog window does not need to attach on activity, check + // window.mAttrs.type != TYPE_BASE_APPLICATION // Are we the top window of our parent? If not, we are a window on top of the // activity, we won't close the activity. backType = BackNavigationInfo.TYPE_DIALOG_CLOSE; @@ -279,9 +284,8 @@ class BackNavigationController { } else if (!currentActivity.occludesParent() || currentActivity.showWallpaper()) { // skip if current activity is translucent backType = BackNavigationInfo.TYPE_CALLBACK; - removedWindowContainer = window; - } else if (prevActivity != null) { - if (!isOccluded || prevActivity.canShowWhenLocked()) { + } else if (prevActivities.size() > 0) { + if (!isOccluded || prevActivities.get(0).canShowWhenLocked()) { // We have another Activity in the same currentTask to go to final WindowContainer parent = currentActivity.getParent(); final boolean canCustomize = parent != null @@ -303,40 +307,45 @@ class BackNavigationController { } } removedWindowContainer = currentActivity; - prevTask = prevActivity.getTask(); + prevTask = prevActivities.get(0).getTask(); backType = BackNavigationInfo.TYPE_CROSS_ACTIVITY; } else { + // keyguard locked and activities are unable to show when locked. backType = BackNavigationInfo.TYPE_CALLBACK; } - } else if (currentTask.returnsToHomeRootTask()) { - if (isOccluded) { + } else { + // TODO(208789724): Create single source of truth for this, maybe in + // RootWindowContainer + prevTask = currentTask.mRootWindowContainer.getTask(t -> { + if (t.showToCurrentUser() && !t.mChildren.isEmpty()) { + final ActivityRecord ar = t.getTopNonFinishingActivity(); + return ar != null && ar.showToCurrentUser(); + } + return false; + }, currentTask, false /*includeBoundary*/, true /*traverseTopToBottom*/); + final ActivityRecord tmpPre = prevTask.getTopNonFinishingActivity(); + if (tmpPre != null) { + prevActivities.add(tmpPre); + findAdjacentActivityIfExist(tmpPre, prevActivities); + } + if (prevActivities.isEmpty() + || (isOccluded && !prevActivities.get(0).canShowWhenLocked())) { backType = BackNavigationInfo.TYPE_CALLBACK; - } else { - // Our Task should bring back to home + } else if (prevTask.isActivityTypeHome()) { removedWindowContainer = currentTask; - prevTask = currentTask.getDisplayArea().getRootHomeTask(); backType = BackNavigationInfo.TYPE_RETURN_TO_HOME; mShowWallpaper = true; - } - } else if (currentActivity.isRootOfTask()) { - // TODO(208789724): Create single source of truth for this, maybe in - // RootWindowContainer - prevTask = currentTask.mRootWindowContainer.getTask(Task::showToCurrentUser, - currentTask, false /*includeBoundary*/, true /*traverseTopToBottom*/); - removedWindowContainer = currentTask; - // If it reaches the top activity, we will check the below task from parent. - // If it's null or multi-window, fallback the type to TYPE_CALLBACK. - // or set the type to proper value when it's return to home or another task. - if (prevTask == null || prevTask.inMultiWindowMode()) { - backType = BackNavigationInfo.TYPE_CALLBACK; } else { - prevActivity = prevTask.getTopNonFinishingActivity(); - if (prevActivity == null || (isOccluded && !prevActivity.canShowWhenLocked())) { + // If it reaches the top activity, we will check the below task from parent. + // If it's null or multi-window and has different parent task, fallback the type + // to TYPE_CALLBACK. Or set the type to proper value when it's return to home or + // another task. + final Task prevParent = prevTask.getParent().asTask(); + final Task currParent = currentTask.getParent().asTask(); + if (prevTask.inMultiWindowMode() && prevParent != currParent) { backType = BackNavigationInfo.TYPE_CALLBACK; - } else if (prevTask.isActivityTypeHome()) { - backType = BackNavigationInfo.TYPE_RETURN_TO_HOME; - mShowWallpaper = true; } else { + removedWindowContainer = prevTask; backType = BackNavigationInfo.TYPE_CROSS_TASK; } } @@ -345,7 +354,8 @@ class BackNavigationController { ProtoLog.d(WM_DEBUG_BACK_PREVIEW, "Previous Destination is Activity:%s Task:%s " + "removedContainer:%s, backType=%s", - prevActivity != null ? prevActivity.mActivityComponent : null, + prevActivities.size() > 0 ? TextUtils.join(";", prevActivities.stream() + .map(r -> r.mActivityComponent).toArray()) : null, prevTask != null ? prevTask.getName() : null, removedWindowContainer, BackNavigationInfo.typeToString(backType)); @@ -360,7 +370,7 @@ class BackNavigationController { if (prepareAnimation) { final AnimationHandler.ScheduleAnimationBuilder builder = mAnimationHandler.prepareAnimation(backType, adapter, - currentTask, prevTask, currentActivity, prevActivity); + currentTask, prevTask, currentActivity, prevActivities); mBackAnimationInProgress = builder != null; if (mBackAnimationInProgress) { if (removedWindowContainer.hasCommittedReparentToAnimationLeash() @@ -372,8 +382,8 @@ class BackNavigationController { // Current transition is still running, we have to defer the hiding to the // client process to prevent the unexpected relayout when handling the back // animation. - if (prevActivity != null) { - prevActivity.setDeferHidingClient(true); + for (int i = prevActivities.size() - 1; i >= 0; --i) { + prevActivities.get(i).setDeferHidingClient(true); } } else { scheduleAnimation(builder); @@ -381,17 +391,91 @@ class BackNavigationController { } } infoBuilder.setPrepareRemoteAnimation(prepareAnimation); - } // Release wm Lock - WindowContainer<?> finalRemovedWindowContainer = removedWindowContainer; - if (finalRemovedWindowContainer != null) { - final int finalBackType = backType; - RemoteCallback onBackNavigationDone = new RemoteCallback(result -> onBackNavigationDone( - result, finalBackType)); - infoBuilder.setOnBackNavigationDone(onBackNavigationDone); + if (removedWindowContainer != null) { + final int finalBackType = backType; + final RemoteCallback onBackNavigationDone = new RemoteCallback(result -> + onBackNavigationDone(result, finalBackType)); + infoBuilder.setOnBackNavigationDone(onBackNavigationDone); + } else { + mNavigationMonitor.stopMonitorForRemote(); + } + mLastBackType = backType; + return infoBuilder.build(); } - mLastBackType = backType; - return infoBuilder.build(); + } + + /** + * Gets previous activities from currentActivity. + * + * @return false if unable to predict what will happen + */ + private static boolean getAnimatablePrevActivities(@NonNull Task currentTask, + @NonNull ActivityRecord currentActivity, + @NonNull ArrayList<ActivityRecord> outPrevActivities) { + if (currentActivity.mAtmService + .mTaskOrganizerController.shouldInterceptBackPressedOnRootTask( + currentTask.getRootTask())) { + // The task organizer will handle back pressed, don't play animation. + return false; + } + final ActivityRecord root = currentTask.getRootActivity(false /*ignoreRelinquishIdentity*/, + true /*setToBottomIfNone*/); + if (root != null && ActivityClientController.shouldMoveTaskToBack(currentActivity, root)) { + return true; + } + + // Searching previous + final ActivityRecord prevActivity = currentTask.getActivity((below) -> !below.finishing, + currentActivity, false /*includeBoundary*/, true /*traverseTopToBottom*/); + if (prevActivity == null) { + // No previous activity in this task, can still predict if previous task exists. + return true; + } + if (currentTask.getActivity((above) -> !above.finishing, currentActivity, + false /*includeBoundary*/, false /*traverseTopToBottom*/) != null) { + // another activity is above this activity, don't know what will happen + return false; + } + + final TaskFragment currTF = currentActivity.getTaskFragment(); + final TaskFragment prevTF = prevActivity.getTaskFragment(); + if (currTF != prevTF && prevTF != null) { + final TaskFragment prevTFAdjacent = prevTF.getAdjacentTaskFragment(); + if (prevTFAdjacent != null) { + if (prevTFAdjacent == currTF) { + // Cannot predict what will happen when app receive back key, skip animation. + outPrevActivities.clear(); + return false; + } else { + final ActivityRecord prevActivityAdjacent = + prevTFAdjacent.getTopNonFinishingActivity(); + if (prevActivityAdjacent != null) { + outPrevActivities.add(prevActivityAdjacent); + } else { + // Don't know what will happen. + outPrevActivities.clear(); + return false; + } + } + } + } + outPrevActivities.add(prevActivity); + return true; + } + + private static void findAdjacentActivityIfExist(@NonNull ActivityRecord mainActivity, + @NonNull ArrayList<ActivityRecord> outList) { + final TaskFragment mainTF = mainActivity.getTaskFragment(); + if (mainTF == null || mainTF.getAdjacentTaskFragment() == null) { + return; + } + final TaskFragment adjacentTF = mainTF.getAdjacentTaskFragment(); + final ActivityRecord topActivity = adjacentTF.getTopNonFinishingActivity(); + if (topActivity == null) { + return; + } + outList.add(topActivity); } boolean isMonitoringTransition() { @@ -696,7 +780,7 @@ class BackNavigationController { if (!hasTarget) { // Skip if no target participated in current finished transition. Slog.w(TAG, "Finished transition didn't include the targets" - + " open: " + mPendingAnimationBuilder.mOpenTarget + + " open: " + Arrays.toString(mPendingAnimationBuilder.mOpenTargets) + " close: " + mPendingAnimationBuilder.mCloseTarget); cancelPendingAnimation(); return false; @@ -732,7 +816,7 @@ class BackNavigationController { private final boolean mShowWindowlessSurface; private final WindowManagerService mWindowManagerService; private BackWindowAnimationAdaptor mCloseAdaptor; - private BackWindowAnimationAdaptor mOpenAdaptor; + private BackWindowAnimationAdaptorWrapper mOpenAnimAdaptor; private boolean mComposed; private boolean mWaitTransition; private int mSwitchType = UNKNOWN; @@ -741,7 +825,7 @@ class BackNavigationController { // exactly match animating target. When target match, reparent the starting surface to // the opening target like starting window do. private boolean mStartingSurfaceTargetMatch; - private ActivityRecord mOpenActivity; + private ActivityRecord[] mOpenActivities; AnimationHandler(WindowManagerService wms) { mWindowManagerService = wms; @@ -753,61 +837,69 @@ class BackNavigationController { private static final int TASK_SWITCH = 1; private static final int ACTIVITY_SWITCH = 2; - private static boolean isActivitySwitch(WindowContainer close, WindowContainer open) { - if (close.asActivityRecord() == null || open.asActivityRecord() == null - || (close.asActivityRecord().getTask() - != open.asActivityRecord().getTask())) { + private static boolean isActivitySwitch(@NonNull WindowContainer close, + @NonNull WindowContainer[] open) { + if (open == null || open.length == 0 || close.asActivityRecord() == null) { return false; } + final Task closeTask = close.asActivityRecord().getTask(); + for (int i = open.length - 1; i >= 0; --i) { + if (open[i].asActivityRecord() == null + || (closeTask != open[i].asActivityRecord().getTask())) { + return false; + } + } return true; } - private static boolean isTaskSwitch(WindowContainer close, WindowContainer open) { - if (close.asTask() == null || open.asTask() == null - || (close.asTask() == open.asTask())) { + private static boolean isTaskSwitch(@NonNull WindowContainer close, + @NonNull WindowContainer[] open) { + if (open == null || open.length != 1 || close.asTask() == null) { return false; } - return true; + return open[0].asTask() != null && (close.asTask() != open[0].asTask()); } - private void initiate(WindowContainer close, WindowContainer open, - ActivityRecord openActivity) { - WindowContainer closeTarget; + private void initiate(@NonNull WindowContainer close, @NonNull WindowContainer[] open, + @NonNull ActivityRecord[] openingActivities) { if (isActivitySwitch(close, open)) { mSwitchType = ACTIVITY_SWITCH; - closeTarget = close.asActivityRecord(); } else if (isTaskSwitch(close, open)) { mSwitchType = TASK_SWITCH; - // The transition target must be activity in legacy transition. - closeTarget = WindowManagerService.sEnableShellTransitions ? close - : close.asTask().getTopNonFinishingActivity(); } else { mSwitchType = UNKNOWN; return; } - mCloseAdaptor = createAdaptor(closeTarget, false, mSwitchType); - mOpenAdaptor = createAdaptor(open, true, mSwitchType); - mOpenActivity = openActivity; - if (mCloseAdaptor.mAnimationTarget == null || mOpenAdaptor.mAnimationTarget == null) { + mCloseAdaptor = createAdaptor(close, false, mSwitchType); + if (mCloseAdaptor.mAnimationTarget == null) { Slog.w(TAG, "composeNewAnimations fail, skip"); clearBackAnimateTarget(); + return; } + + mOpenAnimAdaptor = new BackWindowAnimationAdaptorWrapper(true, mSwitchType, open); + if (!mOpenAnimAdaptor.isValid()) { + Slog.w(TAG, "compose animations fail, skip"); + clearBackAnimateTarget(); + return; + } + mOpenActivities = openingActivities; } private boolean composeAnimations(@NonNull WindowContainer close, - @NonNull WindowContainer open, ActivityRecord openActivity) { + @NonNull WindowContainer[] open, @NonNull ActivityRecord[] openingActivities) { if (mComposed || mWaitTransition) { Slog.e(TAG, "Previous animation is running " + this); return false; } clearBackAnimateTarget(); - if (close == null || open == null || openActivity == null) { + if (close == null || open == null || open.length == 0 || open.length > 2) { Slog.e(TAG, "reset animation with null target close: " - + close + " open: " + open); + + close + " open: " + Arrays.toString(open)); return false; } - initiate(close, open, openActivity); + initiate(close, open, openingActivities); if (mSwitchType == UNKNOWN) { return false; } @@ -816,9 +908,14 @@ class BackNavigationController { return true; } - RemoteAnimationTarget[] getAnimationTargets() { - return mComposed ? new RemoteAnimationTarget[] { - mCloseAdaptor.mAnimationTarget, mOpenAdaptor.mAnimationTarget} : null; + @Nullable RemoteAnimationTarget[] getAnimationTargets() { + if (!mComposed) { + return null; + } + final RemoteAnimationTarget[] targets = new RemoteAnimationTarget[2]; + targets[0] = mCloseAdaptor.mAnimationTarget; + targets[1] = mOpenAnimAdaptor.getOrCreateAnimationTarget(); + return targets; } boolean isSupportWindowlessSurface() { @@ -826,7 +923,7 @@ class BackNavigationController { .isSupportWindowlessStartingSurface(); } - boolean containTarget(ArrayList<WindowContainer> wcs, boolean open) { + boolean containTarget(@NonNull ArrayList<WindowContainer> wcs, boolean open) { for (int i = wcs.size() - 1; i >= 0; --i) { if (isTarget(wcs.get(i), open)) { return true; @@ -835,22 +932,35 @@ class BackNavigationController { return wcs.isEmpty(); } - boolean isTarget(WindowContainer wc, boolean open) { + boolean isTarget(@NonNull WindowContainer wc, boolean open) { if (!mComposed) { return false; } + if (open) { + for (int i = mOpenAnimAdaptor.mAdaptors.length - 1; i >= 0; --i) { + if (isAnimateTarget(wc, mOpenAnimAdaptor.mAdaptors[i].mTarget, mSwitchType)) { + return true; + } + } + return false; + } + return isAnimateTarget(wc, mCloseAdaptor.mTarget, mSwitchType); + } - // WC must be ActivityRecord in legacy transition, but it also can be Task or - // TaskFragment when using Shell transition. - // Open target: Can be Task or ActivityRecord or TaskFragment - // Close target: Limit to the top activity for now, to reduce the chance of misjudgment. - final WindowContainer target = open ? mOpenAdaptor.mTarget : mCloseAdaptor.mTarget; - if (mSwitchType == TASK_SWITCH) { - return wc == target - || (wc.asTask() != null && wc.hasChild(target)) - || (wc.asActivityRecord() != null && target.hasChild(wc)); - } else if (mSwitchType == ACTIVITY_SWITCH) { - return wc == target || (wc.asTaskFragment() != null && wc.hasChild(target)); + private static boolean isAnimateTarget(@NonNull WindowContainer window, + @NonNull WindowContainer animationTarget, int switchType) { + if (switchType == TASK_SWITCH) { + // simplify home search for multiple hierarchy + if (window.isActivityTypeHome() && animationTarget.isActivityTypeHome()) { + return true; + } + return window == animationTarget + || (animationTarget.asTask() != null && animationTarget.hasChild(window)) + || (animationTarget.asActivityRecord() != null + && window.hasChild(animationTarget)); + } else if (switchType == ACTIVITY_SWITCH) { + return window == animationTarget + || (window.asTaskFragment() != null && window.hasChild(animationTarget)); } return false; } @@ -864,19 +974,25 @@ class BackNavigationController { mCloseAdaptor.mTarget.cancelAnimation(); mCloseAdaptor = null; } - if (mOpenAdaptor != null) { - mOpenAdaptor.cleanUpWindowlessSurface(mStartingSurfaceTargetMatch); - mOpenAdaptor.mTarget.cancelAnimation(); - mOpenAdaptor = null; + if (mOpenAnimAdaptor != null) { + mOpenAnimAdaptor.cleanUp(mStartingSurfaceTargetMatch); + mOpenAnimAdaptor = null; } - if (mOpenActivity != null && mOpenActivity.mLaunchTaskBehind) { - restoreLaunchBehind(mOpenActivity); + + if (mOpenActivities != null) { + for (int i = mOpenActivities.length - 1; i >= 0; --i) { + if (mOpenActivities[i].mLaunchTaskBehind) { + restoreLaunchBehind(mOpenActivities[i]); + } + } } } void markStartingSurfaceMatch() { mStartingSurfaceTargetMatch = true; - mOpenAdaptor.reparentWindowlessSurfaceToTarget(); + for (int i = mOpenAnimAdaptor.mAdaptors.length - 1; i >= 0; --i) { + mOpenAnimAdaptor.mAdaptors[i].reparentWindowlessSurfaceToTarget(); + } } void clearBackAnimateTarget() { @@ -885,13 +1001,13 @@ class BackNavigationController { mWaitTransition = false; mStartingSurfaceTargetMatch = false; mSwitchType = UNKNOWN; - mOpenActivity = null; + mOpenActivities = null; } // The close target must in close list // The open target can either in close or open list - boolean containsBackAnimationTargets(ArrayList<WindowContainer> openApps, - ArrayList<WindowContainer> closeApps) { + boolean containsBackAnimationTargets(@NonNull ArrayList<WindowContainer> openApps, + @NonNull ArrayList<WindowContainer> closeApps) { return containTarget(closeApps, false /* open */) && (containTarget(openApps, true /* open */) || containTarget(openApps, false /* open */)); @@ -901,9 +1017,9 @@ class BackNavigationController { public String toString() { return "AnimationTargets{" + " openTarget= " - + (mOpenAdaptor != null ? mOpenAdaptor.mTarget : "null") + + (mOpenAnimAdaptor != null ? dumpOpenAnimTargetsToString() : null) + " closeTarget= " - + (mCloseAdaptor != null ? mCloseAdaptor.mTarget : "null") + + (mCloseAdaptor != null ? mCloseAdaptor.mTarget : null) + " mSwitchType= " + mSwitchType + " mComposed= " @@ -913,8 +1029,21 @@ class BackNavigationController { + '}'; } - private static BackWindowAnimationAdaptor createAdaptor( - WindowContainer target, boolean isOpen, int switchType) { + private String dumpOpenAnimTargetsToString() { + final StringBuilder sb = new StringBuilder(); + sb.append("{"); + for (int i = 0; i < mOpenAnimAdaptor.mAdaptors.length; i++) { + if (i > 0) { + sb.append(','); + } + sb.append(mOpenAnimAdaptor.mAdaptors[i].mTarget); + } + sb.append("}"); + return sb.toString(); + } + + @NonNull private static BackWindowAnimationAdaptor createAdaptor( + @NonNull WindowContainer target, boolean isOpen, int switchType) { final BackWindowAnimationAdaptor adaptor = new BackWindowAnimationAdaptor(target, isOpen, switchType); final SurfaceControl.Transaction pt = target.getPendingTransaction(); @@ -930,6 +1059,100 @@ class BackNavigationController { return adaptor; } + private static class BackWindowAnimationAdaptorWrapper { + final BackWindowAnimationAdaptor[] mAdaptors; + SurfaceControl.Transaction mCloseTransaction; + + BackWindowAnimationAdaptorWrapper(boolean isOpen, int switchType, + @NonNull WindowContainer... targets) { + mAdaptors = new BackWindowAnimationAdaptor[targets.length]; + for (int i = targets.length - 1; i >= 0; --i) { + mAdaptors[i] = createAdaptor(targets[i], isOpen, switchType); + } + } + + boolean isValid() { + for (int i = mAdaptors.length - 1; i >= 0; --i) { + if (mAdaptors[i].mAnimationTarget == null) { + return false; + } + } + return true; + } + + void cleanUp(boolean startingSurfaceMatch) { + for (int i = mAdaptors.length - 1; i >= 0; --i) { + mAdaptors[i].cleanUpWindowlessSurface(startingSurfaceMatch); + mAdaptors[i].mTarget.cancelAnimation(); + } + if (mCloseTransaction != null) { + mCloseTransaction.apply(); + mCloseTransaction = null; + } + } + + void onAnimationFinish() { + final SurfaceControl.Transaction pt = mAdaptors[0].mTarget.getPendingTransaction(); + if (mCloseTransaction != null) { + pt.merge(mCloseTransaction); + mCloseTransaction = null; + } + if (mAdaptors.length > 1) { + for (int i = mAdaptors.length - 1; i >= 0; --i) { + final WindowContainer wc = mAdaptors[i].mTarget; + final WindowContainer parent = wc.getParent(); + if (parent != null) { + pt.reparent(wc.getSurfaceControl(), + parent.getSurfaceControl()); + } + } + } + } + + @NonNull RemoteAnimationTarget getOrCreateAnimationTarget() { + // Special handle for opening two activities together. + // If we animate both activities separately, the animation area and rounded corner + // would also being handled separately. To make them seem like "open" together, wrap + // their leash with another animation leash. + if (mAdaptors.length > 1 && mCloseTransaction == null) { + final Rect unionBounds = new Rect(); + for (int i = mAdaptors.length - 1; i >= 0; --i) { + unionBounds.union(mAdaptors[i].mAnimationTarget.localBounds); + } + final WindowContainer wc = mAdaptors[0].mTarget; + final Task task = wc.asActivityRecord() != null + ? wc.asActivityRecord().getTask() : wc.asTask(); + final RemoteAnimationTarget represent = mAdaptors[0].mAnimationTarget; + final SurfaceControl leashSurface = new SurfaceControl.Builder() + .setName("cross-animation-leash") + .setContainerLayer() + .setHidden(false) + .setParent(task.getSurfaceControl()) + .build(); + final SurfaceControl.Transaction pt = wc.getPendingTransaction(); + pt.setLayer(leashSurface, wc.getParent().getLastLayer()); + mCloseTransaction = new SurfaceControl.Transaction(); + mCloseTransaction.reparent(leashSurface, null); + for (int i = mAdaptors.length - 1; i >= 0; --i) { + BackWindowAnimationAdaptor adaptor = mAdaptors[i]; + pt.reparent(adaptor.mAnimationTarget.leash, leashSurface); + pt.setPosition(adaptor.mAnimationTarget.leash, + adaptor.mAnimationTarget.localBounds.left, + adaptor.mAnimationTarget.localBounds.top); + } + return new RemoteAnimationTarget(represent.taskId, represent.mode, leashSurface, + represent.isTranslucent, represent.clipRect, represent.contentInsets, + represent.prefixOrderIndex, + new Point(unionBounds.left, unionBounds.top), + unionBounds, unionBounds, represent.windowConfiguration, + true /* isNotInRecents */, null, null, represent.taskInfo, + represent.allowEnterPip); + } else { + return mAdaptors[0].mAnimationTarget; + } + } + } + private static class BackWindowAnimationAdaptor implements AnimationAdapter { SurfaceControl mCapturedLeash; private final Rect mBounds = new Rect(); @@ -943,7 +1166,7 @@ class BackNavigationController { private int mRequestedStartingSurfaceId = INVALID_TASK_ID; private SurfaceControl mStartingSurface; - BackWindowAnimationAdaptor(WindowContainer target, boolean isOpen, + BackWindowAnimationAdaptor(@NonNull WindowContainer target, boolean isOpen, int switchType) { mBounds.set(target.getBounds()); mTarget = target; @@ -1034,7 +1257,7 @@ class BackNavigationController { return mAnimationTarget; } - void createStartingSurface() { + void createStartingSurface(@NonNull WindowContainer closeWindow) { if (!mIsOpen) { return; } @@ -1053,7 +1276,10 @@ class BackNavigationController { final TaskSnapshot snapshot = getSnapshot(mTarget); mRequestedStartingSurfaceId = openTask.mAtmService.mTaskOrganizerController .addWindowlessStartingSurface(openTask, mainActivity, - mAnimationTarget.leash, snapshot, + // Choose configuration from closeWindow, because the configuration + // of opening target may not update before resume, so the starting + // surface should occlude it entirely. + mAnimationTarget.leash, snapshot, closeWindow.getConfiguration(), new IWindowlessStartingSurfaceCallback.Stub() { // Once the starting surface has been created in shell, it will call // onSurfaceAdded to pass the created surface to core, so if a @@ -1108,15 +1334,17 @@ class BackNavigationController { ScheduleAnimationBuilder prepareAnimation(int backType, BackAnimationAdapter adapter, Task currentTask, Task previousTask, ActivityRecord currentActivity, - ActivityRecord previousActivity) { + ArrayList<ActivityRecord> previousActivity) { switch (backType) { case BackNavigationInfo.TYPE_RETURN_TO_HOME: return new ScheduleAnimationBuilder(backType, adapter) .setIsLaunchBehind(true) .setComposeTarget(currentTask, previousTask); case BackNavigationInfo.TYPE_CROSS_ACTIVITY: + ActivityRecord[] prevActs = new ActivityRecord[previousActivity.size()]; + prevActs = previousActivity.toArray(prevActs); return new ScheduleAnimationBuilder(backType, adapter) - .setComposeTarget(currentActivity, previousActivity) + .setComposeTarget(currentActivity, prevActs) .setIsLaunchBehind(false); case BackNavigationInfo.TYPE_CROSS_TASK: return new ScheduleAnimationBuilder(backType, adapter) @@ -1130,7 +1358,7 @@ class BackNavigationController { final int mType; final BackAnimationAdapter mBackAnimationAdapter; WindowContainer mCloseTarget; - WindowContainer mOpenTarget; + WindowContainer[] mOpenTargets; boolean mIsLaunchBehind; ScheduleAnimationBuilder(int type, BackAnimationAdapter backAnimationAdapter) { @@ -1138,9 +1366,10 @@ class BackNavigationController { mBackAnimationAdapter = backAnimationAdapter; } - ScheduleAnimationBuilder setComposeTarget(WindowContainer close, WindowContainer open) { + ScheduleAnimationBuilder setComposeTarget(@NonNull WindowContainer close, + @NonNull WindowContainer... open) { mCloseTarget = close; - mOpenTarget = open; + mOpenTargets = open; return this; } @@ -1150,43 +1379,60 @@ class BackNavigationController { } boolean containTarget(@NonNull WindowContainer wc) { - return wc == mOpenTarget || wc == mCloseTarget - || mOpenTarget.hasChild(wc) || mCloseTarget.hasChild(wc); + if (mOpenTargets != null) { + for (int i = mOpenTargets.length - 1; i >= 0; --i) { + if (wc == mOpenTargets[i] || mOpenTargets[i].hasChild(wc)) { + return true; + } + } + } + return wc == mCloseTarget || mCloseTarget.hasChild(wc); } /** * Apply preview strategy on the opening target + * @param closeWindow The close window, where it's configuration should cover all + * open target(s). * @param openAnimationAdaptor The animator who can create starting surface. - * @param visibleOpenActivity The visible activity in opening target. + * @param visibleOpenActivities The visible activities in opening targets. */ - private void applyPreviewStrategy(BackWindowAnimationAdaptor openAnimationAdaptor, - ActivityRecord visibleOpenActivity) { - if (isSupportWindowlessSurface() && mShowWindowlessSurface && !mIsLaunchBehind) { - openAnimationAdaptor.createStartingSurface(); - return; + private void applyPreviewStrategy(@NonNull WindowContainer closeWindow, + @NonNull BackWindowAnimationAdaptor[] openAnimationAdaptor, + @NonNull ActivityRecord[] visibleOpenActivities) { + if (isSupportWindowlessSurface() && mShowWindowlessSurface && !mIsLaunchBehind + // TODO (b/274997067) Draw two snapshot in a single starting surface. + // We are using TaskId as the key of + // StartingSurfaceDrawer#StartingWindowRecordManager, so we cannot create + // two activity snapshot with WindowlessStartingWindow. + // Try to draw two snapshot within a WindowlessStartingWindow, or find + // another key for StartingWindowRecordManager. + && openAnimationAdaptor.length == 1) { + openAnimationAdaptor[0].createStartingSurface(closeWindow); + } else { + for (int i = visibleOpenActivities.length - 1; i >= 0; --i) { + setLaunchBehind(visibleOpenActivities[i]); + } } - setLaunchBehind(visibleOpenActivity); } - Runnable build() { - if (mOpenTarget == null || mCloseTarget == null) { + @Nullable Runnable build() { + if (mOpenTargets == null || mCloseTarget == null || mOpenTargets.length == 0) { return null; } - final ActivityRecord openActivity = mOpenTarget.asTask() != null - ? mOpenTarget.asTask().getTopNonFinishingActivity() - : mOpenTarget.asActivityRecord() != null - ? mOpenTarget.asActivityRecord() : null; - if (openActivity == null) { + final boolean shouldLaunchBehind = mIsLaunchBehind || !isSupportWindowlessSurface(); + final ActivityRecord[] openingActivities = getTopOpenActivities(mOpenTargets); + + if (shouldLaunchBehind && openingActivities == null) { Slog.e(TAG, "No opening activity"); return null; } - if (!composeAnimations(mCloseTarget, mOpenTarget, openActivity)) { + if (!composeAnimations(mCloseTarget, mOpenTargets, openingActivities)) { return null; } mCloseTarget.mTransitionController.mSnapshotController .mActivitySnapshotController.clearOnBackPressedActivities(); - applyPreviewStrategy(mOpenAdaptor, openActivity); + applyPreviewStrategy(mCloseTarget, mOpenAnimAdaptor.mAdaptors, openingActivities); final IBackAnimationFinishedCallback callback = makeAnimationFinishedCallback(); final RemoteAnimationTarget[] targets = getAnimationTargets(); @@ -1210,6 +1456,7 @@ class BackNavigationController { // animation was canceled return; } + mOpenAnimAdaptor.onAnimationFinish(); if (!triggerBack) { clearBackAnimateTarget(); } else { @@ -1223,6 +1470,41 @@ class BackNavigationController { } } + /** + * Finds next opening activity(ies) based on open targets, which could be: + * 1. If the open window is Task, then the open activity can either be an activity, or + * two activities inside two TaskFragments + * 2. If the open window is Activity, then the open window can be an activity, or two + * adjacent TaskFragments below it. + */ + @Nullable + private static ActivityRecord[] getTopOpenActivities( + @NonNull WindowContainer[] openWindows) { + ActivityRecord[] openActivities = null; + final WindowContainer mainTarget = openWindows[0]; + if (mainTarget.asTask() != null) { + final ArrayList<ActivityRecord> inTaskActivities = new ArrayList<>(); + final Task task = mainTarget.asTask(); + final ActivityRecord tmpPreActivity = task.getTopNonFinishingActivity(); + if (tmpPreActivity != null) { + inTaskActivities.add(tmpPreActivity); + findAdjacentActivityIfExist(tmpPreActivity, inTaskActivities); + } + + openActivities = new ActivityRecord[inTaskActivities.size()]; + for (int i = inTaskActivities.size() - 1; i >= 0; --i) { + openActivities[i] = inTaskActivities.get(i); + } + } else if (mainTarget.asActivityRecord() != null) { + final int size = openWindows.length; + openActivities = new ActivityRecord[size]; + for (int i = size - 1; i >= 0; --i) { + openActivities[i] = openWindows[i].asActivityRecord(); + } + } + return openActivities; + } + private static void setLaunchBehind(@NonNull ActivityRecord activity) { if (!activity.isVisibleRequested()) { activity.setVisibility(true); @@ -1311,7 +1593,7 @@ class BackNavigationController { static TaskSnapshot getSnapshot(@NonNull WindowContainer w) { if (w.asTask() != null) { final Task task = w.asTask(); - return task.mRootWindowContainer.mWindowManager.mTaskSnapshotController.getSnapshot( + return task.mRootWindowContainer.mWindowManager.mTaskSnapshotController.getSnapshot( task.mTaskId, task.mUserId, false /* restoreFromDisk */, false /* isLowResolution */); } @@ -1340,8 +1622,10 @@ class BackNavigationController { proto.write(ANIMATION_IN_PROGRESS, mBackAnimationInProgress); proto.write(LAST_BACK_TYPE, mLastBackType); proto.write(SHOW_WALLPAPER, mShowWallpaper); - if (mAnimationHandler.mOpenActivity != null) { - mAnimationHandler.mOpenActivity.writeNameToProto(proto, MAIN_OPEN_ACTIVITY); + if (mAnimationHandler.mOpenAnimAdaptor != null + && mAnimationHandler.mOpenAnimAdaptor.mAdaptors.length > 0) { + mAnimationHandler.mOpenActivities[0].writeNameToProto( + proto, MAIN_OPEN_ACTIVITY); } else { proto.write(MAIN_OPEN_ACTIVITY, ""); } diff --git a/services/core/java/com/android/server/wm/BackgroundActivityStartController.java b/services/core/java/com/android/server/wm/BackgroundActivityStartController.java index 4579cc1412b3..9f3e16279428 100644 --- a/services/core/java/com/android/server/wm/BackgroundActivityStartController.java +++ b/services/core/java/com/android/server/wm/BackgroundActivityStartController.java @@ -291,6 +291,10 @@ public class BackgroundActivityStartController { return name + "[debugOnly]"; } + private boolean callerIsRealCaller() { + return mCallingUid == mRealCallingUid; + } + private String dump(BalVerdict resultIfPiCreatorAllowsBal, BalVerdict resultIfPiSenderAllowsBal) { return " [callingPackage: " + getDebugPackageName(mCallingPackage, mCallingUid) @@ -422,7 +426,7 @@ public class BackgroundActivityStartController { } BalVerdict resultForCaller = checkBackgroundActivityStartAllowedByCaller(state); - BalVerdict resultForRealCaller = callingUid == realCallingUid && resultForCaller.allows() + BalVerdict resultForRealCaller = state.callerIsRealCaller() && resultForCaller.allows() ? resultForCaller // no need to calculate again // otherwise we might need to recalculate because the logic is not the same : checkBackgroundActivityStartAllowedBySender(state, checkedOptions); @@ -636,16 +640,14 @@ public class BackgroundActivityStartController { BalVerdict checkBackgroundActivityStartAllowedBySender( BalState state, ActivityOptions checkedOptions) { - int realCallingUid = state.mRealCallingUid; - BackgroundStartPrivileges backgroundStartPrivileges = state.mBackgroundStartPrivileges; if (PendingIntentRecord.isPendingIntentBalAllowedByPermission(checkedOptions) && ActivityManager.checkComponentPermission( android.Manifest.permission.START_ACTIVITIES_FROM_BACKGROUND, - realCallingUid, -1, true) == PackageManager.PERMISSION_GRANTED) { + state.mRealCallingUid, -1, true) == PackageManager.PERMISSION_GRANTED) { return new BalVerdict(BAL_ALLOW_PENDING_INTENT, /*background*/ false, - "realCallingUid has BAL permission. realCallingUid: " + realCallingUid); + "realCallingUid has BAL permission."); } // don't abort if the realCallingUid has a visible window @@ -653,26 +655,23 @@ public class BackgroundActivityStartController { if (state.mRealCallingUidHasAnyVisibleWindow) { return new BalVerdict(BAL_ALLOW_PENDING_INTENT, /*background*/ false, - "realCallingUid has visible (non-toast) window. realCallingUid: " - + realCallingUid); + "realCallingUid has visible (non-toast) window."); } // if the realCallingUid is a persistent system process, abort if the IntentSender // wasn't allowed to start an activity if (state.mIsRealCallingUidPersistentSystemProcess - && backgroundStartPrivileges.allowsBackgroundActivityStarts()) { + && state.mBackgroundStartPrivileges.allowsBackgroundActivityStarts()) { return new BalVerdict(BAL_ALLOW_PENDING_INTENT, /*background*/ false, "realCallingUid is persistent system process AND intent " - + "sender allowed (allowBackgroundActivityStart = true). " - + "realCallingUid: " + realCallingUid); + + "sender allowed (allowBackgroundActivityStart = true)."); } // don't abort if the realCallingUid is an associated companion app if (mService.isAssociatedCompanionApp( - UserHandle.getUserId(realCallingUid), realCallingUid)) { + UserHandle.getUserId(state.mRealCallingUid), state.mRealCallingUid)) { return new BalVerdict(BAL_ALLOW_PENDING_INTENT, /*background*/ false, - "realCallingUid is a companion app. " - + "realCallingUid: " + realCallingUid); + "realCallingUid is a companion app."); } // don't abort if the callerApp or other processes of that uid are allowed in any way diff --git a/services/core/java/com/android/server/wm/KeyguardController.java b/services/core/java/com/android/server/wm/KeyguardController.java index fa2c94a1ecf2..ccaa3b07aaaa 100644 --- a/services/core/java/com/android/server/wm/KeyguardController.java +++ b/services/core/java/com/android/server/wm/KeyguardController.java @@ -665,12 +665,14 @@ class KeyguardController { mTopTurnScreenOnActivity = top; } - if (top.mDismissKeyguard && mKeyguardShowing) { + final boolean isKeyguardSecure = controller.mWindowManager.isKeyguardSecure( + controller.mService.getCurrentUserId()); + if (top.mDismissKeyguardIfInsecure && mKeyguardShowing && !isKeyguardSecure) { mKeyguardGoingAway = true; } else if (top.canShowWhenLocked()) { mTopOccludesActivity = top; } - top.mDismissKeyguard = false; + top.mDismissKeyguardIfInsecure = false; // Only the top activity may control occluded, as we can't occlude the Keyguard // if the top app doesn't want to occlude it. diff --git a/services/core/java/com/android/server/wm/RootWindowContainer.java b/services/core/java/com/android/server/wm/RootWindowContainer.java index 4a467dfbcd14..e82f3221f0a4 100644 --- a/services/core/java/com/android/server/wm/RootWindowContainer.java +++ b/services/core/java/com/android/server/wm/RootWindowContainer.java @@ -174,10 +174,14 @@ class RootWindowContainer extends WindowContainer<DisplayContent> private static final int SET_SCREEN_BRIGHTNESS_OVERRIDE = 1; private static final int SET_USER_ACTIVITY_TIMEOUT = 2; + private static final int MSG_SEND_SLEEP_TRANSITION = 3; + static final String TAG_TASKS = TAG + POSTFIX_TASKS; static final String TAG_STATES = TAG + POSTFIX_STATES; private static final String TAG_RECENTS = TAG + POSTFIX_RECENTS; + private static final long SLEEP_TRANSITION_WAIT_MILLIS = 1000L; + private Object mLastWindowFreezeSource = null; private float mScreenBrightnessOverride = PowerManager.BRIGHTNESS_INVALID_FLOAT; private long mUserActivityTimeout = -1; @@ -1132,6 +1136,11 @@ class RootWindowContainer extends WindowContainer<DisplayContent> mWmService.mPowerManagerInternal. setUserActivityTimeoutOverrideFromWindowManager((Long) msg.obj); break; + case MSG_SEND_SLEEP_TRANSITION: + synchronized (mService.mGlobalLock) { + sendSleepTransition((DisplayContent) msg.obj); + } + break; default: break; } @@ -1681,8 +1690,8 @@ class RootWindowContainer extends WindowContainer<DisplayContent> return false; } - if (!StorageManager.isUserKeyUnlocked(mCurrentUser)) { - // Can't launch home on secondary display areas if device is still locked. + if (!StorageManager.isCeStorageUnlocked(mCurrentUser)) { + // Can't launch home on secondary display areas if CE storage is still locked. return false; } @@ -2442,8 +2451,38 @@ class RootWindowContainer extends WindowContainer<DisplayContent> return result; } + void sendSleepTransition(final DisplayContent display) { + // We don't actually care about collecting anything here. We really just want + // this as a signal to the transition-player. + final Transition transition = new Transition(TRANSIT_SLEEP, 0 /* flags */, + display.mTransitionController, mWmService.mSyncEngine); + final TransitionController.OnStartCollect sendSleepTransition = (deferred) -> { + if (deferred && !display.shouldSleep()) { + transition.abort(); + } else { + display.mTransitionController.requestStartTransition(transition, + null /* trigger */, null /* remote */, null /* display */); + // Force playing immediately so that unrelated ops can't be collected. + transition.playNow(); + } + }; + if (!display.mTransitionController.isCollecting()) { + // Since this bypasses sync, submit directly ignoring whether sync-engine + // is active. + if (mWindowManager.mSyncEngine.hasActiveSync()) { + Slog.w(TAG, "Ongoing sync outside of a transition."); + } + display.mTransitionController.moveToCollecting(transition); + sendSleepTransition.onCollectStarted(false /* deferred */); + } else { + display.mTransitionController.startCollectOrQueue(transition, + sendSleepTransition); + } + } + void applySleepTokens(boolean applyToRootTasks) { - boolean builtSleepTransition = false; + boolean scheduledSleepTransition = false; + for (int displayNdx = getChildCount() - 1; displayNdx >= 0; --displayNdx) { // Set the sleeping state of the display. final DisplayContent display = getChildAt(displayNdx); @@ -2453,35 +2492,16 @@ class RootWindowContainer extends WindowContainer<DisplayContent> } display.setIsSleeping(displayShouldSleep); - if (display.mTransitionController.isShellTransitionsEnabled() && !builtSleepTransition + if (display.mTransitionController.isShellTransitionsEnabled() + && !scheduledSleepTransition // Only care if there are actual sleep tokens. && displayShouldSleep && !display.mAllSleepTokens.isEmpty()) { - builtSleepTransition = true; - // We don't actually care about collecting anything here. We really just want - // this as a signal to the transition-player. - final Transition transition = new Transition(TRANSIT_SLEEP, 0 /* flags */, - display.mTransitionController, mWmService.mSyncEngine); - final TransitionController.OnStartCollect sendSleepTransition = (deferred) -> { - if (deferred && !display.shouldSleep()) { - transition.abort(); - } else { - display.mTransitionController.requestStartTransition(transition, - null /* trigger */, null /* remote */, null /* display */); - // Force playing immediately so that unrelated ops can't be collected. - transition.playNow(); - } - }; - if (!display.mTransitionController.isCollecting()) { - // Since this bypasses sync, submit directly ignoring whether sync-engine - // is active. - if (mWindowManager.mSyncEngine.hasActiveSync()) { - Slog.w(TAG, "Ongoing sync outside of a transition."); - } - display.mTransitionController.moveToCollecting(transition); - sendSleepTransition.onCollectStarted(false /* deferred */); - } else { - display.mTransitionController.startCollectOrQueue(transition, - sendSleepTransition); + scheduledSleepTransition = true; + + if (!mHandler.hasMessages(MSG_SEND_SLEEP_TRANSITION)) { + mHandler.sendMessageDelayed( + mHandler.obtainMessage(MSG_SEND_SLEEP_TRANSITION, display), + SLEEP_TRANSITION_WAIT_MILLIS); } } @@ -2535,6 +2555,10 @@ class RootWindowContainer extends WindowContainer<DisplayContent> } }); } + + if (!scheduledSleepTransition) { + mHandler.removeMessages(MSG_SEND_SLEEP_TRANSITION); + } } protected Task getRootTask(int rooTaskId) { diff --git a/services/core/java/com/android/server/wm/SafeActivityOptions.java b/services/core/java/com/android/server/wm/SafeActivityOptions.java index 6418148ba104..4ced5d524798 100644 --- a/services/core/java/com/android/server/wm/SafeActivityOptions.java +++ b/services/core/java/com/android/server/wm/SafeActivityOptions.java @@ -343,14 +343,14 @@ public class SafeActivityOptions { } // Check if the caller is allowed to dismiss keyguard. - final boolean dismissKeyguard = options.getDismissKeyguard(); - if (aInfo != null && dismissKeyguard) { + final boolean dismissKeyguardIfInsecure = options.getDismissKeyguardIfInsecure(); + if (aInfo != null && dismissKeyguardIfInsecure) { final int controlKeyguardPerm = ActivityTaskManagerService.checkPermission( CONTROL_KEYGUARD, callingPid, callingUid); if (controlKeyguardPerm != PERMISSION_GRANTED) { final String msg = "Permission Denial: starting " + getIntentString(intent) + " from " + callerApp + " (pid=" + callingPid - + ", uid=" + callingUid + ") with dismissKeyguard=true"; + + ", uid=" + callingUid + ") with dismissKeyguardIfInsecure=true"; Slog.w(TAG, msg); throw new SecurityException(msg); } diff --git a/services/core/java/com/android/server/wm/Session.java b/services/core/java/com/android/server/wm/Session.java index 3775ccd79d4c..a756847d59ea 100644 --- a/services/core/java/com/android/server/wm/Session.java +++ b/services/core/java/com/android/server/wm/Session.java @@ -86,6 +86,7 @@ import com.android.internal.os.logging.MetricsLoggerWrapper; import com.android.internal.protolog.common.ProtoLog; import com.android.server.LocalServices; import com.android.server.wm.WindowManagerService.H; +import com.android.window.flags.Flags; import java.io.PrintWriter; import java.util.Collections; @@ -166,8 +167,8 @@ class Session extends IWindowSession.Stub implements IBinder.DeathRecipient { mCanSetUnrestrictedGestureExclusion = service.mContext.checkCallingOrSelfPermission(SET_UNRESTRICTED_GESTURE_EXCLUSION) == PERMISSION_GRANTED; - mCanAlwaysUpdateWallpaper = - service.mContext.checkCallingOrSelfPermission(ALWAYS_UPDATE_WALLPAPER) + mCanAlwaysUpdateWallpaper = Flags.alwaysUpdateWallpaperPermission() + && service.mContext.checkCallingOrSelfPermission(ALWAYS_UPDATE_WALLPAPER) == PERMISSION_GRANTED; mShowingAlertWindowNotificationAllowed = mService.mShowAlertWindowNotifications; mDragDropController = mService.mDragDropController; diff --git a/services/core/java/com/android/server/wm/TaskFragmentOrganizerController.java b/services/core/java/com/android/server/wm/TaskFragmentOrganizerController.java index 34ae370a6099..e7a1cf106a44 100644 --- a/services/core/java/com/android/server/wm/TaskFragmentOrganizerController.java +++ b/services/core/java/com/android/server/wm/TaskFragmentOrganizerController.java @@ -49,6 +49,7 @@ import android.view.RemoteAnimationDefinition; import android.view.WindowManager; import android.window.ITaskFragmentOrganizer; import android.window.ITaskFragmentOrganizerController; +import android.window.RemoteTransition; import android.window.TaskFragmentInfo; import android.window.TaskFragmentOperation; import android.window.TaskFragmentParentInfo; @@ -566,7 +567,8 @@ public class TaskFragmentOrganizerController extends ITaskFragmentOrganizerContr // Keep the calling identity to avoid unsecure change. synchronized (mGlobalLock) { if (isValidTransaction(wct)) { - applyTransaction(wct, transitionType, shouldApplyIndependently); + applyTransaction( + wct, transitionType, shouldApplyIndependently, null /* remoteTransition */); } // Even if the transaction is empty, we still need to invoke #onTransactionFinished // unless the organizer has been unregistered. @@ -587,14 +589,15 @@ public class TaskFragmentOrganizerController extends ITaskFragmentOrganizerContr @Override public void applyTransaction(@NonNull WindowContainerTransaction wct, - @WindowManager.TransitionType int transitionType, boolean shouldApplyIndependently) { + @WindowManager.TransitionType int transitionType, boolean shouldApplyIndependently, + @Nullable RemoteTransition remoteTransition) { // Keep the calling identity to avoid unsecure change. synchronized (mGlobalLock) { if (!isValidTransaction(wct)) { return; } mWindowOrganizerController.applyTaskFragmentTransactionLocked(wct, transitionType, - shouldApplyIndependently); + shouldApplyIndependently, remoteTransition); } } @@ -839,6 +842,7 @@ public class TaskFragmentOrganizerController extends ITaskFragmentOrganizerContr Slog.e(TAG, "Caller organizer=" + organizer + " is no longer registered"); return false; } + return true; } diff --git a/services/core/java/com/android/server/wm/TaskOrganizerController.java b/services/core/java/com/android/server/wm/TaskOrganizerController.java index 41e49b9f0466..12392a63a467 100644 --- a/services/core/java/com/android/server/wm/TaskOrganizerController.java +++ b/services/core/java/com/android/server/wm/TaskOrganizerController.java @@ -35,6 +35,7 @@ import android.app.ActivityManager.RunningTaskInfo; import android.app.WindowConfiguration; import android.content.Intent; import android.content.pm.ParceledListSlice; +import android.content.res.Configuration; import android.graphics.Rect; import android.os.Binder; import android.os.IBinder; @@ -733,7 +734,8 @@ class TaskOrganizerController extends ITaskOrganizerController.Stub { * the task was removed from hierarchy. */ int addWindowlessStartingSurface(Task task, ActivityRecord activity, SurfaceControl root, - TaskSnapshot taskSnapshot, IWindowlessStartingSurfaceCallback callback) { + TaskSnapshot taskSnapshot, Configuration configuration, + IWindowlessStartingSurfaceCallback callback) { final Task rootTask = task.getRootTask(); if (rootTask == null) { return INVALID_TASK_ID; @@ -743,6 +745,7 @@ class TaskOrganizerController extends ITaskOrganizerController.Stub { return INVALID_TASK_ID; } final StartingWindowInfo info = task.getStartingWindowInfo(activity); + info.taskInfo.configuration.setTo(configuration); info.taskInfo.taskDescription = activity.taskDescription; info.taskSnapshot = taskSnapshot; info.windowlessStartingSurfaceCallback = callback; @@ -1195,8 +1198,7 @@ class TaskOrganizerController extends ITaskOrganizerController.Stub { } public boolean handleInterceptBackPressedOnTaskRoot(Task task) { - if (task == null || !task.isOrganized() - || !mInterceptBackPressedOnRootTasks.contains(task.mTaskId)) { + if (!shouldInterceptBackPressedOnRootTask(task)) { return false; } final TaskOrganizerPendingEventsQueue pendingEventsQueue = @@ -1229,6 +1231,11 @@ class TaskOrganizerController extends ITaskOrganizerController.Stub { return true; } + boolean shouldInterceptBackPressedOnRootTask(Task task) { + return task != null && task.isOrganized() + && mInterceptBackPressedOnRootTasks.contains(task.mTaskId); + } + public void dump(PrintWriter pw, String prefix) { final String innerPrefix = prefix + " "; pw.print(prefix); pw.println("TaskOrganizerController:"); diff --git a/services/core/java/com/android/server/wm/WindowManagerService.java b/services/core/java/com/android/server/wm/WindowManagerService.java index 9fb7e8ddbd20..9eb3389ff43c 100644 --- a/services/core/java/com/android/server/wm/WindowManagerService.java +++ b/services/core/java/com/android/server/wm/WindowManagerService.java @@ -2020,7 +2020,7 @@ public class WindowManagerService extends IWindowManager.Stub } if (win.mActivityRecord != null) { - win.mActivityRecord.postWindowRemoveStartingWindowCleanup(); + win.mActivityRecord.postWindowRemoveStartingWindowCleanup(win); } if (win.mAttrs.type == TYPE_WALLPAPER) { diff --git a/services/core/java/com/android/server/wm/WindowOrganizerController.java b/services/core/java/com/android/server/wm/WindowOrganizerController.java index a8b9417edb9b..95e25151e8cc 100644 --- a/services/core/java/com/android/server/wm/WindowOrganizerController.java +++ b/services/core/java/com/android/server/wm/WindowOrganizerController.java @@ -103,6 +103,7 @@ import android.window.ITransitionMetricsReporter; import android.window.ITransitionPlayer; import android.window.IWindowContainerTransactionCallback; import android.window.IWindowOrganizerController; +import android.window.RemoteTransition; import android.window.TaskFragmentAnimationParams; import android.window.TaskFragmentCreationParams; import android.window.TaskFragmentOperation; @@ -464,12 +465,20 @@ class WindowOrganizerController extends IWindowOrganizerController.Stub * transition, which will be queued until the sync engine is * free if there is any other active sync. If {@code false}, * the {@code wct} will be directly applied to the active sync. + * @param remoteTransition {@link RemoteTransition} to apply for the transaction. Only available + * for system organizers. */ void applyTaskFragmentTransactionLocked(@NonNull WindowContainerTransaction wct, - @WindowManager.TransitionType int type, boolean shouldApplyIndependently) { + @WindowManager.TransitionType int type, boolean shouldApplyIndependently, + @Nullable RemoteTransition remoteTransition) { enforceTaskFragmentOrganizerPermission("applyTaskFragmentTransaction()", Objects.requireNonNull(wct.getTaskFragmentOrganizer()), Objects.requireNonNull(wct)); + if (remoteTransition != null && !mTaskFragmentOrganizerController.isSystemOrganizer( + wct.getTaskFragmentOrganizer().asBinder())) { + throw new SecurityException( + "Only a system organizer is allowed to use remote transition!"); + } final CallerInfo caller = new CallerInfo(); final long ident = Binder.clearCallingIdentity(); try { @@ -512,7 +521,7 @@ class WindowOrganizerController extends IWindowOrganizerController.Stub return; } mTransitionController.requestStartTransition(transition, null /* startTask */, - null /* remoteTransition */, null /* displayChange */); + remoteTransition, null /* displayChange */); transition.setAllReady(); }; mTransitionController.startCollectOrQueue(transition, doApply); @@ -1135,16 +1144,12 @@ class WindowOrganizerController extends IWindowOrganizerController.Stub if (pipTask == null) { break; } - ActivityRecord[] pipActivity = new ActivityRecord[1]; - pipTask.forAllActivities((activity) -> { - if (activity.pictureInPictureArgs != null) { - pipActivity[0] = activity; - } - }); + ActivityRecord pipActivity = pipTask.getActivity( + (activity) -> activity.pictureInPictureArgs != null); Rect entryBounds = hop.getBounds(); mService.mRootWindowContainer.moveActivityToPinnedRootTask( - pipActivity[0], null /* launchIntoPipHostActivity */, + pipActivity, null /* launchIntoPipHostActivity */, "moveActivityToPinnedRootTask", null /* transition */, entryBounds); effects |= TRANSACT_EFFECTS_LIFECYCLE; break; diff --git a/services/core/java/com/android/server/wm/WindowSurfaceController.java b/services/core/java/com/android/server/wm/WindowSurfaceController.java index 33751b9f16a0..209d93421fc1 100644 --- a/services/core/java/com/android/server/wm/WindowSurfaceController.java +++ b/services/core/java/com/android/server/wm/WindowSurfaceController.java @@ -28,7 +28,6 @@ import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_VISIBILITY; import static com.android.server.wm.WindowManagerDebugConfig.SHOW_LIGHT_TRANSACTIONS; import static com.android.server.wm.WindowManagerDebugConfig.TAG_WITH_CLASS_NAME; import static com.android.server.wm.WindowManagerDebugConfig.TAG_WM; -import static com.android.server.wm.WindowSurfaceControllerProto.LAYER; import static com.android.server.wm.WindowSurfaceControllerProto.SHOWN; import android.os.Debug; @@ -53,18 +52,6 @@ class WindowSurfaceController { // Should only be set from within setShown(). private boolean mSurfaceShown = false; - private float mSurfaceX = 0; - private float mSurfaceY = 0; - - // Initialize to the identity matrix. - private float mLastDsdx = 1; - private float mLastDtdx = 0; - private float mLastDsdy = 0; - private float mLastDtdy = 1; - - private float mSurfaceAlpha = 0; - - private int mSurfaceLayer = 0; private final String title; @@ -73,8 +60,6 @@ class WindowSurfaceController { private final int mWindowType; private final Session mWindowSession; - // Used to track whether we have called detach children on the way to invisibility. - boolean mChildrenDetached; WindowSurfaceController(String name, int format, int flags, WindowStateAnimator animator, int windowType) { @@ -157,44 +142,11 @@ class WindowSurfaceController { } } - void setPosition(SurfaceControl.Transaction t, float left, float top) { - final boolean surfaceMoved = mSurfaceX != left || mSurfaceY != top; - if (!surfaceMoved) { - return; - } - - mSurfaceX = left; - mSurfaceY = top; - - ProtoLog.i(WM_SHOW_TRANSACTIONS, - "SURFACE POS (setPositionInTransaction) @ (%f,%f): %s", left, top, title); - - t.setPosition(mSurfaceControl, left, top); - } - - void setMatrix(SurfaceControl.Transaction t, float dsdx, float dtdx, float dtdy, float dsdy) { - final boolean matrixChanged = mLastDsdx != dsdx || mLastDtdx != dtdx || - mLastDtdy != dtdy || mLastDsdy != dsdy; - if (!matrixChanged) { - return; - } - - mLastDsdx = dsdx; - mLastDtdx = dtdx; - mLastDtdy = dtdy; - mLastDsdy = dsdy; - - ProtoLog.i(WM_SHOW_TRANSACTIONS, "SURFACE MATRIX [%f,%f,%f,%f]: %s", - dsdx, dtdx, dtdy, dsdy, title); - t.setMatrix(mSurfaceControl, dsdx, dtdx, dtdy, dsdy); - } - boolean prepareToShowInTransaction(SurfaceControl.Transaction t, float alpha) { if (mSurfaceControl == null) { return false; } - mSurfaceAlpha = alpha; t.setAlpha(mSurfaceControl, alpha); return true; } @@ -305,7 +257,6 @@ class WindowSurfaceController { void dumpDebug(ProtoOutputStream proto, long fieldId) { final long token = proto.start(fieldId); proto.write(SHOWN, mSurfaceShown); - proto.write(LAYER, mSurfaceLayer); proto.end(token); } @@ -314,13 +265,6 @@ class WindowSurfaceController { pw.print(prefix); pw.print("mSurface="); pw.println(mSurfaceControl); } pw.print(prefix); pw.print("Surface: shown="); pw.print(mSurfaceShown); - pw.print(" layer="); pw.print(mSurfaceLayer); - pw.print(" alpha="); pw.print(mSurfaceAlpha); - pw.print(" rect=("); pw.print(mSurfaceX); - pw.print(","); pw.print(mSurfaceY); pw.print(") "); - pw.print(" transform=("); pw.print(mLastDsdx); pw.print(", "); - pw.print(mLastDtdx); pw.print(", "); pw.print(mLastDsdy); - pw.print(", "); pw.print(mLastDtdy); pw.println(")"); } @Override diff --git a/services/credentials/java/com/android/server/credentials/CredentialManagerService.java b/services/credentials/java/com/android/server/credentials/CredentialManagerService.java index a4adf5866f3d..627461a2c6ed 100644 --- a/services/credentials/java/com/android/server/credentials/CredentialManagerService.java +++ b/services/credentials/java/com/android/server/credentials/CredentialManagerService.java @@ -862,37 +862,41 @@ public final class CredentialManagerService Slog.i(TAG, "isEnabledCredentialProviderService with componentName: " + componentName.flattenToString()); - // TODO(253157366): Check additional set of services. final int userId = UserHandle.getCallingUserId(); final int callingUid = Binder.getCallingUid(); enforceCallingPackage(callingPackage, callingUid); - synchronized (mLock) { - final List<CredentialManagerServiceImpl> services = - getServiceListForUserLocked(userId); - for (CredentialManagerServiceImpl s : services) { - final ComponentName serviceComponentName = s.getServiceComponentName(); - - if (serviceComponentName.equals(componentName)) { - if (!s.getServicePackageName().equals(callingPackage)) { - // The component name and the package name do not match. - MetricUtilities.logApiCalledSimpleV2( - ApiName.IS_ENABLED_CREDENTIAL_PROVIDER_SERVICE, - ApiStatus.FAILURE, callingUid); - Slog.w( - TAG, - "isEnabledCredentialProviderService: Component name does " - + "not match package name."); - return false; - } - MetricUtilities.logApiCalledSimpleV2( - ApiName.IS_ENABLED_CREDENTIAL_PROVIDER_SERVICE, - ApiStatus.SUCCESS, callingUid); - return true; - } - } + + if (componentName == null) { + Slog.w(TAG, "isEnabledCredentialProviderService componentName is null"); + // If the component name was not specified then throw an error and + // record a failure because the request failed due to invalid input. + MetricUtilities.logApiCalledSimpleV2( + ApiName.IS_ENABLED_CREDENTIAL_PROVIDER_SERVICE, + ApiStatus.FAILURE, callingUid); + return false; + } + + if (!componentName.getPackageName().equals(callingPackage)) { + Slog.w(TAG, "isEnabledCredentialProviderService component name" + + " does not match requested component"); + // If the requested component name package name does not match + // the calling package then throw an error and record a failure + // metric (because the request failed due to invalid input). + MetricUtilities.logApiCalledSimpleV2( + ApiName.IS_ENABLED_CREDENTIAL_PROVIDER_SERVICE, + ApiStatus.FAILURE, callingUid); + throw new IllegalArgumentException("provided component name does not match" + + " does not match requesting component"); } - return false; + final Set<ComponentName> enabledProviders = getEnabledProvidersForUser(userId); + MetricUtilities.logApiCalledSimpleV2( + ApiName.IS_ENABLED_CREDENTIAL_PROVIDER_SERVICE, + ApiStatus.SUCCESS, callingUid); + if (enabledProviders == null) { + return false; + } + return enabledProviders.contains(componentName); } @Override diff --git a/services/proguard.flags b/services/proguard.flags index e11e613adb5c..261bb7cacdc4 100644 --- a/services/proguard.flags +++ b/services/proguard.flags @@ -47,6 +47,11 @@ -keep,allowoptimization,allowaccessmodification class com.android.net.module.util.* { *; } -keep,allowoptimization,allowaccessmodification public class com.android.server.net.IpConfigStore { *; } -keep,allowoptimization,allowaccessmodification public class com.android.server.net.BaseNetworkObserver { *; } +-keep,allowoptimization,allowaccessmodification class com.android.server.display.feature.DisplayManagerFlags { *; } +-keep,allowoptimization,allowaccessmodification class android.app.admin.flags.FeatureFlagsImpl { *; } +-keep,allowoptimization,allowaccessmodification class com.android.server.input.NativeInputManagerService$NativeImpl { *; } +-keep,allowoptimization,allowaccessmodification class com.android.server.ThreadPriorityBooster { *; } +-keep,allowaccessmodification class android.app.admin.flags.Flags { *; } # Referenced via CarServiceHelperService in car-frameworks-service (avoid removing) -keep public class com.android.server.utils.Slogf { *; } @@ -99,9 +104,6 @@ -keep,allowoptimization,allowaccessmodification class com.android.server.input.InputManagerService { <methods>; } --keep,allowoptimization,allowaccessmodification class com.android.server.input.NativeInputManagerService$NativeImpl { - <methods>; -} -keep,allowoptimization,allowaccessmodification class com.android.server.usb.UsbHostManager { *** usbDeviceRemoved(...); *** usbDeviceAdded(...); diff --git a/services/tests/mockingservicestests/src/com/android/server/am/ActivityManagerServiceTest.java b/services/tests/mockingservicestests/src/com/android/server/am/ActivityManagerServiceTest.java index 3ee8050cda3e..032d026648df 100644 --- a/services/tests/mockingservicestests/src/com/android/server/am/ActivityManagerServiceTest.java +++ b/services/tests/mockingservicestests/src/com/android/server/am/ActivityManagerServiceTest.java @@ -86,6 +86,9 @@ import android.os.Process; import android.os.RemoteException; import android.os.SystemClock; 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.provider.DeviceConfig; import android.util.IntArray; import android.util.Log; @@ -96,6 +99,7 @@ import androidx.test.filters.SmallTest; import androidx.test.platform.app.InstrumentationRegistry; import com.android.dx.mockito.inline.extended.ExtendedMockito; +import com.android.sdksandbox.flags.Flags; import com.android.server.LocalServices; import com.android.server.am.ActivityManagerService.StickyBroadcast; import com.android.server.am.ProcessList.IsolatedUidRange; @@ -145,8 +149,11 @@ public class ActivityManagerServiceTest { private static final String TEST_EXTRA_KEY1 = "com.android.server.am.TEST_EXTRA_KEY1"; private static final String TEST_EXTRA_VALUE1 = "com.android.server.am.TEST_EXTRA_VALUE1"; + private static final String PROPERTY_APPLY_SDK_SANDBOX_AUDIT_RESTRICTIONS = + "apply_sdk_sandbox_audit_restrictions"; private static final String PROPERTY_APPLY_SDK_SANDBOX_NEXT_RESTRICTIONS = "apply_sdk_sandbox_next_restrictions"; + private static final String APPLY_SDK_SANDBOX_AUDIT_RESTRICTIONS = ":isSdkSandboxAudit"; private static final String APPLY_SDK_SANDBOX_NEXT_RESTRICTIONS = ":isSdkSandboxNext"; private static final int TEST_UID = 11111; private static final int USER_ID = 666; @@ -183,6 +190,9 @@ public class ActivityManagerServiceTest { public final ApplicationExitInfoTest.ServiceThreadRule mServiceThreadRule = new ApplicationExitInfoTest.ServiceThreadRule(); + @Rule + public final CheckFlagsRule mCheckFlagsRule = DeviceFlagsValueProvider.createCheckFlagsRule(); + private Context mContext = getInstrumentation().getTargetContext(); @Mock private AppOpsService mAppOpsService; @@ -338,6 +348,7 @@ public class ActivityManagerServiceTest { mockitoSession.finishMocking(); } } + @SuppressWarnings("GuardedBy") @SmallTest @Test @@ -367,6 +378,77 @@ public class ActivityManagerServiceTest { } } + @SuppressWarnings("GuardedBy") + @SmallTest + @Test + @RequiresFlagsEnabled(Flags.FLAG_SELINUX_SDK_SANDBOX_AUDIT) + public void applySdkSandboxAuditRestrictions() throws Exception { + MockitoSession mockitoSession = + ExtendedMockito.mockitoSession().spyStatic(Process.class).startMocking(); + try { + sProcessListSettingsListener.onPropertiesChanged( + new DeviceConfig.Properties( + DeviceConfig.NAMESPACE_ADSERVICES, + Map.of(PROPERTY_APPLY_SDK_SANDBOX_AUDIT_RESTRICTIONS, "true"))); + assertThat(sProcessListSettingsListener.applySdkSandboxRestrictionsAudit()).isTrue(); + ExtendedMockito.doReturn(true).when(() -> Process.isSdkSandboxUid(anyInt())); + ApplicationInfo info = new ApplicationInfo(); + info.packageName = "com.android.sdksandbox"; + info.seInfo = "default:targetSdkVersion=34:complete"; + final ProcessRecord appRec = + new ProcessRecord( + mAms, + info, + TAG, + Process.FIRST_SDK_SANDBOX_UID, + /* sdkSandboxClientPackageName= */ "com.example.client", + /* definingUid= */ 0, + /* definingProcessName= */ ""); + assertThat(mAms.mProcessList.updateSeInfo(appRec)) + .contains(APPLY_SDK_SANDBOX_AUDIT_RESTRICTIONS); + } finally { + mockitoSession.finishMocking(); + } + } + + @SuppressWarnings("GuardedBy") + @SmallTest + @Test + public void applySdkSandboxNextAndAuditRestrictions() throws Exception { + MockitoSession mockitoSession = + ExtendedMockito.mockitoSession().spyStatic(Process.class).startMocking(); + try { + sProcessListSettingsListener.onPropertiesChanged( + new DeviceConfig.Properties( + DeviceConfig.NAMESPACE_ADSERVICES, + Map.of(PROPERTY_APPLY_SDK_SANDBOX_NEXT_RESTRICTIONS, "true"))); + sProcessListSettingsListener.onPropertiesChanged( + new DeviceConfig.Properties( + DeviceConfig.NAMESPACE_ADSERVICES, + Map.of(PROPERTY_APPLY_SDK_SANDBOX_AUDIT_RESTRICTIONS, "true"))); + assertThat(sProcessListSettingsListener.applySdkSandboxRestrictionsNext()).isTrue(); + assertThat(sProcessListSettingsListener.applySdkSandboxRestrictionsAudit()).isTrue(); + ExtendedMockito.doReturn(true).when(() -> Process.isSdkSandboxUid(anyInt())); + ApplicationInfo info = new ApplicationInfo(); + info.packageName = "com.android.sdksandbox"; + info.seInfo = "default:targetSdkVersion=34:complete"; + final ProcessRecord appRec = + new ProcessRecord( + mAms, + info, + TAG, + Process.FIRST_SDK_SANDBOX_UID, + /* sdkSandboxClientPackageName= */ "com.example.client", + /* definingUid= */ 0, + /* definingProcessName= */ ""); + assertThat(mAms.mProcessList.updateSeInfo(appRec)) + .contains(APPLY_SDK_SANDBOX_NEXT_RESTRICTIONS); + assertThat(mAms.mProcessList.updateSeInfo(appRec)) + .doesNotContain(APPLY_SDK_SANDBOX_AUDIT_RESTRICTIONS); + } finally { + mockitoSession.finishMocking(); + } + } private UidRecord addUidRecord(int uid) { final UidRecord uidRec = new UidRecord(uid, mAms); diff --git a/services/tests/mockingservicestests/src/com/android/server/job/controllers/ConnectivityControllerTest.java b/services/tests/mockingservicestests/src/com/android/server/job/controllers/ConnectivityControllerTest.java index 809a0e80dd63..64e86f9ab1fd 100644 --- a/services/tests/mockingservicestests/src/com/android/server/job/controllers/ConnectivityControllerTest.java +++ b/services/tests/mockingservicestests/src/com/android/server/job/controllers/ConnectivityControllerTest.java @@ -983,9 +983,8 @@ public class ConnectivityControllerTest { final JobStatus blue = createJobStatus(createJob() .setEstimatedNetworkBytes(DataUnit.MEBIBYTES.toBytes(1), 0) .setRequiredNetworkType(JobInfo.NETWORK_TYPE_ANY), UID_BLUE); - // Unmetered preference is disabled for now. assertFalse(red.getPreferUnmetered()); - assertFalse(blue.getPreferUnmetered()); + assertTrue(blue.getPreferUnmetered()); controller.maybeStartTrackingJobLocked(red, null); controller.maybeStartTrackingJobLocked(blue, null); @@ -1039,7 +1038,7 @@ public class ConnectivityControllerTest { generalCallback.onLost(meteredNet); assertTrue(red.isConstraintSatisfied(JobStatus.CONSTRAINT_CONNECTIVITY)); - assertTrue(red.getHasAccessToUnmetered()); + assertFalse(red.getHasAccessToUnmetered()); assertTrue(blue.isConstraintSatisfied(JobStatus.CONSTRAINT_CONNECTIVITY)); assertTrue(blue.getHasAccessToUnmetered()); diff --git a/services/tests/mockingservicestests/src/com/android/server/job/controllers/FlexibilityControllerTest.java b/services/tests/mockingservicestests/src/com/android/server/job/controllers/FlexibilityControllerTest.java index 7ae6a2d5996d..bb9dcf1c85cc 100644 --- a/services/tests/mockingservicestests/src/com/android/server/job/controllers/FlexibilityControllerTest.java +++ b/services/tests/mockingservicestests/src/com/android/server/job/controllers/FlexibilityControllerTest.java @@ -189,10 +189,7 @@ public class FlexibilityControllerTest { } private static JobInfo.Builder createJob(int id) { - return new JobInfo.Builder(id, new ComponentName("foo", "bar")) - .setPrefersBatteryNotLow(true) - .setPrefersCharging(true) - .setPrefersDeviceIdle(true); + return new JobInfo.Builder(id, new ComponentName("foo", "bar")); } private JobStatus createJobStatus(String testTag, JobInfo.Builder job) { @@ -536,15 +533,12 @@ public class FlexibilityControllerTest { jb = createJob(i); if (i > 0) { jb.setRequiresDeviceIdle(true); - jb.setPrefersDeviceIdle(false); } if (i > 1) { jb.setRequiresBatteryNotLow(true); - jb.setPrefersBatteryNotLow(false); } if (i > 2) { jb.setRequiresCharging(true); - jb.setPrefersCharging(false); } jobs[i] = createJobStatus("", jb); flexTracker.add(jobs[i]); @@ -553,55 +547,53 @@ public class FlexibilityControllerTest { synchronized (mFlexibilityController.mLock) { ArrayList<ArraySet<JobStatus>> trackedJobs = flexTracker.getArrayList(); assertEquals(1, trackedJobs.get(0).size()); - assertEquals(1, trackedJobs.get(1).size()); - assertEquals(1, trackedJobs.get(2).size()); - assertEquals(1, trackedJobs.get(3).size()); + assertEquals(0, trackedJobs.get(1).size()); + assertEquals(0, trackedJobs.get(2).size()); + assertEquals(3, trackedJobs.get(3).size()); assertEquals(0, trackedJobs.get(4).size()); flexTracker.adjustJobsRequiredConstraints(jobs[0], -1, FROZEN_TIME); assertEquals(1, trackedJobs.get(0).size()); - assertEquals(1, trackedJobs.get(1).size()); - assertEquals(2, trackedJobs.get(2).size()); - assertEquals(0, trackedJobs.get(3).size()); + assertEquals(0, trackedJobs.get(1).size()); + assertEquals(1, trackedJobs.get(2).size()); + assertEquals(2, trackedJobs.get(3).size()); assertEquals(0, trackedJobs.get(4).size()); flexTracker.adjustJobsRequiredConstraints(jobs[0], -1, FROZEN_TIME); assertEquals(1, trackedJobs.get(0).size()); - assertEquals(2, trackedJobs.get(1).size()); - assertEquals(1, trackedJobs.get(2).size()); - assertEquals(0, trackedJobs.get(3).size()); + assertEquals(1, trackedJobs.get(1).size()); + assertEquals(0, trackedJobs.get(2).size()); + assertEquals(2, trackedJobs.get(3).size()); assertEquals(0, trackedJobs.get(4).size()); flexTracker.adjustJobsRequiredConstraints(jobs[0], -1, FROZEN_TIME); assertEquals(2, trackedJobs.get(0).size()); - assertEquals(1, trackedJobs.get(1).size()); - assertEquals(1, trackedJobs.get(2).size()); - assertEquals(0, trackedJobs.get(3).size()); + assertEquals(0, trackedJobs.get(1).size()); + assertEquals(0, trackedJobs.get(2).size()); + assertEquals(2, trackedJobs.get(3).size()); assertEquals(0, trackedJobs.get(4).size()); flexTracker.remove(jobs[1]); assertEquals(2, trackedJobs.get(0).size()); - assertEquals(1, trackedJobs.get(1).size()); + assertEquals(0, trackedJobs.get(1).size()); assertEquals(0, trackedJobs.get(2).size()); - assertEquals(0, trackedJobs.get(3).size()); + assertEquals(1, trackedJobs.get(3).size()); assertEquals(0, trackedJobs.get(4).size()); flexTracker.resetJobNumDroppedConstraints(jobs[0], FROZEN_TIME); assertEquals(1, trackedJobs.get(0).size()); - assertEquals(1, trackedJobs.get(1).size()); + assertEquals(0, trackedJobs.get(1).size()); assertEquals(0, trackedJobs.get(2).size()); - assertEquals(1, trackedJobs.get(3).size()); + assertEquals(2, trackedJobs.get(3).size()); assertEquals(0, trackedJobs.get(4).size()); flexTracker.adjustJobsRequiredConstraints(jobs[0], -2, FROZEN_TIME); assertEquals(1, trackedJobs.get(0).size()); - assertEquals(2, trackedJobs.get(1).size()); + assertEquals(1, trackedJobs.get(1).size()); assertEquals(0, trackedJobs.get(2).size()); - assertEquals(0, trackedJobs.get(3).size()); + assertEquals(1, trackedJobs.get(3).size()); assertEquals(0, trackedJobs.get(4).size()); - // Over halfway through the flex window. The job that prefers all flex constraints - // should have its first flex constraint dropped. final long nowElapsed = ((DEFAULT_FALLBACK_FLEXIBILITY_DEADLINE_MS / 2) + HOUR_IN_MILLIS); JobSchedulerService.sElapsedRealtimeClock = @@ -609,9 +601,9 @@ public class FlexibilityControllerTest { flexTracker.resetJobNumDroppedConstraints(jobs[0], nowElapsed); assertEquals(1, trackedJobs.get(0).size()); - assertEquals(1, trackedJobs.get(1).size()); + assertEquals(0, trackedJobs.get(1).size()); assertEquals(1, trackedJobs.get(2).size()); - assertEquals(0, trackedJobs.get(3).size()); + assertEquals(1, trackedJobs.get(3).size()); assertEquals(0, trackedJobs.get(4).size()); } } @@ -626,13 +618,8 @@ public class FlexibilityControllerTest { @Test public void testExceptions_UserInitiated() { - JobInfo.Builder jb = createJob(0) - .setUserInitiated(true) - .setRequiredNetworkType(JobInfo.NETWORK_TYPE_ANY) - // Attempt to add flex constraints to the job. For now, we will ignore them. - .setPrefersBatteryNotLow(true) - .setPrefersCharging(true) - .setPrefersDeviceIdle(false); + JobInfo.Builder jb = createJob(0); + jb.setUserInitiated(true).setRequiredNetworkType(JobInfo.NETWORK_TYPE_ANY); JobStatus js = createJobStatus("testExceptions_UserInitiated", jb); assertFalse(js.hasFlexibilityConstraint()); } @@ -648,10 +635,10 @@ public class FlexibilityControllerTest { @Test public void testExceptions_NoFlexibleConstraints() { - JobInfo.Builder jb = createJob(0) - .setPrefersBatteryNotLow(false) - .setPrefersCharging(false) - .setPrefersDeviceIdle(false); + JobInfo.Builder jb = createJob(0); + jb.setRequiresDeviceIdle(true); + jb.setRequiresCharging(true); + jb.setRequiresBatteryNotLow(true); JobStatus js = createJobStatus("testExceptions_NoFlexibleConstraints", jb); assertFalse(js.hasFlexibilityConstraint()); } @@ -710,50 +697,15 @@ public class FlexibilityControllerTest { JobStatus js = createJobStatus("testTopAppBypass", jb); synchronized (mFlexibilityController.mLock) { js.setHasAccessToUnmetered(false); - assertEquals(0, mFlexibilityController.getNumSatisfiedFlexibleConstraintsLocked(js)); + assertEquals(0, mFlexibilityController.getNumSatisfiedRequiredConstraintsLocked(js)); js.setHasAccessToUnmetered(true); - assertEquals(1, mFlexibilityController.getNumSatisfiedFlexibleConstraintsLocked(js)); + assertEquals(1, mFlexibilityController.getNumSatisfiedRequiredConstraintsLocked(js)); js.setHasAccessToUnmetered(false); - assertEquals(0, mFlexibilityController.getNumSatisfiedFlexibleConstraintsLocked(js)); + assertEquals(0, mFlexibilityController.getNumSatisfiedRequiredConstraintsLocked(js)); } } @Test - public void testGetNumSatisfiedFlexibleConstraints() { - long nowElapsed = FROZEN_TIME; - mFlexibilityController.setConstraintSatisfied(CONSTRAINT_BATTERY_NOT_LOW, true, nowElapsed); - mFlexibilityController.setConstraintSatisfied(CONSTRAINT_CHARGING, true, nowElapsed); - mFlexibilityController.setConstraintSatisfied(CONSTRAINT_IDLE, true, nowElapsed); - JobInfo.Builder jb = createJob(0) - .setPrefersBatteryNotLow(false) - .setPrefersCharging(false) - .setPrefersDeviceIdle(false); - JobStatus js = createJobStatus("testGetNumSatisfiedFlexibleConstraints", jb); - assertEquals(0, mFlexibilityController.getNumSatisfiedFlexibleConstraintsLocked(js)); - - jb = createJob(0) - .setPrefersBatteryNotLow(true) - .setPrefersCharging(false) - .setPrefersDeviceIdle(false); - js = createJobStatus("testGetNumSatisfiedFlexibleConstraints", jb); - assertEquals(1, mFlexibilityController.getNumSatisfiedFlexibleConstraintsLocked(js)); - - jb = createJob(0) - .setPrefersBatteryNotLow(true) - .setPrefersCharging(false) - .setPrefersDeviceIdle(true); - js = createJobStatus("testGetNumSatisfiedFlexibleConstraints", jb); - assertEquals(2, mFlexibilityController.getNumSatisfiedFlexibleConstraintsLocked(js)); - - jb = createJob(0) - .setPrefersBatteryNotLow(true) - .setPrefersCharging(true) - .setPrefersDeviceIdle(true); - js = createJobStatus("testGetNumSatisfiedFlexibleConstraints", jb); - assertEquals(3, mFlexibilityController.getNumSatisfiedFlexibleConstraintsLocked(js)); - } - - @Test public void testSetConstraintSatisfied_Constraints() { mFlexibilityController.setConstraintSatisfied(CONSTRAINT_IDLE, false, FROZEN_TIME); assertFalse(mFlexibilityController.isConstraintSatisfied(CONSTRAINT_IDLE)); @@ -784,11 +736,8 @@ public class FlexibilityControllerTest { jb = createJob(i); constraints = constraintCombinations[i]; jb.setRequiresDeviceIdle((constraints & CONSTRAINT_IDLE) != 0); - jb.setPrefersDeviceIdle((constraints & CONSTRAINT_IDLE) == 0); jb.setRequiresBatteryNotLow((constraints & CONSTRAINT_BATTERY_NOT_LOW) != 0); - jb.setPrefersBatteryNotLow((constraints & CONSTRAINT_BATTERY_NOT_LOW) == 0); jb.setRequiresCharging((constraints & CONSTRAINT_CHARGING) != 0); - jb.setPrefersCharging((constraints & CONSTRAINT_CHARGING) == 0); synchronized (mFlexibilityController.mLock) { mFlexibilityController.maybeStartTrackingJobLocked( createJobStatus(String.valueOf(i), jb), null); diff --git a/services/tests/mockingservicestests/src/com/android/server/job/controllers/JobStatusTest.java b/services/tests/mockingservicestests/src/com/android/server/job/controllers/JobStatusTest.java index 1de7e3719112..92aa982c3dd1 100644 --- a/services/tests/mockingservicestests/src/com/android/server/job/controllers/JobStatusTest.java +++ b/services/tests/mockingservicestests/src/com/android/server/job/controllers/JobStatusTest.java @@ -1240,9 +1240,7 @@ public class JobStatusTest { @Test public void testReadinessStatusWithConstraint_FlexibilityConstraint() { final JobStatus job = createJobStatus( - new JobInfo.Builder(101, new ComponentName("foo", "bar")) - .setPrefersCharging(true) - .build()); + new JobInfo.Builder(101, new ComponentName("foo", "bar")).build()); job.setConstraintSatisfied(CONSTRAINT_FLEXIBLE, sElapsedRealtimeClock.millis(), false); markImplicitConstraintsSatisfied(job, true); assertTrue(job.readinessStatusWithConstraint(CONSTRAINT_FLEXIBLE, true)); diff --git a/services/tests/mockingservicestests/src/com/android/server/pm/PackageArchiverTest.java b/services/tests/mockingservicestests/src/com/android/server/pm/PackageArchiverTest.java index 5c8a19c76887..1e65c89643fd 100644 --- a/services/tests/mockingservicestests/src/com/android/server/pm/PackageArchiverTest.java +++ b/services/tests/mockingservicestests/src/com/android/server/pm/PackageArchiverTest.java @@ -16,6 +16,8 @@ package com.android.server.pm; +import static android.app.AppOpsManager.MODE_ALLOWED; +import static android.app.AppOpsManager.MODE_IGNORED; import static android.content.Intent.FLAG_RECEIVER_FOREGROUND; import static android.content.pm.PackageManager.DELETE_ARCHIVE; import static android.content.pm.PackageManager.DELETE_KEEP_DATA; @@ -103,6 +105,8 @@ public class PackageArchiverTest { @Mock private ActivityManager mActivityManager; @Mock + private AppOpsManager mAppOpsManager; + @Mock private PackageManager mPackageManager; @Mock private PackageInstallerService mInstallerService; @@ -160,12 +164,17 @@ public class PackageArchiverTest { when(mPackageState.getUserStateOrDefault(eq(mUserId))).thenReturn(mUserState); when(mContext.getSystemService(LauncherApps.class)).thenReturn(mLauncherApps); + when(mContext.getSystemService(AppOpsManager.class)).thenReturn( + mAppOpsManager); when(mLauncherApps.getActivityList(eq(PACKAGE), eq(UserHandle.CURRENT))).thenReturn( mLauncherActivityInfos); when(mContext.getSystemService(ActivityManager.class)).thenReturn(mActivityManager); when(mActivityManager.getLauncherLargeIconDensity()).thenReturn(100); + when(mAppOpsManager.checkOp( + eq(AppOpsManager.OP_AUTO_REVOKE_PERMISSIONS_IF_UNUSED), + anyInt(), eq(PACKAGE))).thenReturn(MODE_ALLOWED); doReturn(mComputer).when(mPackageManagerService).snapshotComputer(); when(mComputer.getPackageUid(eq(CALLER_PACKAGE), eq(0L), eq(mUserId))).thenReturn( Binder.getCallingUid()); @@ -305,6 +314,21 @@ public class PackageArchiverTest { } @Test + public void archiveApp_appOptedOutOfArchiving() { + when(mAppOpsManager.checkOp( + eq(AppOpsManager.OP_AUTO_REVOKE_PERMISSIONS_IF_UNUSED), + anyInt(), eq(PACKAGE))).thenReturn(MODE_IGNORED); + + Exception e = assertThrows( + ParcelableException.class, + () -> mArchiveManager.requestArchive(PACKAGE, CALLER_PACKAGE, mIntentSender, + UserHandle.CURRENT)); + assertThat(e.getCause()).isInstanceOf(PackageManager.NameNotFoundException.class); + assertThat(e.getCause()).hasMessageThat().isEqualTo( + TextUtils.formatSimple("The app %s is opted out of archiving.", PACKAGE)); + } + + @Test public void archiveApp_success() { mArchiveManager.requestArchive(PACKAGE, CALLER_PACKAGE, mIntentSender, UserHandle.CURRENT); rule.mocks().getHandler().flush(); @@ -319,6 +343,39 @@ public class PackageArchiverTest { } @Test + public void isAppArchivable_success() throws PackageManager.NameNotFoundException { + assertThat(mArchiveManager.isAppArchivable(PACKAGE, UserHandle.CURRENT)).isTrue(); + } + + @Test + public void isAppArchivable_installerDoesntSupportUnarchival() + throws PackageManager.NameNotFoundException { + doReturn(new ParceledListSlice<>(List.of())) + .when(mPackageManagerService).queryIntentReceivers(any(), any(), any(), anyLong(), + eq(mUserId)); + + assertThat(mArchiveManager.isAppArchivable(PACKAGE, UserHandle.CURRENT)).isFalse(); + } + + @Test + public void isAppArchivable_noMainActivities() throws PackageManager.NameNotFoundException { + when(mLauncherApps.getActivityList(eq(PACKAGE), eq(UserHandle.CURRENT))).thenReturn( + List.of()); + + assertThat(mArchiveManager.isAppArchivable(PACKAGE, UserHandle.CURRENT)).isFalse(); + } + + @Test + public void isAppArchivable_appOptedOutOfArchiving() + throws PackageManager.NameNotFoundException { + when(mAppOpsManager.checkOp( + eq(AppOpsManager.OP_AUTO_REVOKE_PERMISSIONS_IF_UNUSED), + anyInt(), eq(PACKAGE))).thenReturn(MODE_IGNORED); + + assertThat(mArchiveManager.isAppArchivable(PACKAGE, UserHandle.CURRENT)).isFalse(); + } + + @Test public void unarchiveApp_callerPackageNameIncorrect() { mUserState.setArchiveState(createArchiveState()).setInstalled(false); diff --git a/services/tests/servicestests/res/xml/user_100_v9.xml b/services/tests/servicestests/res/xml/user_100_v9.xml new file mode 100644 index 000000000000..03c08ed40828 --- /dev/null +++ b/services/tests/servicestests/res/xml/user_100_v9.xml @@ -0,0 +1,20 @@ +<user id="100" + serialNumber="0" + flags="3091" + type="android.os.usertype.full.SYSTEM" + created="0" + lastLoggedIn="0" + lastLoggedInFingerprint="0" + profileBadge="0"> + <restrictions no_oem_unlock="true" /> + <device_policy_local_restrictions> + <restrictions_user user_id="0"> + <restrictions no_camera="true" /> + </restrictions_user> + <restrictions_user user_id="100"> + <restrictions no_camera="true" /> + <restrictions no_install_unknown_sources="true" /> + </restrictions_user> + </device_policy_local_restrictions> + <ignorePrepareStorageErrors>false</ignorePrepareStorageErrors> +</user>
\ No newline at end of file diff --git a/services/tests/servicestests/src/com/android/server/accessibility/AccessibilityManagerServiceTest.java b/services/tests/servicestests/src/com/android/server/accessibility/AccessibilityManagerServiceTest.java index b9e45bab7ab3..82efdd3ce40a 100644 --- a/services/tests/servicestests/src/com/android/server/accessibility/AccessibilityManagerServiceTest.java +++ b/services/tests/servicestests/src/com/android/server/accessibility/AccessibilityManagerServiceTest.java @@ -535,6 +535,78 @@ public class AccessibilityManagerServiceTest { @SmallTest @Test + public void testOnClientChange_magnificationTripleTapEnabled_requestConnection() { + when(mProxyManager.canRetrieveInteractiveWindowsLocked()).thenReturn(false); + + final AccessibilityUserState userState = mA11yms.mUserStates.get( + mA11yms.getCurrentUserIdLocked()); + userState.setMagnificationCapabilitiesLocked( + Settings.Secure.ACCESSIBILITY_MAGNIFICATION_MODE_ALL); + userState.setMagnificationSingleFingerTripleTapEnabledLocked(true); + + // Invokes client change to trigger onUserStateChanged. + mA11yms.onClientChangeLocked(/* serviceInfoChanged= */false); + + verify(mMockWindowMagnificationMgr).requestConnection(true); + } + + @SmallTest + @Test + public void testOnClientChange_magnificationTripleTapDisabled_requestDisconnection() { + when(mProxyManager.canRetrieveInteractiveWindowsLocked()).thenReturn(false); + + final AccessibilityUserState userState = mA11yms.mUserStates.get( + mA11yms.getCurrentUserIdLocked()); + userState.setMagnificationCapabilitiesLocked( + Settings.Secure.ACCESSIBILITY_MAGNIFICATION_MODE_ALL); + //userState.setMagnificationSingleFingerTripleTapEnabledLocked(false); + userState.setMagnificationSingleFingerTripleTapEnabledLocked(false); + + // Invokes client change to trigger onUserStateChanged. + mA11yms.onClientChangeLocked(/* serviceInfoChanged= */false); + + verify(mMockWindowMagnificationMgr).requestConnection(false); + } + + @SmallTest + @Test + @RequiresFlagsEnabled(Flags.FLAG_ENABLE_MAGNIFICATION_MULTIPLE_FINGER_MULTIPLE_TAP_GESTURE) + public void testOnClientChange_magnificationTwoFingerTripleTapEnabled_requestConnection() { + when(mProxyManager.canRetrieveInteractiveWindowsLocked()).thenReturn(false); + + final AccessibilityUserState userState = mA11yms.mUserStates.get( + mA11yms.getCurrentUserIdLocked()); + userState.setMagnificationCapabilitiesLocked( + Settings.Secure.ACCESSIBILITY_MAGNIFICATION_MODE_ALL); + userState.setMagnificationTwoFingerTripleTapEnabledLocked(true); + + // Invokes client change to trigger onUserStateChanged. + mA11yms.onClientChangeLocked(/* serviceInfoChanged= */false); + + verify(mMockWindowMagnificationMgr).requestConnection(true); + } + + @SmallTest + @Test + @RequiresFlagsEnabled(Flags.FLAG_ENABLE_MAGNIFICATION_MULTIPLE_FINGER_MULTIPLE_TAP_GESTURE) + public void testOnClientChange_magnificationTwoFingerTripleTapDisabled_requestDisconnection() { + when(mProxyManager.canRetrieveInteractiveWindowsLocked()).thenReturn(false); + + final AccessibilityUserState userState = mA11yms.mUserStates.get( + mA11yms.getCurrentUserIdLocked()); + userState.setMagnificationCapabilitiesLocked( + Settings.Secure.ACCESSIBILITY_MAGNIFICATION_MODE_ALL); + //userState.setMagnificationSingleFingerTripleTapEnabledLocked(false); + userState.setMagnificationTwoFingerTripleTapEnabledLocked(false); + + // Invokes client change to trigger onUserStateChanged. + mA11yms.onClientChangeLocked(/* serviceInfoChanged= */false); + + verify(mMockWindowMagnificationMgr).requestConnection(false); + } + + @SmallTest + @Test public void testOnClientChange_boundServiceCanControlMagnification_requestConnection() { when(mProxyManager.canRetrieveInteractiveWindowsLocked()).thenReturn(false); @@ -547,6 +619,64 @@ public class AccessibilityManagerServiceTest { verify(mMockWindowMagnificationMgr).requestConnection(true); } + @SmallTest + @Test + public void testOnClientChange_magnificationTripleTapDisabled_removeMagnificationButton() { + final AccessibilityUserState userState = mA11yms.mUserStates.get( + mA11yms.getCurrentUserIdLocked()); + userState.setMagnificationCapabilitiesLocked(ACCESSIBILITY_MAGNIFICATION_MODE_WINDOW); + userState.setMagnificationSingleFingerTripleTapEnabledLocked(false); + + // Invokes client change to trigger onUserStateChanged. + mA11yms.onClientChangeLocked(/* serviceInfoChanged= */false); + + verify(mMockWindowMagnificationMgr, atLeastOnce()).removeMagnificationButton(anyInt()); + } + + @SmallTest + @Test + public void testOnClientChange_magnificationTripleTapEnabled_keepMagnificationButton() { + final AccessibilityUserState userState = mA11yms.mUserStates.get( + mA11yms.getCurrentUserIdLocked()); + userState.setMagnificationCapabilitiesLocked(ACCESSIBILITY_MAGNIFICATION_MODE_ALL); + userState.setMagnificationSingleFingerTripleTapEnabledLocked(true); + + // Invokes client change to trigger onUserStateChanged. + mA11yms.onClientChangeLocked(/* serviceInfoChanged= */false); + + verify(mMockWindowMagnificationMgr, never()).removeMagnificationButton(anyInt()); + } + + @SmallTest + @Test + @RequiresFlagsEnabled(Flags.FLAG_ENABLE_MAGNIFICATION_MULTIPLE_FINGER_MULTIPLE_TAP_GESTURE) + public void onClientChange_magnificationTwoFingerTripleTapDisabled_removeMagnificationButton() { + final AccessibilityUserState userState = mA11yms.mUserStates.get( + mA11yms.getCurrentUserIdLocked()); + userState.setMagnificationCapabilitiesLocked(ACCESSIBILITY_MAGNIFICATION_MODE_WINDOW); + userState.setMagnificationTwoFingerTripleTapEnabledLocked(false); + + // Invokes client change to trigger onUserStateChanged. + mA11yms.onClientChangeLocked(/* serviceInfoChanged= */false); + + verify(mMockWindowMagnificationMgr, atLeastOnce()).removeMagnificationButton(anyInt()); + } + + @SmallTest + @Test + @RequiresFlagsEnabled(Flags.FLAG_ENABLE_MAGNIFICATION_MULTIPLE_FINGER_MULTIPLE_TAP_GESTURE) + public void onClientChange_magnificationTwoFingerTripleTapEnabled_keepMagnificationButton() { + final AccessibilityUserState userState = mA11yms.mUserStates.get( + mA11yms.getCurrentUserIdLocked()); + userState.setMagnificationCapabilitiesLocked(ACCESSIBILITY_MAGNIFICATION_MODE_ALL); + userState.setMagnificationTwoFingerTripleTapEnabledLocked(true); + + // Invokes client change to trigger onUserStateChanged. + mA11yms.onClientChangeLocked(/* serviceInfoChanged= */false); + + verify(mMockWindowMagnificationMgr, never()).removeMagnificationButton(anyInt()); + } + @Test public void testUnbindIme_whenServiceUnbinds() { setupAccessibilityServiceConnection(AccessibilityServiceInfo.FLAG_INPUT_METHOD_EDITOR); diff --git a/services/tests/servicestests/src/com/android/server/contentprotection/ContentProtectionAllowlistManagerTest.java b/services/tests/servicestests/src/com/android/server/contentprotection/ContentProtectionAllowlistManagerTest.java index dc38f2bf3083..a28647e49664 100644 --- a/services/tests/servicestests/src/com/android/server/contentprotection/ContentProtectionAllowlistManagerTest.java +++ b/services/tests/servicestests/src/com/android/server/contentprotection/ContentProtectionAllowlistManagerTest.java @@ -33,6 +33,7 @@ import android.os.Handler; import android.os.UserHandle; import android.os.test.TestLooper; import android.platform.test.flag.junit.SetFlagsRule; +import android.service.contentcapture.IContentProtectionAllowlistCallback; import androidx.test.ext.junit.runners.AndroidJUnit4; import androidx.test.filters.SmallTest; @@ -48,6 +49,8 @@ import org.mockito.Mock; import org.mockito.junit.MockitoJUnit; import org.mockito.junit.MockitoRule; +import java.util.List; + /** * Test for {@link ContentProtectionAllowlistManager}. * @@ -58,7 +61,9 @@ import org.mockito.junit.MockitoRule; @SmallTest public class ContentProtectionAllowlistManagerTest { - private static final String PACKAGE_NAME = "com.test.package.name"; + private static final String FIRST_PACKAGE_NAME = "com.test.first.package.name"; + + private static final String SECOND_PACKAGE_NAME = "com.test.second.package.name"; private static final long TIMEOUT_MS = 111_111_111L; @@ -74,12 +79,18 @@ public class ContentProtectionAllowlistManagerTest { @Mock private RemoteContentProtectionService mMockRemoteContentProtectionService; + @Mock private IContentProtectionAllowlistCallback mMockAllowlistCallback; + private final TestLooper mTestLooper = new TestLooper(); private Handler mHandler; private ContentProtectionAllowlistManager mContentProtectionAllowlistManager; + private boolean mUseMockPackageMonitor = true; + + private boolean mUseMockAllowlistCallback = true; + @Before public void setup() { mHandler = new Handler(mTestLooper.getLooper()); @@ -91,6 +102,8 @@ public class ContentProtectionAllowlistManagerTest { assertThat(mHandler.hasMessagesOrCallbacks()).isFalse(); verifyZeroInteractions(mMockContentCaptureManagerService); verifyZeroInteractions(mMockPackageMonitor); + verifyZeroInteractions(mMockRemoteContentProtectionService); + verifyZeroInteractions(mMockAllowlistCallback); } @Test @@ -103,6 +116,8 @@ public class ContentProtectionAllowlistManagerTest { assertThat(mHandler.hasMessagesOrCallbacks()).isTrue(); verifyZeroInteractions(mMockContentCaptureManagerService); verifyZeroInteractions(mMockPackageMonitor); + verifyZeroInteractions(mMockRemoteContentProtectionService); + verifyZeroInteractions(mMockAllowlistCallback); } @Test @@ -117,6 +132,8 @@ public class ContentProtectionAllowlistManagerTest { verify(mMockContentCaptureManagerService).createRemoteContentProtectionService(); verify(mMockPackageMonitor).register(any(), eq(UserHandle.ALL), eq(mHandler)); verify(mMockPackageMonitor, never()).unregister(); + verifyZeroInteractions(mMockRemoteContentProtectionService); + verifyZeroInteractions(mMockAllowlistCallback); } @Test @@ -132,6 +149,8 @@ public class ContentProtectionAllowlistManagerTest { verify(mMockContentCaptureManagerService).createRemoteContentProtectionService(); verify(mMockPackageMonitor).register(any(), eq(UserHandle.ALL), eq(mHandler)); verify(mMockPackageMonitor, never()).unregister(); + verifyZeroInteractions(mMockRemoteContentProtectionService); + verifyZeroInteractions(mMockAllowlistCallback); } @Test @@ -144,6 +163,8 @@ public class ContentProtectionAllowlistManagerTest { assertThat(mHandler.hasMessagesOrCallbacks()).isTrue(); verifyZeroInteractions(mMockContentCaptureManagerService); verifyZeroInteractions(mMockPackageMonitor); + verifyZeroInteractions(mMockRemoteContentProtectionService); + verifyZeroInteractions(mMockAllowlistCallback); } @Test @@ -158,6 +179,8 @@ public class ContentProtectionAllowlistManagerTest { verifyZeroInteractions(mMockContentCaptureManagerService); verify(mMockPackageMonitor).register(any(), eq(UserHandle.ALL), eq(mHandler)); verify(mMockPackageMonitor, never()).unregister(); + verifyZeroInteractions(mMockRemoteContentProtectionService); + verifyZeroInteractions(mMockAllowlistCallback); } @Test @@ -173,6 +196,8 @@ public class ContentProtectionAllowlistManagerTest { verifyZeroInteractions(mMockContentCaptureManagerService); verify(mMockPackageMonitor).register(any(), eq(UserHandle.ALL), eq(mHandler)); verify(mMockPackageMonitor, never()).unregister(); + verifyZeroInteractions(mMockRemoteContentProtectionService); + verifyZeroInteractions(mMockAllowlistCallback); } @Test @@ -186,6 +211,8 @@ public class ContentProtectionAllowlistManagerTest { verifyZeroInteractions(mMockContentCaptureManagerService); verify(mMockPackageMonitor, never()).register(any(), any(), any()); verify(mMockPackageMonitor).unregister(); + verifyZeroInteractions(mMockRemoteContentProtectionService); + verifyZeroInteractions(mMockAllowlistCallback); } @Test @@ -201,6 +228,8 @@ public class ContentProtectionAllowlistManagerTest { verifyZeroInteractions(mMockContentCaptureManagerService); verify(mMockPackageMonitor, never()).register(any(), any(), any()); verify(mMockPackageMonitor).unregister(); + verifyZeroInteractions(mMockRemoteContentProtectionService); + verifyZeroInteractions(mMockAllowlistCallback); } @Test @@ -216,6 +245,8 @@ public class ContentProtectionAllowlistManagerTest { verify(mMockContentCaptureManagerService).createRemoteContentProtectionService(); verify(mMockPackageMonitor).register(any(), eq(UserHandle.ALL), eq(mHandler)); verify(mMockPackageMonitor).unregister(); + verifyZeroInteractions(mMockRemoteContentProtectionService); + verifyZeroInteractions(mMockAllowlistCallback); } @Test @@ -229,6 +260,8 @@ public class ContentProtectionAllowlistManagerTest { verifyZeroInteractions(mMockContentCaptureManagerService); verify(mMockPackageMonitor, never()).register(any(), any(), any()); verify(mMockPackageMonitor).unregister(); + verifyZeroInteractions(mMockRemoteContentProtectionService); + verifyZeroInteractions(mMockAllowlistCallback); } @Test @@ -244,6 +277,8 @@ public class ContentProtectionAllowlistManagerTest { verifyZeroInteractions(mMockContentCaptureManagerService); verify(mMockPackageMonitor, never()).register(any(), any(), any()); verify(mMockPackageMonitor).unregister(); + verifyZeroInteractions(mMockRemoteContentProtectionService); + verifyZeroInteractions(mMockAllowlistCallback); } @Test @@ -259,6 +294,8 @@ public class ContentProtectionAllowlistManagerTest { verifyZeroInteractions(mMockContentCaptureManagerService); verify(mMockPackageMonitor).register(any(), eq(UserHandle.ALL), eq(mHandler)); verify(mMockPackageMonitor).unregister(); + verifyZeroInteractions(mMockRemoteContentProtectionService); + verifyZeroInteractions(mMockAllowlistCallback); } @Test @@ -274,6 +311,8 @@ public class ContentProtectionAllowlistManagerTest { assertThat(mHandler.hasMessagesOrCallbacks()).isFalse(); verify(mMockPackageMonitor).register(any(), eq(UserHandle.ALL), eq(mHandler)); verify(mMockPackageMonitor).unregister(); + verifyZeroInteractions(mMockRemoteContentProtectionService); + verifyZeroInteractions(mMockAllowlistCallback); } @Test @@ -290,60 +329,130 @@ public class ContentProtectionAllowlistManagerTest { assertThat(mHandler.hasMessagesOrCallbacks()).isFalse(); verify(mMockPackageMonitor, times(2)).register(any(), eq(UserHandle.ALL), eq(mHandler)); verify(mMockPackageMonitor).unregister(); + verifyZeroInteractions(mMockRemoteContentProtectionService); + verifyZeroInteractions(mMockAllowlistCallback); + } + + @Test + public void isAllowed_default() { + boolean actual = mContentProtectionAllowlistManager.isAllowed(FIRST_PACKAGE_NAME); + + assertThat(actual).isFalse(); + verifyZeroInteractions(mMockContentCaptureManagerService); + verifyZeroInteractions(mMockPackageMonitor); + verifyZeroInteractions(mMockRemoteContentProtectionService); + verifyZeroInteractions(mMockAllowlistCallback); } @Test - public void isAllowed() { - boolean actual = mContentProtectionAllowlistManager.isAllowed(PACKAGE_NAME); + public void isAllowed_false() throws Exception { + mUseMockAllowlistCallback = false; + ContentProtectionAllowlistManager manager = new TestContentProtectionAllowlistManager(); + manager.mAllowlistCallback.setAllowlist(List.of(FIRST_PACKAGE_NAME)); + mTestLooper.dispatchNext(); + + boolean actual = manager.isAllowed(SECOND_PACKAGE_NAME); assertThat(actual).isFalse(); verifyZeroInteractions(mMockContentCaptureManagerService); verifyZeroInteractions(mMockPackageMonitor); + verifyZeroInteractions(mMockRemoteContentProtectionService); } @Test - public void handleUpdate_updateDisabled() { + public void isAllowed_true() throws Exception { + mUseMockAllowlistCallback = false; + ContentProtectionAllowlistManager manager = new TestContentProtectionAllowlistManager(); + manager.mAllowlistCallback.setAllowlist(List.of(FIRST_PACKAGE_NAME)); + mTestLooper.dispatchNext(); + + boolean actual = manager.isAllowed(FIRST_PACKAGE_NAME); + + assertThat(actual).isTrue(); + verifyZeroInteractions(mMockContentCaptureManagerService); + verifyZeroInteractions(mMockPackageMonitor); + verifyZeroInteractions(mMockRemoteContentProtectionService); + } + + @Test + public void handlePackagesChanged_updateDisabled() { mSetFlagsRule.disableFlags(FLAG_BLOCKLIST_UPDATE_ENABLED); - ContentProtectionAllowlistManager manager = - new ContentProtectionAllowlistManager( - mMockContentCaptureManagerService, mHandler, TIMEOUT_MS); + mUseMockPackageMonitor = false; + ContentProtectionAllowlistManager manager = new TestContentProtectionAllowlistManager(); manager.mPackageMonitor.onSomePackagesChanged(); verifyZeroInteractions(mMockContentCaptureManagerService); + verifyZeroInteractions(mMockRemoteContentProtectionService); + verifyZeroInteractions(mMockAllowlistCallback); } @Test - public void handleUpdate_updateEnabled() { + public void handlePackagesChanged_updateEnabled_noService() { mSetFlagsRule.enableFlags(FLAG_BLOCKLIST_UPDATE_ENABLED); - ContentProtectionAllowlistManager manager = - new ContentProtectionAllowlistManager( - mMockContentCaptureManagerService, mHandler, TIMEOUT_MS); + mUseMockPackageMonitor = false; + ContentProtectionAllowlistManager manager = new TestContentProtectionAllowlistManager(); manager.mPackageMonitor.onSomePackagesChanged(); verify(mMockContentCaptureManagerService).createRemoteContentProtectionService(); + verifyZeroInteractions(mMockRemoteContentProtectionService); + verifyZeroInteractions(mMockAllowlistCallback); } @Test - public void handleUpdate_rateLimit_noService() { + public void handlePackagesChanged_updateEnabled_withService() { mSetFlagsRule.enableFlags(FLAG_BLOCKLIST_UPDATE_ENABLED); - ContentProtectionAllowlistManager manager = - new ContentProtectionAllowlistManager( - mMockContentCaptureManagerService, mHandler, TIMEOUT_MS); + mUseMockPackageMonitor = false; + ContentProtectionAllowlistManager manager = new TestContentProtectionAllowlistManager(); + when(mMockContentCaptureManagerService.createRemoteContentProtectionService()) + .thenReturn(mMockRemoteContentProtectionService); + + manager.mPackageMonitor.onSomePackagesChanged(); + + verify(mMockRemoteContentProtectionService) + .onUpdateAllowlistRequest(mMockAllowlistCallback); + verifyZeroInteractions(mMockAllowlistCallback); + } + + @Test + public void handlePackagesChanged_updateEnabled_withServiceException() { + mSetFlagsRule.enableFlags(FLAG_BLOCKLIST_UPDATE_ENABLED); + mUseMockPackageMonitor = false; + ContentProtectionAllowlistManager manager = new TestContentProtectionAllowlistManager(); + when(mMockContentCaptureManagerService.createRemoteContentProtectionService()) + .thenReturn(mMockRemoteContentProtectionService); + doThrow(new RuntimeException("TEST EXCEPTION")) + .when(mMockRemoteContentProtectionService) + .onUpdateAllowlistRequest(mMockAllowlistCallback); + + manager.mPackageMonitor.onSomePackagesChanged(); + + // Does not rethrow + verify(mMockRemoteContentProtectionService) + .onUpdateAllowlistRequest(mMockAllowlistCallback); + verifyZeroInteractions(mMockAllowlistCallback); + } + + @Test + public void handlePackagesChanged_rateLimit_noService() { + mSetFlagsRule.enableFlags(FLAG_BLOCKLIST_UPDATE_ENABLED); + mUseMockPackageMonitor = false; + ContentProtectionAllowlistManager manager = new TestContentProtectionAllowlistManager(); manager.mPackageMonitor.onSomePackagesChanged(); manager.mPackageMonitor.onSomePackagesChanged(); verify(mMockContentCaptureManagerService, times(2)).createRemoteContentProtectionService(); + verifyZeroInteractions(mMockRemoteContentProtectionService); + verifyZeroInteractions(mMockAllowlistCallback); } @Test - public void handleUpdate_rateLimit_beforeTimeout() { + public void handlePackagesChanged_rateLimit_beforeTimeout() { mSetFlagsRule.enableFlags(FLAG_BLOCKLIST_UPDATE_ENABLED); - ContentProtectionAllowlistManager manager = - new ContentProtectionAllowlistManager( - mMockContentCaptureManagerService, mHandler, TIMEOUT_MS); + mUseMockPackageMonitor = false; + ContentProtectionAllowlistManager manager = new TestContentProtectionAllowlistManager(); when(mMockContentCaptureManagerService.createRemoteContentProtectionService()) .thenReturn(mMockRemoteContentProtectionService); @@ -351,32 +460,68 @@ public class ContentProtectionAllowlistManagerTest { manager.mPackageMonitor.onSomePackagesChanged(); verify(mMockContentCaptureManagerService).createRemoteContentProtectionService(); + verify(mMockRemoteContentProtectionService) + .onUpdateAllowlistRequest(mMockAllowlistCallback); + verifyZeroInteractions(mMockAllowlistCallback); } @Test - public void handleUpdate_rateLimit_afterTimeout() { + public void handlePackagesChanged_rateLimit_afterTimeout() { mSetFlagsRule.enableFlags(FLAG_BLOCKLIST_UPDATE_ENABLED); + mUseMockPackageMonitor = false; ContentProtectionAllowlistManager manager = - new ContentProtectionAllowlistManager( - mMockContentCaptureManagerService, mHandler, /* timeoutMs= */ 0L); + new TestContentProtectionAllowlistManager(/* timeoutMs= */ 0L); + when(mMockContentCaptureManagerService.createRemoteContentProtectionService()) + .thenReturn(mMockRemoteContentProtectionService); + + manager.mPackageMonitor.onSomePackagesChanged(); + manager.mPackageMonitor.onSomePackagesChanged(); + + verify(mMockContentCaptureManagerService, times(2)).createRemoteContentProtectionService(); + verify(mMockRemoteContentProtectionService, times(2)) + .onUpdateAllowlistRequest(mMockAllowlistCallback); + verifyZeroInteractions(mMockAllowlistCallback); + } + + @Test + public void handlePackagesChanged_rateLimit_afterUpdate() throws Exception { + mSetFlagsRule.enableFlags(FLAG_BLOCKLIST_UPDATE_ENABLED); + mUseMockPackageMonitor = false; + mUseMockAllowlistCallback = false; + ContentProtectionAllowlistManager manager = new TestContentProtectionAllowlistManager(); when(mMockContentCaptureManagerService.createRemoteContentProtectionService()) .thenReturn(mMockRemoteContentProtectionService); manager.mPackageMonitor.onSomePackagesChanged(); + manager.mAllowlistCallback.setAllowlist(List.of()); + mTestLooper.dispatchNext(); manager.mPackageMonitor.onSomePackagesChanged(); verify(mMockContentCaptureManagerService, times(2)).createRemoteContentProtectionService(); + verify(mMockRemoteContentProtectionService, times(2)) + .onUpdateAllowlistRequest(manager.mAllowlistCallback); } private class TestContentProtectionAllowlistManager extends ContentProtectionAllowlistManager { TestContentProtectionAllowlistManager() { - super(mMockContentCaptureManagerService, mHandler, TIMEOUT_MS); + this(TIMEOUT_MS); + } + + TestContentProtectionAllowlistManager(long timeoutMs) { + super(mMockContentCaptureManagerService, mHandler, timeoutMs); + } + + @Override + protected IContentProtectionAllowlistCallback createAllowlistCallback() { + return mUseMockAllowlistCallback + ? mMockAllowlistCallback + : super.createAllowlistCallback(); } @Override protected PackageMonitor createPackageMonitor() { - return mMockPackageMonitor; + return mUseMockPackageMonitor ? mMockPackageMonitor : super.createPackageMonitor(); } } } diff --git a/services/tests/servicestests/src/com/android/server/job/JobStoreTest.java b/services/tests/servicestests/src/com/android/server/job/JobStoreTest.java index 4bb7d63995ac..2db46e60aea0 100644 --- a/services/tests/servicestests/src/com/android/server/job/JobStoreTest.java +++ b/services/tests/servicestests/src/com/android/server/job/JobStoreTest.java @@ -784,66 +784,6 @@ public class JobStoreTest { } @Test - public void testPersistedPreferredBatteryNotLowConstraint() throws Exception { - JobInfo.Builder b = new Builder(8, mComponent) - .setPrefersBatteryNotLow(true) - .setPersisted(true); - JobStatus taskStatus = - JobStatus.createFromJobInfo(b.build(), SOME_UID, null, -1, null, null); - - mTaskStoreUnderTest.add(taskStatus); - waitForPendingIo(); - - final JobSet jobStatusSet = new JobSet(); - mTaskStoreUnderTest.readJobMapFromDisk(jobStatusSet, true); - assertEquals("Incorrect # of persisted tasks.", 1, jobStatusSet.size()); - JobStatus loaded = jobStatusSet.getAllJobs().iterator().next(); - assertEquals("Battery-not-low constraint not persisted correctly.", - taskStatus.getJob().isPreferBatteryNotLow(), - loaded.getJob().isPreferBatteryNotLow()); - } - - @Test - public void testPersistedPreferredChargingConstraint() throws Exception { - JobInfo.Builder b = new Builder(8, mComponent) - .setPrefersCharging(true) - .setPersisted(true); - JobStatus taskStatus = - JobStatus.createFromJobInfo(b.build(), SOME_UID, null, -1, null, null); - - mTaskStoreUnderTest.add(taskStatus); - waitForPendingIo(); - - final JobSet jobStatusSet = new JobSet(); - mTaskStoreUnderTest.readJobMapFromDisk(jobStatusSet, true); - assertEquals("Incorrect # of persisted tasks.", 1, jobStatusSet.size()); - JobStatus loaded = jobStatusSet.getAllJobs().iterator().next(); - assertEquals("Charging constraint not persisted correctly.", - taskStatus.getJob().isPreferCharging(), - loaded.getJob().isPreferCharging()); - } - - @Test - public void testPersistedPreferredDeviceIdleConstraint() throws Exception { - JobInfo.Builder b = new Builder(8, mComponent) - .setPrefersDeviceIdle(true) - .setPersisted(true); - JobStatus taskStatus = - JobStatus.createFromJobInfo(b.build(), SOME_UID, null, -1, null, null); - - mTaskStoreUnderTest.add(taskStatus); - waitForPendingIo(); - - final JobSet jobStatusSet = new JobSet(); - mTaskStoreUnderTest.readJobMapFromDisk(jobStatusSet, true); - assertEquals("Incorrect # of persisted tasks.", 1, jobStatusSet.size()); - JobStatus loaded = jobStatusSet.getAllJobs().iterator().next(); - assertEquals("Idle constraint not persisted correctly.", - taskStatus.getJob().isPreferDeviceIdle(), - loaded.getJob().isPreferDeviceIdle()); - } - - @Test public void testJobWorkItems() throws Exception { JobWorkItem item1 = new JobWorkItem.Builder().build(); item1.bumpDeliveryCount(); diff --git a/services/tests/servicestests/src/com/android/server/pm/UserManagerServiceUserInfoTest.java b/services/tests/servicestests/src/com/android/server/pm/UserManagerServiceUserInfoTest.java index 253592c9a07d..d1b2e8e6d868 100644 --- a/services/tests/servicestests/src/com/android/server/pm/UserManagerServiceUserInfoTest.java +++ b/services/tests/servicestests/src/com/android/server/pm/UserManagerServiceUserInfoTest.java @@ -43,6 +43,7 @@ import android.annotation.UserIdInt; import android.app.PropertyInvalidatedCache; import android.content.pm.UserInfo; import android.content.pm.UserInfo.UserInfoFlag; +import android.content.res.Resources; import android.multiuser.Flags; import android.os.Looper; import android.os.Parcel; @@ -50,21 +51,26 @@ import android.os.UserHandle; import android.os.UserManager; import android.platform.test.annotations.Presubmit; import android.text.TextUtils; +import android.util.Xml; import androidx.test.InstrumentationRegistry; import androidx.test.filters.MediumTest; import androidx.test.runner.AndroidJUnit4; +import com.android.frameworks.servicestests.R; import com.android.server.LocalServices; import com.android.server.pm.UserManagerService.UserData; import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; +import org.xmlpull.v1.XmlPullParser; +import org.xmlpull.v1.XmlSerializer; import java.io.ByteArrayInputStream; import java.io.ByteArrayOutputStream; import java.io.DataOutputStream; +import java.nio.charset.StandardCharsets; import java.util.List; /** @@ -77,6 +83,7 @@ import java.util.List; @MediumTest public class UserManagerServiceUserInfoTest { private UserManagerService mUserManagerService; + private Resources mResources; @Before public void setup() { @@ -96,6 +103,8 @@ public class UserManagerServiceUserInfoTest { assertEquals("Multiple users so this test can't run.", 1, users.size()); assertEquals("Only user present isn't the system user.", UserHandle.USER_SYSTEM, users.get(0).id); + + mResources = InstrumentationRegistry.getTargetContext().getResources(); } @Test @@ -109,7 +118,7 @@ public class UserManagerServiceUserInfoTest { byte[] bytes = baos.toByteArray(); UserData read = mUserManagerService.readUserLP( - data.info.id, new ByteArrayInputStream(bytes)); + data.info.id, new ByteArrayInputStream(bytes), 0); assertUserInfoEquals(data.info, read.info, /* parcelCopy= */ false); } @@ -146,11 +155,13 @@ public class UserManagerServiceUserInfoTest { // Clear the restrictions to see if they are properly read in from the user file. setUserRestrictions(data.info.id, globalRestriction, localRestriction, false); + final int userVersion = 10; //read the secondary and SYSTEM user file to fetch local/global device policy restrictions. - mUserManagerService.readUserLP(data.info.id, new ByteArrayInputStream(secondaryUserBytes)); + mUserManagerService.readUserLP(data.info.id, new ByteArrayInputStream(secondaryUserBytes), + userVersion); if (Flags.saveGlobalAndGuestRestrictionsOnSystemUserXmlReadOnly()) { mUserManagerService.readUserLP(UserHandle.USER_SYSTEM, - new ByteArrayInputStream(systemUserBytes)); + new ByteArrayInputStream(systemUserBytes), userVersion); } assertTrue(mUserManagerService.hasUserRestrictionOnAnyUser(globalRestriction)); @@ -303,6 +314,45 @@ public class UserManagerServiceUserInfoTest { assertTrue(mUserManagerService.isUserOfType(106, USER_TYPE_FULL_DEMO)); } + /** Tests readUserLP upgrading from version 9 to 10+. */ + @Test + public void testUserRestrictionsUpgradeFromV9() throws Exception { + final String[] localRestrictions = new String[] { + UserManager.DISALLOW_CAMERA, + UserManager.DISALLOW_INSTALL_UNKNOWN_SOURCES, + }; + + final int userId = 100; + UserData data = new UserData(); + data.info = createUser(userId, FLAG_FULL, "A type"); + + mUserManagerService.putUserInfo(data.info); + + for (String restriction : localRestrictions) { + assertFalse(mUserManagerService.hasBaseUserRestriction(restriction, userId)); + assertFalse(mUserManagerService.hasUserRestriction(restriction, userId)); + } + + // Convert the xml resource to the system storage xml format. + ByteArrayOutputStream baos = new ByteArrayOutputStream(); + DataOutputStream os = new DataOutputStream(baos); + XmlPullParser in = mResources.getXml(R.xml.user_100_v9); + XmlSerializer out = Xml.newBinarySerializer(); + out.setOutput(os, StandardCharsets.UTF_8.name()); + Xml.copy(in, out); + byte[] userBytes = baos.toByteArray(); + baos.reset(); + + final int userVersion = 9; + mUserManagerService.readUserLP(data.info.id, new ByteArrayInputStream(userBytes), + userVersion); + + for (String restriction : localRestrictions) { + assertFalse(mUserManagerService.hasBaseUserRestriction(restriction, userId)); + assertTrue(mUserManagerService.hasUserRestriction(restriction, userId)); + } + } + /** Creates a UserInfo with the given flags and userType. */ private UserInfo createUser(@UserIdInt int userId, @UserInfoFlag int flags, String userType) { return new UserInfo(userId, "A Name", "A path", flags, userType); diff --git a/services/tests/wmtests/src/com/android/server/wm/ActivityOptionsTest.java b/services/tests/wmtests/src/com/android/server/wm/ActivityOptionsTest.java index 93adddb2ac6d..6e5baee3dc67 100644 --- a/services/tests/wmtests/src/com/android/server/wm/ActivityOptionsTest.java +++ b/services/tests/wmtests/src/com/android/server/wm/ActivityOptionsTest.java @@ -275,7 +275,7 @@ public class ActivityOptionsTest { case "android.activity.launchTypeBubble": // KEY_LAUNCHED_FROM_BUBBLE case "android.activity.splashScreenStyle": // KEY_SPLASH_SCREEN_STYLE case "android.activity.launchIntoPipParams": // KEY_LAUNCH_INTO_PIP_PARAMS - case "android.activity.dismissKeyguard": // KEY_DISMISS_KEYGUARD + case "android.activity.dismissKeyguardIfInsecure": // KEY_DISMISS_KEYGUARD_IF_INSECURE case "android.activity.pendingIntentCreatorBackgroundActivityStartMode": // KEY_PENDING_INTENT_CREATOR_BACKGROUND_ACTIVITY_START_MODE case "android.activity.launchCookie": // KEY_LAUNCH_COOKIE diff --git a/services/tests/wmtests/src/com/android/server/wm/BackNavigationControllerTests.java b/services/tests/wmtests/src/com/android/server/wm/BackNavigationControllerTests.java index dd7dec0bdb2b..7b1fa036a016 100644 --- a/services/tests/wmtests/src/com/android/server/wm/BackNavigationControllerTests.java +++ b/services/tests/wmtests/src/com/android/server/wm/BackNavigationControllerTests.java @@ -76,6 +76,7 @@ import org.mockito.Mockito; import org.mockito.MockitoSession; import org.mockito.quality.Strictness; +import java.util.ArrayList; import java.util.concurrent.CountDownLatch; import java.util.concurrent.TimeUnit; @@ -601,30 +602,33 @@ public class BackNavigationControllerTests extends WindowTestsBase { final Task task = createTask(mDefaultDisplay); final ActivityRecord bottomActivity = createActivityRecord(task); final ActivityRecord homeActivity = mRootHomeTask.getTopNonFinishingActivity(); - + final ArrayList<ActivityRecord> openActivities = new ArrayList<>(); + openActivities.add(homeActivity); final BackNavigationController.AnimationHandler.ScheduleAnimationBuilder toHomeBuilder = animationHandler.prepareAnimation(BackNavigationInfo.TYPE_RETURN_TO_HOME, - mBackAnimationAdapter, task, mRootHomeTask, bottomActivity, homeActivity); + mBackAnimationAdapter, task, mRootHomeTask, bottomActivity, openActivities); assertTrue(toHomeBuilder.mIsLaunchBehind); toHomeBuilder.build(); - verify(mAtm.mTaskOrganizerController, never()) - .addWindowlessStartingSurface(any(), any(), any(), any(), any()); + verify(mAtm.mTaskOrganizerController, never()).addWindowlessStartingSurface( + any(), any(), any(), any(), any(), any()); animationHandler.clearBackAnimateTarget(); + openActivities.clear(); // Back to ACTIVITY and TASK have the same logic, just with different target. final ActivityRecord topActivity = createActivityRecord(task); + openActivities.add(bottomActivity); final BackNavigationController.AnimationHandler.ScheduleAnimationBuilder toActivityBuilder = animationHandler.prepareAnimation( BackNavigationInfo.TYPE_CROSS_ACTIVITY, mBackAnimationAdapter, task, task, - topActivity, bottomActivity); + topActivity, openActivities); assertFalse(toActivityBuilder.mIsLaunchBehind); toActivityBuilder.build(); if (preferWindowlessSurface) { - verify(mAtm.mTaskOrganizerController) - .addWindowlessStartingSurface(any(), any(), any(), any(), any()); + verify(mAtm.mTaskOrganizerController).addWindowlessStartingSurface( + any(), any(), any(), any(), any(), any()); } else { - verify(mAtm.mTaskOrganizerController, never()) - .addWindowlessStartingSurface(any(), any(), any(), any(), any()); + verify(mAtm.mTaskOrganizerController, never()).addWindowlessStartingSurface( + any(), any(), any(), any(), any(), any()); } } diff --git a/services/tests/wmtests/src/com/android/server/wm/RootWindowContainerTests.java b/services/tests/wmtests/src/com/android/server/wm/RootWindowContainerTests.java index c241033c69d3..eb78906f570d 100644 --- a/services/tests/wmtests/src/com/android/server/wm/RootWindowContainerTests.java +++ b/services/tests/wmtests/src/com/android/server/wm/RootWindowContainerTests.java @@ -872,7 +872,7 @@ public class RootWindowContainerTests extends WindowTestsBase { new TestDisplayContent.Builder(mAtm, 1000, 1500) .setSystemDecorations(true).build(); - // Use invalid user id to let StorageManager.isUserKeyUnlocked() return false. + // Use invalid user id to let StorageManager.isCeStorageUnlocked() return false. final int currentUser = mRootWindowContainer.mCurrentUser; mRootWindowContainer.mCurrentUser = -1; diff --git a/services/tests/wmtests/src/com/android/server/wm/SafeActivityOptionsTest.java b/services/tests/wmtests/src/com/android/server/wm/SafeActivityOptionsTest.java index 9f43a1785266..55a7089f3344 100644 --- a/services/tests/wmtests/src/com/android/server/wm/SafeActivityOptionsTest.java +++ b/services/tests/wmtests/src/com/android/server/wm/SafeActivityOptionsTest.java @@ -145,7 +145,7 @@ public class SafeActivityOptionsTest { verifySecureExceptionThrown(activityOptions, taskSupervisor); activityOptions = ActivityOptions.makeBasic(); - activityOptions.setDismissKeyguard(); + activityOptions.setDismissKeyguardIfInsecure(); verifySecureExceptionThrown(activityOptions, taskSupervisor); activityOptions = ActivityOptions.makeBasic(); diff --git a/services/tests/wmtests/src/com/android/server/wm/TaskFragmentOrganizerControllerTest.java b/services/tests/wmtests/src/com/android/server/wm/TaskFragmentOrganizerControllerTest.java index c57b05130e77..8a90f127f4eb 100644 --- a/services/tests/wmtests/src/com/android/server/wm/TaskFragmentOrganizerControllerTest.java +++ b/services/tests/wmtests/src/com/android/server/wm/TaskFragmentOrganizerControllerTest.java @@ -86,7 +86,9 @@ import android.os.RemoteException; import android.platform.test.annotations.Presubmit; import android.view.RemoteAnimationDefinition; import android.view.SurfaceControl; +import android.window.IRemoteTransition; import android.window.ITaskFragmentOrganizer; +import android.window.RemoteTransition; import android.window.TaskFragmentAnimationParams; import android.window.TaskFragmentCreationParams; import android.window.TaskFragmentInfo; @@ -546,6 +548,35 @@ public class TaskFragmentOrganizerControllerTest extends WindowTestsBase { } @Test + public void testApplyTransaction_disallowRemoteTransitionForNonSystemOrganizer() { + mTransaction.setRelativeBounds(mFragmentWindowToken, new Rect(0, 0, 100, 100)); + mTaskFragment.setTaskFragmentOrganizer(mOrganizerToken, 10 /* uid */, + "Test:TaskFragmentOrganizer" /* processName */); + + // Throw exception if the transaction has remote transition and is not requested by system + // organizer + assertThrows(SecurityException.class, () -> + mController.applyTransaction(mTransaction, TASK_FRAGMENT_TRANSIT_CHANGE, + true /* shouldApplyIndependently */, + new RemoteTransition(mock(IRemoteTransition.class)))); + } + + @Test + public void testApplyTransaction_allowRemoteTransitionForSystemOrganizer() { + mController.unregisterOrganizer(mIOrganizer); + mController.registerOrganizerInternal(mIOrganizer, true /* isSystemOrganizer */); + + mTransaction.setRelativeBounds(mFragmentWindowToken, new Rect(0, 0, 100, 100)); + mTaskFragment.setTaskFragmentOrganizer(mOrganizerToken, 10 /* uid */, + "Test:TaskFragmentOrganizer" /* processName */); + + // Remote transition is allowed for system organizer + mController.applyTransaction(mTransaction, TASK_FRAGMENT_TRANSIT_CHANGE, + true /* shouldApplyIndependently */, + new RemoteTransition(mock(IRemoteTransition.class))); + } + + @Test public void testApplyTransaction_enforceConfigurationChangeOnOrganizedTaskFragment() { // Throw exception if the transaction is trying to change a window that is not organized by // the organizer. @@ -1801,13 +1832,13 @@ public class TaskFragmentOrganizerControllerTest extends WindowTestsBase { private void assertApplyTransactionDisallowed(WindowContainerTransaction t) { assertThrows(SecurityException.class, () -> mController.applyTransaction(t, TASK_FRAGMENT_TRANSIT_CHANGE, - false /* shouldApplyIndependently */)); + false /* shouldApplyIndependently */, null /* remoteTransition */)); } /** Asserts that applying the given transaction will not throw any exception. */ private void assertApplyTransactionAllowed(WindowContainerTransaction t) { mController.applyTransaction(t, TASK_FRAGMENT_TRANSIT_CHANGE, - false /* shouldApplyIndependently */); + false /* shouldApplyIndependently */, null /* remoteTransition */); } /** Asserts that there will be a transaction for TaskFragment appeared. */ diff --git a/services/tests/wmtests/src/com/android/server/wm/WindowOrganizerTests.java b/services/tests/wmtests/src/com/android/server/wm/WindowOrganizerTests.java index 699580a6536d..2c3917387aec 100644 --- a/services/tests/wmtests/src/com/android/server/wm/WindowOrganizerTests.java +++ b/services/tests/wmtests/src/com/android/server/wm/WindowOrganizerTests.java @@ -614,7 +614,7 @@ public class WindowOrganizerTests extends WindowTestsBase { t.setForceTranslucent(taskFragment.mRemoteToken.toWindowContainerToken(), true); mWm.mAtmService.mWindowOrganizerController.applyTaskFragmentTransactionLocked( t, TaskFragmentOrganizer.TASK_FRAGMENT_TRANSIT_CHANGE, - false /* shouldApplyIndependently */); + false /* shouldApplyIndependently */, null /* remoteTransition */); // Should be not visible and not focusable after the transaction. assertFalse(taskFragment.shouldBeVisible(null)); @@ -628,7 +628,7 @@ public class WindowOrganizerTests extends WindowTestsBase { t.setForceTranslucent(taskFragment.mRemoteToken.toWindowContainerToken(), false); mWm.mAtmService.mWindowOrganizerController.applyTaskFragmentTransactionLocked( t, TaskFragmentOrganizer.TASK_FRAGMENT_TRANSIT_CHANGE, - false /* shouldApplyIndependently */); + false /* shouldApplyIndependently */, null /* remoteTransition */); // Should be visible and focusable after the transaction. assertTrue(taskFragment.shouldBeVisible(null)); @@ -680,7 +680,7 @@ public class WindowOrganizerTests extends WindowTestsBase { assertThrows(SecurityException.class, () -> mWm.mAtmService.mWindowOrganizerController.applyTaskFragmentTransactionLocked( t, TaskFragmentOrganizer.TASK_FRAGMENT_TRANSIT_CHANGE, - false /* shouldApplyIndependently */) + false /* shouldApplyIndependently */, null /* remoteTransition */) ); } diff --git a/telecomm/java/android/telecom/TelecomManager.java b/telecomm/java/android/telecom/TelecomManager.java index 1f32c978fad1..55fecfccf108 100644 --- a/telecomm/java/android/telecom/TelecomManager.java +++ b/telecomm/java/android/telecom/TelecomManager.java @@ -19,6 +19,7 @@ import static android.content.Intent.LOCAL_FLAG_FROM_SYSTEM; import android.Manifest; import android.annotation.CallbackExecutor; +import android.annotation.FlaggedApi; import android.annotation.IntDef; import android.annotation.NonNull; import android.annotation.Nullable; @@ -54,6 +55,7 @@ import com.android.internal.annotations.GuardedBy; import com.android.internal.telecom.ClientTransactionalServiceRepository; import com.android.internal.telecom.ClientTransactionalServiceWrapper; import com.android.internal.telecom.ITelecomService; +import com.android.server.telecom.flags.Flags; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; @@ -412,6 +414,14 @@ public class TelecomManager { "android.telecom.extra.CALL_CREATED_TIME_MILLIS"; /** + * The extra for call log uri that was used to mark missed calls as read when dialer gets the + * notification on reboot. + */ + @FlaggedApi(Flags.FLAG_ADD_CALL_URI_FOR_MISSED_CALLS) + public static final String EXTRA_CALL_LOG_URI = + "android.telecom.extra.CALL_LOG_URI"; + + /** * Optional extra for incoming containing a long which specifies the time the * call was answered by user. This value is in milliseconds. * @hide @@ -2361,6 +2371,11 @@ public class TelecomManager { * <p> * <b>Note</b>: {@link android.app.Notification.CallStyle} notifications should be posted after * the call is placed in order for the notification to be non-dismissible. + * <p><b>Note</b>: Call Forwarding MMI codes can only be dialed by applications that are + * configured as the user defined default dialer or system dialer role. If a call containing a + * call forwarding MMI code is placed by an application that is not in one of these roles, the + * dialer will be launched with a UI showing the MMI code already populated so that the user can + * confirm the action before the call is placed. * @param address The address to make the call to. * @param extras Bundle of extras to use with the call. */ diff --git a/telephony/java/android/telephony/CarrierConfigManager.java b/telephony/java/android/telephony/CarrierConfigManager.java index 042b2a3de0a1..4250bd14da52 100644 --- a/telephony/java/android/telephony/CarrierConfigManager.java +++ b/telephony/java/android/telephony/CarrierConfigManager.java @@ -9692,6 +9692,7 @@ public class CarrierConfigManager { * * @see TelephonyManager#PURCHASE_PREMIUM_CAPABILITY_RESULT_USER_CANCELED * @see TelephonyManager#PURCHASE_PREMIUM_CAPABILITY_RESULT_TIMEOUT + * @see TelephonyManager#PURCHASE_PREMIUM_CAPABILITY_RESULT_USER_DISABLED */ public static final String KEY_PREMIUM_CAPABILITY_NOTIFICATION_BACKOFF_HYSTERESIS_TIME_MILLIS_LONG = diff --git a/telephony/java/android/telephony/TelephonyManager.java b/telephony/java/android/telephony/TelephonyManager.java index c0d6b301def0..e9ea5a7c2ce2 100644 --- a/telephony/java/android/telephony/TelephonyManager.java +++ b/telephony/java/android/telephony/TelephonyManager.java @@ -17483,9 +17483,8 @@ public class TelephonyManager { * {@link CarrierConfigManager * #KEY_PREMIUM_CAPABILITY_NOTIFICATION_BACKOFF_HYSTERESIS_TIME_MILLIS_LONG} * and return {@link #PURCHASE_PREMIUM_CAPABILITY_RESULT_THROTTLED}. - * - * @hide */ + @FlaggedApi(Flags.FLAG_SLICING_ADDITIONAL_ERROR_CODES) public static final int PURCHASE_PREMIUM_CAPABILITY_RESULT_USER_DISABLED = 16; /** diff --git a/telephony/java/android/telephony/data/ApnSetting.java b/telephony/java/android/telephony/data/ApnSetting.java index 11cbcb1c149d..cb7926ca0608 100644 --- a/telephony/java/android/telephony/data/ApnSetting.java +++ b/telephony/java/android/telephony/data/ApnSetting.java @@ -568,6 +568,7 @@ public class ApnSetting implements Parcelable { private final int mSkip464Xlat; private final boolean mAlwaysOn; private final @InfrastructureBitmask int mInfrastructureBitmask; + private final boolean mEsimBootstrapProvisioning; /** * Returns the default MTU (Maximum Transmission Unit) size in bytes of the IPv4 routes brought @@ -979,6 +980,18 @@ public class ApnSetting implements Parcelable { return mInfrastructureBitmask; } + /** + * Returns esim bootstrap provisioning flag for which the APN can be used on. For example, + * some APNs are only allowed to bring up network, when the device esim bootstrap provisioning + * is being activated. + * + * {@code true} if the APN is used for eSIM bootstrap provisioning, {@code false} otherwise. + * @hide + */ + public boolean isEsimBootstrapProvisioning() { + return mEsimBootstrapProvisioning; + } + private ApnSetting(Builder builder) { this.mEntryName = builder.mEntryName; this.mApnName = builder.mApnName; @@ -1016,6 +1029,7 @@ public class ApnSetting implements Parcelable { this.mSkip464Xlat = builder.mSkip464Xlat; this.mAlwaysOn = builder.mAlwaysOn; this.mInfrastructureBitmask = builder.mInfrastructureBitmask; + this.mEsimBootstrapProvisioning = builder.mEsimBootstrapProvisioning; } /** @@ -1097,6 +1111,8 @@ public class ApnSetting implements Parcelable { .setAlwaysOn(cursor.getInt(cursor.getColumnIndexOrThrow(Carriers.ALWAYS_ON)) == 1) .setInfrastructureBitmask(cursor.getInt(cursor.getColumnIndexOrThrow( Telephony.Carriers.INFRASTRUCTURE_BITMASK))) + .setEsimBootstrapProvisioning(cursor.getInt( + cursor.getColumnIndexOrThrow(Carriers.ESIM_BOOTSTRAP_PROVISIONING)) == 1) .buildWithoutCheck(); } @@ -1137,6 +1153,7 @@ public class ApnSetting implements Parcelable { .setSkip464Xlat(apn.mSkip464Xlat) .setAlwaysOn(apn.mAlwaysOn) .setInfrastructureBitmask(apn.mInfrastructureBitmask) + .setEsimBootstrapProvisioning(apn.mEsimBootstrapProvisioning) .buildWithoutCheck(); } @@ -1184,6 +1201,7 @@ public class ApnSetting implements Parcelable { sb.append(", ").append(mAlwaysOn); sb.append(", ").append(mInfrastructureBitmask); sb.append(", ").append(Objects.hash(mUser, mPassword)); + sb.append(", ").append(mEsimBootstrapProvisioning); return sb.toString(); } @@ -1247,7 +1265,7 @@ public class ApnSetting implements Parcelable { mProtocol, mRoamingProtocol, mMtuV4, mMtuV6, mCarrierEnabled, mNetworkTypeBitmask, mLingeringNetworkTypeBitmask, mProfileId, mPersistent, mMaxConns, mWaitTime, mMaxConnsTime, mMvnoType, mMvnoMatchData, mApnSetId, mCarrierId, mSkip464Xlat, - mAlwaysOn, mInfrastructureBitmask); + mAlwaysOn, mInfrastructureBitmask, mEsimBootstrapProvisioning); } @Override @@ -1289,7 +1307,8 @@ public class ApnSetting implements Parcelable { && mCarrierId == other.mCarrierId && mSkip464Xlat == other.mSkip464Xlat && mAlwaysOn == other.mAlwaysOn - && mInfrastructureBitmask == other.mInfrastructureBitmask; + && mInfrastructureBitmask == other.mInfrastructureBitmask + && Objects.equals(mEsimBootstrapProvisioning, other.mEsimBootstrapProvisioning); } /** @@ -1340,7 +1359,8 @@ public class ApnSetting implements Parcelable { && Objects.equals(mCarrierId, other.mCarrierId) && Objects.equals(mSkip464Xlat, other.mSkip464Xlat) && Objects.equals(mAlwaysOn, other.mAlwaysOn) - && Objects.equals(mInfrastructureBitmask, other.mInfrastructureBitmask); + && Objects.equals(mInfrastructureBitmask, other.mInfrastructureBitmask) + && Objects.equals(mEsimBootstrapProvisioning, other.mEsimBootstrapProvisioning); } /** @@ -1378,7 +1398,9 @@ public class ApnSetting implements Parcelable { && Objects.equals(this.mCarrierId, other.mCarrierId) && Objects.equals(this.mSkip464Xlat, other.mSkip464Xlat) && Objects.equals(this.mAlwaysOn, other.mAlwaysOn) - && Objects.equals(this.mInfrastructureBitmask, other.mInfrastructureBitmask); + && Objects.equals(this.mInfrastructureBitmask, other.mInfrastructureBitmask) + && Objects.equals(this.mEsimBootstrapProvisioning, + other.mEsimBootstrapProvisioning); } // Equal or one is null. @@ -1451,6 +1473,7 @@ public class ApnSetting implements Parcelable { apnValue.put(Telephony.Carriers.SKIP_464XLAT, mSkip464Xlat); apnValue.put(Telephony.Carriers.ALWAYS_ON, mAlwaysOn); apnValue.put(Telephony.Carriers.INFRASTRUCTURE_BITMASK, mInfrastructureBitmask); + apnValue.put(Carriers.ESIM_BOOTSTRAP_PROVISIONING, mEsimBootstrapProvisioning); return apnValue; } @@ -1724,6 +1747,7 @@ public class ApnSetting implements Parcelable { dest.writeInt(mSkip464Xlat); dest.writeBoolean(mAlwaysOn); dest.writeInt(mInfrastructureBitmask); + dest.writeBoolean(mEsimBootstrapProvisioning); } private static ApnSetting readFromParcel(Parcel in) { @@ -1760,6 +1784,7 @@ public class ApnSetting implements Parcelable { .setSkip464Xlat(in.readInt()) .setAlwaysOn(in.readBoolean()) .setInfrastructureBitmask(in.readInt()) + .setEsimBootstrapProvisioning(in.readBoolean()) .buildWithoutCheck(); } @@ -1842,6 +1867,7 @@ public class ApnSetting implements Parcelable { private int mSkip464Xlat = Carriers.SKIP_464XLAT_DEFAULT; private boolean mAlwaysOn; private int mInfrastructureBitmask = INFRASTRUCTURE_CELLULAR; + private boolean mEsimBootstrapProvisioning; /** * Default constructor for Builder. @@ -2280,6 +2306,19 @@ public class ApnSetting implements Parcelable { } /** + * Sets esim bootstrap provisioning flag + * + * @param esimBootstrapProvisioning {@code true} if the APN is used for eSIM bootstrap + * provisioning, {@code false} otherwise. + * @hide + */ + @NonNull + public Builder setEsimBootstrapProvisioning(boolean esimBootstrapProvisioning) { + this.mEsimBootstrapProvisioning = esimBootstrapProvisioning; + return this; + } + + /** * Builds {@link ApnSetting} from this builder. * * @return {@code null} if {@link #setApnName(String)} or {@link #setEntryName(String)} diff --git a/tests/FlickerTests/Android.bp b/tests/FlickerTests/Android.bp index f4f2be642e81..3d49d81a0f5a 100644 --- a/tests/FlickerTests/Android.bp +++ b/tests/FlickerTests/Android.bp @@ -166,22 +166,6 @@ android_test { } android_test { - name: "FlickerTestsAppLaunch", - defaults: ["FlickerTestsDefault"], - additional_manifests: ["manifests/AndroidManifestAppLaunch.xml"], - package_name: "com.android.server.wm.flicker.launch", - instrumentation_target_package: "com.android.server.wm.flicker.launch", - srcs: [ - ":FlickerTestsBase-src", - ":FlickerTestsAppLaunchCommon-src", - ":FlickerTestsAppLaunch2-src", - ], - exclude_srcs: [ - ":FlickerTestsActivityEmbedding-src", - ], -} - -android_test { name: "FlickerTestsAppLaunch1", defaults: ["FlickerTestsDefault"], additional_manifests: ["manifests/AndroidManifestAppLaunch.xml"], diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/launch/common/OpenTransferSplashscreenAppFromLauncherTransition.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/launch/common/OpenTransferSplashscreenAppFromLauncherTransition.kt index 2e9620bb13c5..17f749079da6 100644 --- a/tests/FlickerTests/src/com/android/server/wm/flicker/launch/common/OpenTransferSplashscreenAppFromLauncherTransition.kt +++ b/tests/FlickerTests/src/com/android/server/wm/flicker/launch/common/OpenTransferSplashscreenAppFromLauncherTransition.kt @@ -24,6 +24,7 @@ import android.tools.device.flicker.legacy.LegacyFlickerTestFactory import androidx.test.filters.FlakyTest import androidx.test.filters.RequiresDevice import com.android.server.wm.flicker.helpers.TransferSplashscreenAppHelper +import com.android.server.wm.flicker.replacesLayer import org.junit.FixMethodOrder import org.junit.Test import org.junit.runner.RunWith @@ -119,7 +120,13 @@ class OpenTransferSplashscreenAppFromLauncherTransition(flicker: LegacyFlickerTe @FlakyTest(bugId = 240916028) @Test override fun appLayerReplacesLauncher() { - super.appLayerReplacesLauncher() + flicker.replacesLayer( + ComponentNameMatcher.LAUNCHER, + testApp, + ignoreEntriesWithRotationLayer = true, + ignoreSnapshot = true, + ignoreSplashscreen = false + ) } @FlakyTest(bugId = 240916028) diff --git a/tools/lint/global/checks/src/main/java/com/google/android/lint/AndroidGlobalIssueRegistry.kt b/tools/lint/global/checks/src/main/java/com/google/android/lint/AndroidGlobalIssueRegistry.kt index a20266a9b140..28eab8f62e74 100644 --- a/tools/lint/global/checks/src/main/java/com/google/android/lint/AndroidGlobalIssueRegistry.kt +++ b/tools/lint/global/checks/src/main/java/com/google/android/lint/AndroidGlobalIssueRegistry.kt @@ -20,7 +20,6 @@ import com.android.tools.lint.client.api.IssueRegistry import com.android.tools.lint.client.api.Vendor import com.android.tools.lint.detector.api.CURRENT_API import com.google.android.lint.aidl.EnforcePermissionDetector -import com.google.android.lint.aidl.EnforcePermissionHelperDetector import com.google.android.lint.aidl.SimpleManualPermissionEnforcementDetector import com.google.auto.service.AutoService @@ -30,7 +29,8 @@ class AndroidGlobalIssueRegistry : IssueRegistry() { override val issues = listOf( EnforcePermissionDetector.ISSUE_MISSING_ENFORCE_PERMISSION, EnforcePermissionDetector.ISSUE_MISMATCHING_ENFORCE_PERMISSION, - EnforcePermissionHelperDetector.ISSUE_ENFORCE_PERMISSION_HELPER, + EnforcePermissionDetector.ISSUE_ENFORCE_PERMISSION_HELPER, + EnforcePermissionDetector.ISSUE_MISUSING_ENFORCE_PERMISSION, SimpleManualPermissionEnforcementDetector.ISSUE_SIMPLE_MANUAL_PERMISSION_ENFORCEMENT, ) @@ -45,4 +45,4 @@ class AndroidGlobalIssueRegistry : IssueRegistry() { feedbackUrl = "http://b/issues/new?component=315013", contact = "repsonsible-apis@google.com" ) -}
\ No newline at end of file +} diff --git a/tools/lint/global/checks/src/main/java/com/google/android/lint/aidl/EnforcePermissionDetector.kt b/tools/lint/global/checks/src/main/java/com/google/android/lint/aidl/EnforcePermissionDetector.kt index 3a95df9b2773..dcd94f1bcba4 100644 --- a/tools/lint/global/checks/src/main/java/com/google/android/lint/aidl/EnforcePermissionDetector.kt +++ b/tools/lint/global/checks/src/main/java/com/google/android/lint/aidl/EnforcePermissionDetector.kt @@ -30,31 +30,34 @@ import com.android.tools.lint.detector.api.JavaContext import com.android.tools.lint.detector.api.Scope import com.android.tools.lint.detector.api.Severity import com.android.tools.lint.detector.api.SourceCodeScanner +import com.google.android.lint.findCallExpression import com.intellij.psi.PsiAnnotation import com.intellij.psi.PsiArrayInitializerMemberValue import com.intellij.psi.PsiClass import com.intellij.psi.PsiElement import com.intellij.psi.PsiMethod -import org.jetbrains.uast.UAnnotation +import org.jetbrains.uast.UBlockExpression +import org.jetbrains.uast.UDeclarationsExpression import org.jetbrains.uast.UElement +import org.jetbrains.uast.UExpression import org.jetbrains.uast.UMethod -import org.jetbrains.uast.toUElement +import org.jetbrains.uast.skipParenthesizedExprDown import java.util.EnumSet /** - * Lint Detector that ensures that any method overriding a method annotated - * with @EnforcePermission is also annotated with the exact same annotation. - * The intent is to surface the effective permission checks to the service - * implementations. + * Lint Detector that ensures consistency when using the @EnforcePermission + * annotation. Multiple verifications are implemented: * - * This is done with 2 mechanisms: * 1. Visit any annotation usage, to ensure that any derived class will have - * the correct annotation on each methods. This is for the top to bottom - * propagation. - * 2. Visit any annotation, to ensure that if a method is annotated, it has + * the correct annotation on each methods. Even if the subclass does not + * have the annotation, visitAnnotationUsage will be called which allows us + * to capture the issue. + * 2. Visit any method, to ensure that if a method is annotated, it has * its ancestor also annotated. This is to avoid having an annotation on a * Java method without the corresponding annotation on the AIDL interface. + * 3. When annotated, ensures that the first instruction is to call the helper + * method (or the parent helper). */ class EnforcePermissionDetector : Detector(), SourceCodeScanner { @@ -62,9 +65,8 @@ class EnforcePermissionDetector : Detector(), SourceCodeScanner { return listOf(ANNOTATION_ENFORCE_PERMISSION) } - override fun getApplicableUastTypes(): List<Class<out UElement>> { - return listOf(UAnnotation::class.java) - } + override fun getApplicableUastTypes(): List<Class<out UElement?>> = + listOf(UMethod::class.java) private fun annotationValueGetChildren(elem: PsiElement): Array<PsiElement> { if (elem is PsiArrayInitializerMemberValue) @@ -129,11 +131,6 @@ class EnforcePermissionDetector : Detector(), SourceCodeScanner { overriddenMethod: PsiMethod, checkEquivalence: Boolean = true ) { - // If method is not from a Stub subclass, this method shouldn't use @EP at all. - // This is handled by EnforcePermissionHelperDetector. - if (!isContainedInSubclassOfStub(context, overridingMethod.toUElement() as? UMethod)) { - return - } val overridingAnnotation = overridingMethod.getAnnotation(ANNOTATION_ENFORCE_PERMISSION) val overriddenAnnotation = overriddenMethod.getAnnotation(ANNOTATION_ENFORCE_PERMISSION) val location = context.getLocation(element) @@ -169,40 +166,102 @@ class EnforcePermissionDetector : Detector(), SourceCodeScanner { ) { if (usageInfo.type == AnnotationUsageType.METHOD_OVERRIDE && annotationInfo.origin == AnnotationOrigin.METHOD) { + /* Ignore implementations that are not a sub-class of Stub (i.e., Proxy). */ + val uMethod = element as? UMethod ?: return + if (!isContainedInSubclassOfStub(context, uMethod)) { + return + } val overridingMethod = element.sourcePsi as PsiMethod val overriddenMethod = usageInfo.referenced as PsiMethod compareMethods(context, element, overridingMethod, overriddenMethod) } } - override fun createUastHandler(context: JavaContext): UElementHandler { - return object : UElementHandler() { - override fun visitAnnotation(node: UAnnotation) { - if (node.qualifiedName != ANNOTATION_ENFORCE_PERMISSION) { - return - } - val method = node.uastParent as? UMethod ?: return - val overridingMethod = method as PsiMethod - val parents = overridingMethod.findSuperMethods() - for (overriddenMethod in parents) { - // The equivalence check can be skipped, if both methods are - // annotated, it will be verified by visitAnnotationUsage. - compareMethods(context, method, overridingMethod, - overriddenMethod, checkEquivalence = false) - } + override fun createUastHandler(context: JavaContext): UElementHandler = AidlStubHandler(context) + + private inner class AidlStubHandler(val context: JavaContext) : UElementHandler() { + override fun visitMethod(node: UMethod) { + if (context.evaluator.isAbstract(node)) return + if (!node.hasAnnotation(ANNOTATION_ENFORCE_PERMISSION)) return + + if (!isContainedInSubclassOfStub(context, node)) { + context.report( + ISSUE_MISUSING_ENFORCE_PERMISSION, + node, + context.getLocation(node), + "The class of ${node.name} does not inherit from an AIDL generated Stub class" + ) + return + } + + /* Check that we are connected to the super class */ + val overridingMethod = node as PsiMethod + val parents = overridingMethod.findSuperMethods() + for (overriddenMethod in parents) { + // The equivalence check can be skipped, if both methods are + // annotated, it will be verified by visitAnnotationUsage. + compareMethods(context, node, overridingMethod, + overriddenMethod, checkEquivalence = false) + } + + /* Check that the helper is called as a first instruction */ + val targetExpression = getHelperMethodCallSourceString(node) + val message = + "Method must start with $targetExpression or super.${node.name}(), if applicable" + + val firstExpression = (node.uastBody as? UBlockExpression) + ?.expressions?.firstOrNull() + + if (firstExpression == null) { + context.report( + ISSUE_ENFORCE_PERMISSION_HELPER, + context.getLocation(node), + message, + ) + return + } + + val firstExpressionSource = firstExpression.skipParenthesizedExprDown() + .asSourceString() + .filterNot(Char::isWhitespace) + + if (firstExpressionSource != targetExpression && + firstExpressionSource != "super.$targetExpression") { + // calling super.<methodName>() is also legal + val directSuper = context.evaluator.getSuperMethod(node) + val firstCall = findCallExpression(firstExpression)?.resolve() + if (directSuper != null && firstCall == directSuper) return + + val locationTarget = getLocationTarget(firstExpression) + val expressionLocation = context.getLocation(locationTarget) + + context.report( + ISSUE_ENFORCE_PERMISSION_HELPER, + context.getLocation(node), + message, + getHelperMethodFix(node, expressionLocation), + ) } } } companion object { + + private const val HELPER_SUFFIX = "_enforcePermission" + val EXPLANATION = """ - The @EnforcePermission annotation is used to indicate that the underlying binder code - has already verified the caller's permissions before calling the appropriate method. The - verification code is usually generated by the AIDL compiler, which also takes care of - annotating the generated Java code. + The @EnforcePermission annotation is used to delegate the verification of the caller's + permissions to a generated AIDL method. In order to surface that information to platform developers, the same annotation must be used on the implementation class or methods. + + The @EnforcePermission annotation can only be used on methods whose class extends from + the Stub class generated by the AIDL compiler. When @EnforcePermission is applied, the + AIDL compiler generates a Stub method to do the permission check called yourMethodName$HELPER_SUFFIX. + + yourMethodName$HELPER_SUFFIX must be executed before any other operation. To do that, you can + either call it directly, or call it indirectly via super.yourMethodName(). """ val ISSUE_MISSING_ENFORCE_PERMISSION: Issue = Issue.create( @@ -230,5 +289,44 @@ class EnforcePermissionDetector : Detector(), SourceCodeScanner { EnumSet.of(Scope.JAVA_FILE, Scope.TEST_SOURCES) ) ) + + val ISSUE_ENFORCE_PERMISSION_HELPER: Issue = Issue.create( + id = "MissingEnforcePermissionHelper", + briefDescription = """Missing permission-enforcing method call in AIDL method + |annotated with @EnforcePermission""".trimMargin(), + explanation = EXPLANATION, + category = Category.SECURITY, + priority = 6, + severity = Severity.ERROR, + implementation = Implementation( + EnforcePermissionDetector::class.java, + EnumSet.of(Scope.JAVA_FILE, Scope.TEST_SOURCES) + ) + ) + + val ISSUE_MISUSING_ENFORCE_PERMISSION: Issue = Issue.create( + id = "MisusingEnforcePermissionAnnotation", + briefDescription = "@EnforcePermission cannot be used here", + explanation = EXPLANATION, + category = Category.SECURITY, + priority = 6, + severity = Severity.ERROR, + implementation = Implementation( + EnforcePermissionDetector::class.java, + EnumSet.of(Scope.JAVA_FILE, Scope.TEST_SOURCES) + ) + ) + + /** + * handles an edge case with UDeclarationsExpression, where sourcePsi is null, + * resulting in an incorrect Location if used directly + */ + private fun getLocationTarget(firstExpression: UExpression): PsiElement? { + if (firstExpression.sourcePsi != null) return firstExpression.sourcePsi + if (firstExpression is UDeclarationsExpression) { + return firstExpression.declarations.firstOrNull()?.sourcePsi + } + return null + } } } diff --git a/tools/lint/global/checks/src/main/java/com/google/android/lint/aidl/EnforcePermissionHelperDetector.kt b/tools/lint/global/checks/src/main/java/com/google/android/lint/aidl/EnforcePermissionHelperDetector.kt deleted file mode 100644 index 758de4dfccf8..000000000000 --- a/tools/lint/global/checks/src/main/java/com/google/android/lint/aidl/EnforcePermissionHelperDetector.kt +++ /dev/null @@ -1,151 +0,0 @@ -/* - * Copyright (C) 2022 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.google.android.lint.aidl - -import com.android.tools.lint.client.api.UElementHandler -import com.android.tools.lint.detector.api.Category -import com.android.tools.lint.detector.api.Detector -import com.android.tools.lint.detector.api.Implementation -import com.android.tools.lint.detector.api.Issue -import com.android.tools.lint.detector.api.JavaContext -import com.android.tools.lint.detector.api.Scope -import com.android.tools.lint.detector.api.Severity -import com.android.tools.lint.detector.api.SourceCodeScanner -import com.google.android.lint.findCallExpression -import com.intellij.psi.PsiElement -import org.jetbrains.uast.UBlockExpression -import org.jetbrains.uast.UDeclarationsExpression -import org.jetbrains.uast.UElement -import org.jetbrains.uast.UExpression -import org.jetbrains.uast.UMethod -import org.jetbrains.uast.skipParenthesizedExprDown - -import java.util.EnumSet - -class EnforcePermissionHelperDetector : Detector(), SourceCodeScanner { - override fun getApplicableUastTypes(): List<Class<out UElement?>> = - listOf(UMethod::class.java) - - override fun createUastHandler(context: JavaContext): UElementHandler = AidlStubHandler(context) - - private inner class AidlStubHandler(val context: JavaContext) : UElementHandler() { - override fun visitMethod(node: UMethod) { - if (context.evaluator.isAbstract(node)) return - if (!node.hasAnnotation(ANNOTATION_ENFORCE_PERMISSION)) return - - if (!isContainedInSubclassOfStub(context, node)) { - context.report( - ISSUE_MISUSING_ENFORCE_PERMISSION, - node, - context.getLocation(node), - "The class of ${node.name} does not inherit from an AIDL generated Stub class" - ) - return - } - - val targetExpression = getHelperMethodCallSourceString(node) - val message = - "Method must start with $targetExpression or super.${node.name}(), if applicable" - - val firstExpression = (node.uastBody as? UBlockExpression) - ?.expressions?.firstOrNull() - - if (firstExpression == null) { - context.report( - ISSUE_ENFORCE_PERMISSION_HELPER, - context.getLocation(node), - message, - ) - return - } - - val firstExpressionSource = firstExpression.skipParenthesizedExprDown() - .asSourceString() - .filterNot(Char::isWhitespace) - - if (firstExpressionSource != targetExpression && - firstExpressionSource != "super.$targetExpression") { - // calling super.<methodName>() is also legal - val directSuper = context.evaluator.getSuperMethod(node) - val firstCall = findCallExpression(firstExpression)?.resolve() - if (directSuper != null && firstCall == directSuper) return - - val locationTarget = getLocationTarget(firstExpression) - val expressionLocation = context.getLocation(locationTarget) - - context.report( - ISSUE_ENFORCE_PERMISSION_HELPER, - context.getLocation(node), - message, - getHelperMethodFix(node, expressionLocation), - ) - } - } - } - - companion object { - private const val HELPER_SUFFIX = "_enforcePermission" - - private const val EXPLANATION = """ - The @EnforcePermission annotation can only be used on methods whose class extends from - the Stub class generated by the AIDL compiler. When @EnforcePermission is applied, the - AIDL compiler generates a Stub method to do the permission check called yourMethodName$HELPER_SUFFIX. - - yourMethodName$HELPER_SUFFIX must be executed before any other operation. To do that, you can - either call it directly, or call it indirectly via super.yourMethodName(). - """ - - val ISSUE_ENFORCE_PERMISSION_HELPER: Issue = Issue.create( - id = "MissingEnforcePermissionHelper", - briefDescription = """Missing permission-enforcing method call in AIDL method - |annotated with @EnforcePermission""".trimMargin(), - explanation = EXPLANATION, - category = Category.SECURITY, - priority = 6, - severity = Severity.ERROR, - implementation = Implementation( - EnforcePermissionHelperDetector::class.java, - EnumSet.of(Scope.JAVA_FILE, Scope.TEST_SOURCES) - ) - ) - - val ISSUE_MISUSING_ENFORCE_PERMISSION: Issue = Issue.create( - id = "MisusingEnforcePermissionAnnotation", - briefDescription = "@EnforcePermission cannot be used here", - explanation = EXPLANATION, - category = Category.SECURITY, - priority = 6, - severity = Severity.ERROR, - implementation = Implementation( - EnforcePermissionHelperDetector::class.java, - EnumSet.of(Scope.JAVA_FILE, Scope.TEST_SOURCES) - ) - ) - - /** - * handles an edge case with UDeclarationsExpression, where sourcePsi is null, - * resulting in an incorrect Location if used directly - */ - private fun getLocationTarget(firstExpression: UExpression): PsiElement? { - if (firstExpression.sourcePsi != null) return firstExpression.sourcePsi - if (firstExpression is UDeclarationsExpression) { - return firstExpression.declarations.firstOrNull()?.sourcePsi - } - return null - } - } -} diff --git a/tools/lint/global/checks/src/test/java/com/google/android/lint/aidl/EnforcePermissionHelperDetectorCodegenTest.kt b/tools/lint/global/checks/src/test/java/com/google/android/lint/aidl/EnforcePermissionHelperDetectorCodegenTest.kt index 5a63bb4084d2..3ef02f865355 100644 --- a/tools/lint/global/checks/src/test/java/com/google/android/lint/aidl/EnforcePermissionHelperDetectorCodegenTest.kt +++ b/tools/lint/global/checks/src/test/java/com/google/android/lint/aidl/EnforcePermissionHelperDetectorCodegenTest.kt @@ -25,10 +25,10 @@ import com.android.tools.lint.detector.api.Issue @Suppress("UnstableApiUsage") class EnforcePermissionHelperDetectorCodegenTest : LintDetectorTest() { - override fun getDetector(): Detector = EnforcePermissionHelperDetector() + override fun getDetector(): Detector = EnforcePermissionDetector() override fun getIssues(): List<Issue> = listOf( - EnforcePermissionHelperDetector.ISSUE_ENFORCE_PERMISSION_HELPER + EnforcePermissionDetector.ISSUE_ENFORCE_PERMISSION_HELPER ) override fun lint(): TestLintTask = super.lint().allowMissingSdk(true) diff --git a/tools/lint/global/checks/src/test/java/com/google/android/lint/aidl/EnforcePermissionHelperDetectorTest.kt b/tools/lint/global/checks/src/test/java/com/google/android/lint/aidl/EnforcePermissionHelperDetectorTest.kt index 10a6e1da91dc..64e2bfbad7bb 100644 --- a/tools/lint/global/checks/src/test/java/com/google/android/lint/aidl/EnforcePermissionHelperDetectorTest.kt +++ b/tools/lint/global/checks/src/test/java/com/google/android/lint/aidl/EnforcePermissionHelperDetectorTest.kt @@ -20,10 +20,10 @@ import com.android.tools.lint.checks.infrastructure.LintDetectorTest import com.android.tools.lint.checks.infrastructure.TestLintTask class EnforcePermissionHelperDetectorTest : LintDetectorTest() { - override fun getDetector() = EnforcePermissionHelperDetector() + override fun getDetector() = EnforcePermissionDetector() override fun getIssues() = listOf( - EnforcePermissionHelperDetector.ISSUE_ENFORCE_PERMISSION_HELPER, - EnforcePermissionHelperDetector.ISSUE_MISUSING_ENFORCE_PERMISSION + EnforcePermissionDetector.ISSUE_ENFORCE_PERMISSION_HELPER, + EnforcePermissionDetector.ISSUE_MISUSING_ENFORCE_PERMISSION ) override fun lint(): TestLintTask = super.lint().allowMissingSdk() |