diff options
397 files changed, 6838 insertions, 1896 deletions
diff --git a/AconfigFlags.bp b/AconfigFlags.bp index 2e7d0ec9c89a..372ae6da4959 100644 --- a/AconfigFlags.bp +++ b/AconfigFlags.bp @@ -58,6 +58,7 @@ aconfig_srcjars = [ ":android.service.autofill.flags-aconfig-java{.generated_srcjars}", ":com.android.net.flags-aconfig-java{.generated_srcjars}", ":device_policy_aconfig_flags_lib{.generated_srcjars}", + ":surfaceflinger_flags_java_lib{.generated_srcjars}", ] filegroup { @@ -482,7 +483,7 @@ java_aconfig_library { defaults: ["framework-minus-apex-aconfig-java-defaults"], } -// Activity Manager +// android.app aconfig_declarations { name: "android.app.flags-aconfig", package: "android.app", @@ -641,3 +642,10 @@ java_aconfig_library { aconfig_declarations: "android.app.smartspace.flags-aconfig", defaults: ["framework-minus-apex-aconfig-java-defaults"], } + +// SurfaceFlinger +java_aconfig_library { + name: "surfaceflinger_flags_java_lib", + aconfig_declarations: "surfaceflinger_flags", + defaults: ["framework-minus-apex-aconfig-java-defaults"], +} diff --git a/Android.bp b/Android.bp index 49256ddb5cd4..8c4d76919568 100644 --- a/Android.bp +++ b/Android.bp @@ -745,90 +745,36 @@ stubs_defaults { // non_updatable_modules list in frameworks/base/api/api.go java_defaults { name: "framework-non-updatable-unbundled-defaults", - defaults: ["framework-non-updatable-lint-defaults"], - - sdk_version: "core_platform", - - // Api scope settings + defaults: [ + "framework-non-updatable-lint-defaults", + "non-updatable-framework-module-defaults", + ], public: { - enabled: true, - sdk_version: "module_current", libs: ["android_module_lib_stubs_current"], }, system: { - enabled: true, - sdk_version: "module_current", libs: ["android_module_lib_stubs_current"], }, module_lib: { - enabled: true, - sdk_version: "module_current", libs: ["android_module_lib_stubs_current"], }, test: { - enabled: true, - sdk_version: "test_frameworks_core_current", libs: ["android_test_frameworks_core_stubs_current"], }, - - stub_only_libs: [ - "framework-protos", - ], - impl_only_libs: [ - "framework-minus-apex-headers", // full access to framework-minus-apex including hidden API - "framework-annotations-lib", - ], - visibility: ["//visibility:public"], - stubs_library_visibility: ["//visibility:public"], - stubs_source_visibility: ["//visibility:private"], - impl_library_visibility: [ - ":__pkg__", - "//frameworks/base", - "//frameworks/base/api", // For framework-all - ], - defaults_visibility: [ - "//frameworks/base/location", - ], - plugins: [ - "error_prone_android_framework", - ], + 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"], - - // Use the source of annotations that affect metalava doc generation, since - // the relevant generation instructions are themselves in javadoc, which is - // not present in class files. - api_srcs: [":framework-metalava-annotations"], - - // Framework modules are not generally shared libraries, i.e. they are not - // intended, and must not be allowed, to be used in a <uses-library> manifest - // entry. - shared_library: false, - - // Prevent dependencies that do not specify an sdk_version from accessing the - // implementation library by default and force them to use stubs instead. - default_to_stubs: true, - - // Subdirectory for the artifacts that are copied to the dist directory - dist_group: "android", - - droiddoc_options: [ - "--error UnhiddenSystemApi " + - "--hide CallbackInterface " + - "--hide HiddenTypedefConstant " + - "--hide RequiresPermission " + - "--enhance-documentation " + - "--hide-package com.android.server ", - ], - - annotations_enabled: true, } build = [ diff --git a/BAL_OWNERS b/BAL_OWNERS new file mode 100644 index 000000000000..d56a1d4634df --- /dev/null +++ b/BAL_OWNERS @@ -0,0 +1,5 @@ +brufino@google.com +achim@google.com +topjohnwu@google.com +lus@google.com + diff --git a/apex/jobscheduler/service/java/com/android/server/AppStateTrackerImpl.java b/apex/jobscheduler/service/java/com/android/server/AppStateTrackerImpl.java index e08200b055d8..5fc77451e832 100644 --- a/apex/jobscheduler/service/java/com/android/server/AppStateTrackerImpl.java +++ b/apex/jobscheduler/service/java/com/android/server/AppStateTrackerImpl.java @@ -23,6 +23,7 @@ import android.app.AppOpsManager; import android.app.AppOpsManager.PackageOps; import android.app.IActivityManager; import android.app.usage.UsageStatsManager; +import android.content.AttributionSource; import android.content.BroadcastReceiver; import android.content.Context; import android.content.Intent; @@ -746,8 +747,10 @@ public class AppStateTrackerImpl implements AppStateTracker { public void opChanged(int op, int uid, String packageName) throws RemoteException { boolean restricted = false; try { - restricted = mAppOpsService.checkOperation(TARGET_OP, - uid, packageName) != AppOpsManager.MODE_ALLOWED; + final AttributionSource attributionSource = + new AttributionSource.Builder(uid).setPackageName(packageName).build(); + restricted = mAppOpsService.checkOperationWithState(TARGET_OP, + attributionSource.asState()) != AppOpsManager.MODE_ALLOWED; } catch (RemoteException e) { // Shouldn't happen } 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/tare/InternalResourceService.java b/apex/jobscheduler/service/java/com/android/server/tare/InternalResourceService.java index b8397d2cd1b4..95f901c4a365 100644 --- a/apex/jobscheduler/service/java/com/android/server/tare/InternalResourceService.java +++ b/apex/jobscheduler/service/java/com/android/server/tare/InternalResourceService.java @@ -38,6 +38,7 @@ import android.app.tare.EconomyManager; import android.app.tare.IEconomyManager; import android.app.usage.UsageEvents; import android.app.usage.UsageStatsManagerInternal; +import android.content.AttributionSource; import android.content.BroadcastReceiver; import android.content.ContentResolver; import android.content.Context; @@ -230,8 +231,11 @@ public class InternalResourceService extends SystemService { public void opChanged(int op, int uid, String packageName) { boolean restricted = false; try { - restricted = mAppOpsService.checkOperation( - AppOpsManager.OP_RUN_ANY_IN_BACKGROUND, uid, packageName) + final AttributionSource attributionSource = new AttributionSource.Builder(uid) + .setPackageName(packageName) + .build(); + restricted = mAppOpsService.checkOperationWithState( + AppOpsManager.OP_RUN_ANY_IN_BACKGROUND, attributionSource.asState()) != AppOpsManager.MODE_ALLOWED; } catch (RemoteException e) { // Shouldn't happen diff --git a/core/api/current.txt b/core/api/current.txt index fdb4133743cb..7e3da2279311 100644 --- a/core/api/current.txt +++ b/core/api/current.txt @@ -11989,22 +11989,22 @@ package android.content.pm { method public final int compare(android.content.pm.ApplicationInfo, android.content.pm.ApplicationInfo); } - @FlaggedApi("android.content.pm.archiving") public final class ArchivedActivity { - ctor public ArchivedActivity(@NonNull CharSequence, @NonNull android.content.ComponentName); + @FlaggedApi("android.content.pm.archiving") public final class ArchivedActivityInfo { + ctor public ArchivedActivityInfo(@NonNull CharSequence, @NonNull android.content.ComponentName); method @NonNull public android.content.ComponentName getComponentName(); method @Nullable public android.graphics.drawable.Drawable getIcon(); method @NonNull public CharSequence getLabel(); method @Nullable public android.graphics.drawable.Drawable getMonochromeIcon(); - method @NonNull public android.content.pm.ArchivedActivity setComponentName(@NonNull android.content.ComponentName); - method @NonNull public android.content.pm.ArchivedActivity setIcon(@NonNull android.graphics.drawable.Drawable); - method @NonNull public android.content.pm.ArchivedActivity setLabel(@NonNull CharSequence); - method @NonNull public android.content.pm.ArchivedActivity setMonochromeIcon(@NonNull android.graphics.drawable.Drawable); + method @NonNull public android.content.pm.ArchivedActivityInfo setComponentName(@NonNull android.content.ComponentName); + method @NonNull public android.content.pm.ArchivedActivityInfo setIcon(@NonNull android.graphics.drawable.Drawable); + method @NonNull public android.content.pm.ArchivedActivityInfo setLabel(@NonNull CharSequence); + method @NonNull public android.content.pm.ArchivedActivityInfo setMonochromeIcon(@NonNull android.graphics.drawable.Drawable); } - @FlaggedApi("android.content.pm.archiving") public final class ArchivedPackage { - ctor public ArchivedPackage(@NonNull String, @NonNull android.content.pm.SigningInfo, @NonNull java.util.List<android.content.pm.ArchivedActivity>); + @FlaggedApi("android.content.pm.archiving") public final class ArchivedPackageInfo { + ctor public ArchivedPackageInfo(@NonNull String, @NonNull android.content.pm.SigningInfo, @NonNull java.util.List<android.content.pm.ArchivedActivityInfo>); method @Nullable public String getDefaultToDeviceProtectedStorage(); - method @NonNull public java.util.List<android.content.pm.ArchivedActivity> getLauncherActivities(); + method @NonNull public java.util.List<android.content.pm.ArchivedActivityInfo> getLauncherActivities(); method @NonNull public String getPackageName(); method @Nullable public String getRequestLegacyExternalStorage(); method @NonNull public android.content.pm.SigningInfo getSigningInfo(); @@ -12012,15 +12012,15 @@ package android.content.pm { method @Nullable public String getUserDataFragile(); method public int getVersionCode(); method public int getVersionCodeMajor(); - method @NonNull public android.content.pm.ArchivedPackage setDefaultToDeviceProtectedStorage(@NonNull String); - method @NonNull public android.content.pm.ArchivedPackage setLauncherActivities(@NonNull java.util.List<android.content.pm.ArchivedActivity>); - method @NonNull public android.content.pm.ArchivedPackage setPackageName(@NonNull String); - method @NonNull public android.content.pm.ArchivedPackage setRequestLegacyExternalStorage(@NonNull String); - method @NonNull public android.content.pm.ArchivedPackage setSigningInfo(@NonNull android.content.pm.SigningInfo); - method @NonNull public android.content.pm.ArchivedPackage setTargetSdkVersion(int); - method @NonNull public android.content.pm.ArchivedPackage setUserDataFragile(@NonNull String); - method @NonNull public android.content.pm.ArchivedPackage setVersionCode(int); - method @NonNull public android.content.pm.ArchivedPackage setVersionCodeMajor(int); + method @NonNull public android.content.pm.ArchivedPackageInfo setDefaultToDeviceProtectedStorage(@NonNull String); + method @NonNull public android.content.pm.ArchivedPackageInfo setLauncherActivities(@NonNull java.util.List<android.content.pm.ArchivedActivityInfo>); + method @NonNull public android.content.pm.ArchivedPackageInfo setPackageName(@NonNull String); + method @NonNull public android.content.pm.ArchivedPackageInfo setRequestLegacyExternalStorage(@NonNull String); + method @NonNull public android.content.pm.ArchivedPackageInfo setSigningInfo(@NonNull android.content.pm.SigningInfo); + method @NonNull public android.content.pm.ArchivedPackageInfo setTargetSdkVersion(int); + method @NonNull public android.content.pm.ArchivedPackageInfo setUserDataFragile(@NonNull String); + method @NonNull public android.content.pm.ArchivedPackageInfo setVersionCode(int); + method @NonNull public android.content.pm.ArchivedPackageInfo setVersionCodeMajor(int); } public final class Attribution implements android.os.Parcelable { @@ -12355,7 +12355,7 @@ package android.content.pm { method @Nullable public android.content.pm.PackageInstaller.SessionInfo getSessionInfo(int); method @NonNull public java.util.List<android.content.pm.PackageInstaller.SessionInfo> getStagedSessions(); method @RequiresPermission(allOf={android.Manifest.permission.INSTALL_PACKAGES, "com.android.permission.INSTALL_EXISTING_PACKAGES"}) public void installExistingPackage(@NonNull String, int, @Nullable android.content.IntentSender); - method @FlaggedApi("android.content.pm.archiving") @RequiresPermission(android.Manifest.permission.INSTALL_PACKAGES) public void installPackageArchived(@NonNull android.content.pm.ArchivedPackage, @NonNull android.content.pm.PackageInstaller.SessionParams, @NonNull android.content.IntentSender); + method @FlaggedApi("android.content.pm.archiving") @RequiresPermission(android.Manifest.permission.INSTALL_PACKAGES) public void installPackageArchived(@NonNull android.content.pm.ArchivedPackageInfo, @NonNull android.content.pm.PackageInstaller.SessionParams, @NonNull android.content.IntentSender); method @NonNull public android.content.pm.PackageInstaller.Session openSession(int) throws java.io.IOException; method public void registerSessionCallback(@NonNull android.content.pm.PackageInstaller.SessionCallback); method public void registerSessionCallback(@NonNull android.content.pm.PackageInstaller.SessionCallback, @NonNull android.os.Handler); @@ -12637,7 +12637,7 @@ package android.content.pm { method @NonNull public abstract CharSequence getApplicationLabel(@NonNull android.content.pm.ApplicationInfo); method @Nullable public abstract android.graphics.drawable.Drawable getApplicationLogo(@NonNull android.content.pm.ApplicationInfo); method @Nullable public abstract android.graphics.drawable.Drawable getApplicationLogo(@NonNull String) throws android.content.pm.PackageManager.NameNotFoundException; - method @FlaggedApi("android.content.pm.archiving") @Nullable public android.content.pm.ArchivedPackage getArchivedPackage(@NonNull String); + method @FlaggedApi("android.content.pm.archiving") @Nullable public android.content.pm.ArchivedPackageInfo getArchivedPackage(@NonNull String); method @NonNull public CharSequence getBackgroundPermissionOptionLabel(); method @Nullable public abstract android.content.pm.ChangedPackages getChangedPackages(@IntRange(from=0) int); method public abstract int getComponentEnabledSetting(@NonNull android.content.ComponentName); @@ -17708,11 +17708,14 @@ package android.graphics.pdf { package android.graphics.text { - public final class LineBreakConfig { + public final class LineBreakConfig implements android.os.Parcelable { + method @FlaggedApi("com.android.text.flags.no_break_no_hyphenation_span") public int describeContents(); method @FlaggedApi("com.android.text.flags.no_break_no_hyphenation_span") public int getHyphenation(); method public int getLineBreakStyle(); method public int getLineBreakWordStyle(); method @FlaggedApi("com.android.text.flags.no_break_no_hyphenation_span") @NonNull public android.graphics.text.LineBreakConfig merge(@NonNull android.graphics.text.LineBreakConfig); + method @FlaggedApi("com.android.text.flags.no_break_no_hyphenation_span") public void writeToParcel(@NonNull android.os.Parcel, int); + field @FlaggedApi("com.android.text.flags.no_break_no_hyphenation_span") @NonNull public static final android.os.Parcelable.Creator<android.graphics.text.LineBreakConfig> CREATOR; field @FlaggedApi("com.android.text.flags.no_break_no_hyphenation_span") public static final int HYPHENATION_DISABLED = 0; // 0x0 field @FlaggedApi("com.android.text.flags.no_break_no_hyphenation_span") public static final int HYPHENATION_ENABLED = 1; // 0x1 field @FlaggedApi("com.android.text.flags.no_break_no_hyphenation_span") public static final int HYPHENATION_UNSPECIFIED = -1; // 0xffffffff @@ -42596,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"; @@ -45534,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 @@ -48011,17 +48016,15 @@ package android.text.style { method public void writeToParcel(@NonNull android.os.Parcel, int); } - @FlaggedApi("com.android.text.flags.no_break_no_hyphenation_span") public class LineBreakConfigSpan { + @FlaggedApi("com.android.text.flags.no_break_no_hyphenation_span") public final class LineBreakConfigSpan implements android.text.ParcelableSpan { ctor @FlaggedApi("com.android.text.flags.no_break_no_hyphenation_span") public LineBreakConfigSpan(@NonNull android.graphics.text.LineBreakConfig); + method @FlaggedApi("com.android.text.flags.no_break_no_hyphenation_span") @NonNull public static android.text.style.LineBreakConfigSpan createNoBreakSpan(); + method @FlaggedApi("com.android.text.flags.no_break_no_hyphenation_span") @NonNull public static android.text.style.LineBreakConfigSpan createNoHyphenationSpan(); + method public int describeContents(); method @FlaggedApi("com.android.text.flags.no_break_no_hyphenation_span") @NonNull public android.graphics.text.LineBreakConfig getLineBreakConfig(); - } - - @FlaggedApi("com.android.text.flags.no_break_no_hyphenation_span") public static final class LineBreakConfigSpan.NoBreakSpan extends android.text.style.LineBreakConfigSpan { - ctor @FlaggedApi("com.android.text.flags.no_break_no_hyphenation_span") public LineBreakConfigSpan.NoBreakSpan(); - } - - @FlaggedApi("com.android.text.flags.no_break_no_hyphenation_span") public static final class LineBreakConfigSpan.NoHyphenationSpan extends android.text.style.LineBreakConfigSpan { - ctor @FlaggedApi("com.android.text.flags.no_break_no_hyphenation_span") public LineBreakConfigSpan.NoHyphenationSpan(); + method public int getSpanTypeId(); + method public void writeToParcel(@NonNull android.os.Parcel, int); + field @NonNull public static final android.os.Parcelable.Creator<android.text.style.LineBreakConfigSpan> CREATOR; } public interface LineHeightSpan extends android.text.style.ParagraphStyle android.text.style.WrapTogetherSpan { @@ -49803,6 +49806,7 @@ package android.view { method public boolean applyTransactionOnDraw(@NonNull android.view.SurfaceControl.Transaction); method @Nullable public android.view.SurfaceControl.Transaction buildReparentTransaction(@NonNull android.view.SurfaceControl); method public default int getBufferTransformHint(); + method @FlaggedApi("com.android.window.flags.get_host_token_api") @Nullable public default android.os.IBinder getHostToken(); method public default void removeOnBufferTransformHintChangedListener(@NonNull android.view.AttachedSurfaceControl.OnBufferTransformHintChangedListener); method public default void setChildBoundingInsets(@NonNull android.graphics.Rect); method public default void setTouchableRegion(@Nullable android.graphics.Region); diff --git a/core/api/system-current.txt b/core/api/system-current.txt index 0ad73af28a2c..183b925cefd5 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"; @@ -3819,7 +3820,7 @@ package android.content.pm { field public static final String EXTRA_CALLBACK = "android.content.pm.extra.CALLBACK"; field public static final String EXTRA_DATA_LOADER_TYPE = "android.content.pm.extra.DATA_LOADER_TYPE"; field public static final String EXTRA_LEGACY_STATUS = "android.content.pm.extra.LEGACY_STATUS"; - field public static final String EXTRA_RESOLVED_BASE_PATH = "android.content.pm.extra.RESOLVED_BASE_PATH"; + field @Deprecated public static final String EXTRA_RESOLVED_BASE_PATH = "android.content.pm.extra.RESOLVED_BASE_PATH"; field @FlaggedApi("android.content.pm.archiving") public static final String EXTRA_UNARCHIVE_ALL_USERS = "android.content.pm.extra.UNARCHIVE_ALL_USERS"; field @FlaggedApi("android.content.pm.archiving") public static final String EXTRA_UNARCHIVE_PACKAGE_NAME = "android.content.pm.extra.UNARCHIVE_PACKAGE_NAME"; field public static final int LOCATION_DATA_APP = 0; // 0x0 diff --git a/core/java/android/app/AppOpsManager.java b/core/java/android/app/AppOpsManager.java index 9a19d8edf8a8..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 @@ -8305,7 +8331,9 @@ public class AppOpsManager { */ public int unsafeCheckOpRawNoThrow(int op, int uid, @NonNull String packageName) { try { - return mService.checkOperationRaw(op, uid, packageName, null); + final AttributionSource attributionSource = + new AttributionSource.Builder(uid).setPackageName(packageName).build(); + return mService.checkOperationWithStateRaw(op, attributionSource.asState()); } catch (RemoteException e) { throw e.rethrowFromSystemServer(); } @@ -8468,7 +8496,12 @@ public class AppOpsManager { } } - SyncNotedAppOp syncOp = mService.noteOperation(op, uid, packageName, attributionTag, + final AttributionSource attributionSource = + new AttributionSource.Builder(uid) + .setPackageName(packageName) + .setAttributionTag(attributionTag) + .build(); + SyncNotedAppOp syncOp = mService.noteOperationWithState(op, attributionSource.asState(), collectionMode == COLLECT_ASYNC, message, shouldCollectMessage); if (syncOp.getOpMode() == MODE_ALLOWED) { @@ -8708,7 +8741,9 @@ public class AppOpsManager { @UnsupportedAppUsage public int checkOp(int op, int uid, String packageName) { try { - int mode = mService.checkOperation(op, uid, packageName); + final AttributionSource attributionSource = + new AttributionSource.Builder(uid).setPackageName(packageName).build(); + int mode = mService.checkOperationWithState(op, attributionSource.asState()); if (mode == MODE_ERRORED) { throw new SecurityException(buildSecurityExceptionMsg(op, uid, packageName)); } @@ -8729,7 +8764,9 @@ public class AppOpsManager { @UnsupportedAppUsage public int checkOpNoThrow(int op, int uid, String packageName) { try { - int mode = mService.checkOperation(op, uid, packageName); + final AttributionSource attributionSource = + new AttributionSource.Builder(uid).setPackageName(packageName).build(); + int mode = mService.checkOperationWithState(op, attributionSource.asState()); return mode == AppOpsManager.MODE_FOREGROUND ? AppOpsManager.MODE_ALLOWED : mode; } catch (RemoteException e) { throw e.rethrowFromSystemServer(); @@ -8974,8 +9011,14 @@ public class AppOpsManager { } } - SyncNotedAppOp syncOp = mService.startOperation(token, op, uid, packageName, - attributionTag, startIfModeDefault, collectionMode == COLLECT_ASYNC, message, + final AttributionSource attributionSource = + new AttributionSource.Builder(uid) + .setPackageName(packageName) + .setAttributionTag(attributionTag) + .build(); + SyncNotedAppOp syncOp = mService.startOperationWithState(token, op, + attributionSource.asState(), startIfModeDefault, + collectionMode == COLLECT_ASYNC, message, shouldCollectMessage, attributionFlags, attributionChainId); if (syncOp.getOpMode() == MODE_ALLOWED) { @@ -9188,7 +9231,12 @@ public class AppOpsManager { public void finishOp(IBinder token, int op, int uid, @NonNull String packageName, @Nullable String attributionTag) { try { - mService.finishOperation(token, op, uid, packageName, attributionTag); + final AttributionSource attributionSource = + new AttributionSource.Builder(uid) + .setPackageName(packageName) + .setAttributionTag(attributionTag) + .build(); + mService.finishOperationWithState(token, op, attributionSource.asState()); } catch (RemoteException e) { throw e.rethrowFromSystemServer(); } diff --git a/core/java/android/app/AppOpsManagerInternal.java b/core/java/android/app/AppOpsManagerInternal.java index 43023fe9c2ab..a3de8faa1273 100644 --- a/core/java/android/app/AppOpsManagerInternal.java +++ b/core/java/android/app/AppOpsManagerInternal.java @@ -26,11 +26,12 @@ import android.util.SparseArray; import android.util.SparseIntArray; import com.android.internal.app.IAppOpsCallback; -import com.android.internal.util.function.HeptFunction; import com.android.internal.util.function.HexFunction; +import com.android.internal.util.function.NonaFunction; import com.android.internal.util.function.QuadFunction; -import com.android.internal.util.function.QuintConsumer; import com.android.internal.util.function.QuintFunction; +import com.android.internal.util.function.TriConsumer; +import com.android.internal.util.function.TriFunction; import com.android.internal.util.function.UndecFunction; /** @@ -45,15 +46,13 @@ public abstract class AppOpsManagerInternal { * Allows overriding check operation behavior. * * @param code The op code to check. - * @param uid The UID for which to check. - * @param packageName The package for which to check. - * @param attributionTag The attribution tag for which to check. + * @param attributionSource the {@link AttributionSource} responsible for data access * @param raw Whether to check the raw op i.e. not interpret the mode based on UID state. * @param superImpl The super implementation. * @return The app op check result. */ - int checkOperation(int code, int uid, String packageName, @Nullable String attributionTag, - boolean raw, QuintFunction<Integer, Integer, String, String, Boolean, Integer> + int checkOperation(int code, AttributionSource attributionSource, + boolean raw, TriFunction<Integer, AttributionSource, Boolean, Integer> superImpl); /** @@ -73,25 +72,23 @@ public abstract class AppOpsManagerInternal { * Allows overriding note operation behavior. * * @param code The op code to note. - * @param uid The UID for which to note. - * @param packageName The package for which to note. {@code null} for system package. - * @param featureId Id of the feature in the package + * @param attributionSource the {@link AttributionSource} responsible for data access * @param shouldCollectAsyncNotedOp If an {@link AsyncNotedAppOp} should be collected * @param message The message in the async noted op * @param superImpl The super implementation. * @return The app op note result. */ - SyncNotedAppOp noteOperation(int code, int uid, @Nullable String packageName, - @Nullable String featureId, boolean shouldCollectAsyncNotedOp, + SyncNotedAppOp noteOperation(int code, AttributionSource attributionSource, + boolean shouldCollectAsyncNotedOp, @Nullable String message, boolean shouldCollectMessage, - @NonNull HeptFunction<Integer, Integer, String, String, Boolean, String, Boolean, + @NonNull QuintFunction<Integer, AttributionSource, Boolean, String, Boolean, SyncNotedAppOp> superImpl); /** * Allows overriding note proxy operation behavior. * * @param code The op code to note. - * @param attributionSource The permission identity of the caller. + * @param attributionSource the {@link AttributionSource} responsible for data access * @param shouldCollectAsyncNotedOp If an {@link AsyncNotedAppOp} should be collected * @param message The message in the async noted op * @param shouldCollectMessage whether to collect messages @@ -110,9 +107,7 @@ public abstract class AppOpsManagerInternal { * * @param token The client state. * @param code The op code to start. - * @param uid The UID for which to note. - * @param packageName The package for which to note. {@code null} for system package. - * @param attributionTag the attribution tag. + * @param attributionSource the {@link AttributionSource} responsible for data access * @param startIfModeDefault Whether to start the op of the mode is default. * @param shouldCollectAsyncNotedOp If an {@link AsyncNotedAppOp} should be collected * @param message The message in the async noted op @@ -122,12 +117,12 @@ public abstract class AppOpsManagerInternal { * @param superImpl The super implementation. * @return The app op note result. */ - SyncNotedAppOp startOperation(IBinder token, int code, int uid, - @Nullable String packageName, @Nullable String attributionTag, + SyncNotedAppOp startOperation(IBinder token, int code, + AttributionSource attributionSource, boolean startIfModeDefault, boolean shouldCollectAsyncNotedOp, @Nullable String message, boolean shouldCollectMessage, @AttributionFlags int attributionFlags, int attributionChainId, - @NonNull UndecFunction<IBinder, Integer, Integer, String, String, Boolean, + @NonNull NonaFunction<IBinder, Integer, AttributionSource, Boolean, Boolean, String, Boolean, Integer, Integer, SyncNotedAppOp> superImpl); /** @@ -135,7 +130,7 @@ public abstract class AppOpsManagerInternal { * * @param clientId The client calling start, represented by an IBinder * @param code The op code to start. - * @param attributionSource The permission identity of the caller. + * @param attributionSource the {@link AttributionSource} responsible for data access * @param startIfModeDefault Whether to start the op of the mode is default. * @param shouldCollectAsyncNotedOp If an {@link AsyncNotedAppOp} should be collected * @param message The message in the async noted op @@ -161,21 +156,19 @@ public abstract class AppOpsManagerInternal { * * @param clientId The client state. * @param code The op code to finish. - * @param uid The UID for which the op was noted. - * @param packageName The package for which it was noted. {@code null} for system package. - * @param attributionTag the attribution tag. + * @param attributionSource the {@link AttributionSource} responsible for data access */ - default void finishOperation(IBinder clientId, int code, int uid, String packageName, - String attributionTag, - @NonNull QuintConsumer<IBinder, Integer, Integer, String, String> superImpl) { - superImpl.accept(clientId, code, uid, packageName, attributionTag); + default void finishOperation(IBinder clientId, int code, + AttributionSource attributionSource, + @NonNull TriConsumer<IBinder, Integer, AttributionSource> superImpl) { + superImpl.accept(clientId, code, attributionSource); } /** * Allows overriding finish proxy op. * * @param code The op code to finish. - * @param attributionSource The permission identity of the caller. + * @param attributionSource the {@link AttributionSource} responsible for data access * @param skipProxyOperation Whether to skip the proxy in the proxy/proxied operation * @param clientId The client calling finishProxyOperation * @param superImpl The "standard" implementation to potentially call diff --git a/core/java/android/app/ApplicationPackageManager.java b/core/java/android/app/ApplicationPackageManager.java index fd308ce2e85a..367e92b9d960 100644 --- a/core/java/android/app/ApplicationPackageManager.java +++ b/core/java/android/app/ApplicationPackageManager.java @@ -48,7 +48,7 @@ import android.content.IntentSender; import android.content.pm.ActivityInfo; import android.content.pm.ApkChecksum; import android.content.pm.ApplicationInfo; -import android.content.pm.ArchivedPackage; +import android.content.pm.ArchivedPackageInfo; import android.content.pm.ChangedPackages; import android.content.pm.Checksum; import android.content.pm.ComponentInfo; @@ -3937,13 +3937,13 @@ public class ApplicationPackageManager extends PackageManager { } @Override - public @Nullable ArchivedPackage getArchivedPackage(@NonNull String packageName) { + public @Nullable ArchivedPackageInfo getArchivedPackage(@NonNull String packageName) { try { var parcel = mPM.getArchivedPackage(packageName, mContext.getUserId()); if (parcel == null) { return null; } - return new ArchivedPackage(parcel); + return new ArchivedPackageInfo(parcel); } catch (RemoteException e) { throw e.rethrowAsRuntimeException(); } 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/notification.aconfig b/core/java/android/app/notification.aconfig new file mode 100644 index 000000000000..cd1d8ce66cb5 --- /dev/null +++ b/core/java/android/app/notification.aconfig @@ -0,0 +1,8 @@ +package: "android.app" + +flag { + name: "modes_api" + namespace: "systemui" + description: "This flag controls new and updated DND apis" + bug: "300477976" +}
\ No newline at end of file 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/VirtualDeviceManager.java b/core/java/android/companion/virtual/VirtualDeviceManager.java index d40a5911d8f4..b3ea93bb8a85 100644 --- a/core/java/android/companion/virtual/VirtualDeviceManager.java +++ b/core/java/android/companion/virtual/VirtualDeviceManager.java @@ -185,9 +185,6 @@ public final class VirtualDeviceManager { int associationId, @NonNull VirtualDeviceParams params) { Objects.requireNonNull(params, "params must not be null"); - if (Flags.moreLogs()) { - Log.i(TAG, "Creating VirtualDevice"); - } try { return new VirtualDevice(mService, mContext, associationId, params); } catch (RemoteException e) { diff --git a/core/java/android/companion/virtual/flags.aconfig b/core/java/android/companion/virtual/flags.aconfig index f380963fbcab..3cadb7c09d54 100644 --- a/core/java/android/companion/virtual/flags.aconfig +++ b/core/java/android/companion/virtual/flags.aconfig @@ -1,13 +1,6 @@ package: "android.companion.virtual.flags" flag { - name: "more_logs" - namespace: "virtual_devices" - description: "More logs to test flags with" - bug: "291725823" -} - -flag { name: "enable_native_vdm" namespace: "virtual_devices" description: "Enable native VDM service" diff --git a/core/java/android/content/AttributionSource.java b/core/java/android/content/AttributionSource.java index 4b2cee698df2..c2bc974a42ae 100644 --- a/core/java/android/content/AttributionSource.java +++ b/core/java/android/content/AttributionSource.java @@ -235,6 +235,12 @@ public final class AttributionSource implements Parcelable { } /** @hide */ + public AttributionSource withUid(int uid) { + return new AttributionSource(uid, getPid(), getPackageName(), getAttributionTag(), + getToken(), mAttributionSourceState.renouncedPermissions, getDeviceId(), getNext()); + } + + /** @hide */ public AttributionSource withPid(int pid) { return new AttributionSource(getUid(), pid, getPackageName(), getAttributionTag(), getToken(), mAttributionSourceState.renouncedPermissions, getDeviceId(), getNext()); 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/ArchivedActivity.java b/core/java/android/content/pm/ArchivedActivityInfo.java index 9e49c9e52878..1faa4373d88f 100644 --- a/core/java/android/content/pm/ArchivedActivity.java +++ b/core/java/android/content/pm/ArchivedActivityInfo.java @@ -32,9 +32,13 @@ import java.io.ByteArrayOutputStream; import java.io.IOException; import java.util.Objects; +/** + * Contains fields required to show archived package in Launcher. + * @see ArchivedPackageInfo + */ @DataClass(genBuilder = false, genConstructor = false, genSetters = true) @FlaggedApi(Flags.FLAG_ARCHIVING) -public final class ArchivedActivity { +public final class ArchivedActivityInfo { /** The label for the activity. */ private @NonNull CharSequence mLabel; /** The component name of this activity. */ @@ -47,7 +51,7 @@ public final class ArchivedActivity { /** Monochrome icon, if defined, of the activity. */ private @Nullable Drawable mMonochromeIcon; - public ArchivedActivity(@NonNull CharSequence label, @NonNull ComponentName componentName) { + public ArchivedActivityInfo(@NonNull CharSequence label, @NonNull ComponentName componentName) { Objects.requireNonNull(label); Objects.requireNonNull(componentName); mLabel = label; @@ -55,7 +59,7 @@ public final class ArchivedActivity { } /* @hide */ - ArchivedActivity(@NonNull ArchivedActivityParcel parcel) { + ArchivedActivityInfo(@NonNull ArchivedActivityParcel parcel) { mLabel = parcel.title; mComponentName = parcel.originalComponentName; mIcon = drawableFromCompressedBitmap(parcel.iconBitmap); @@ -149,7 +153,7 @@ public final class ArchivedActivity { // CHECKSTYLE:OFF Generated code // // To regenerate run: - // $ codegen $ANDROID_BUILD_TOP/frameworks/base/core/java/android/content/pm/ArchivedActivity.java + // $ codegen $ANDROID_BUILD_TOP/frameworks/base/core/java/android/content/pm/ArchivedActivityInfo.java // // To exclude the generated code from IntelliJ auto-formatting enable (one-time): // Settings > Editor > Code Style > Formatter Control @@ -193,7 +197,7 @@ public final class ArchivedActivity { * The label for the activity. */ @DataClass.Generated.Member - public @NonNull ArchivedActivity setLabel(@NonNull CharSequence value) { + public @NonNull ArchivedActivityInfo setLabel(@NonNull CharSequence value) { mLabel = value; com.android.internal.util.AnnotationValidations.validate( NonNull.class, null, mLabel); @@ -204,7 +208,7 @@ public final class ArchivedActivity { * The component name of this activity. */ @DataClass.Generated.Member - public @NonNull ArchivedActivity setComponentName(@NonNull ComponentName value) { + public @NonNull ArchivedActivityInfo setComponentName(@NonNull ComponentName value) { mComponentName = value; com.android.internal.util.AnnotationValidations.validate( NonNull.class, null, mComponentName); @@ -216,7 +220,7 @@ public final class ArchivedActivity { * launcher. */ @DataClass.Generated.Member - public @NonNull ArchivedActivity setIcon(@NonNull Drawable value) { + public @NonNull ArchivedActivityInfo setIcon(@NonNull Drawable value) { mIcon = value; return this; } @@ -225,16 +229,16 @@ public final class ArchivedActivity { * Monochrome icon, if defined, of the activity. */ @DataClass.Generated.Member - public @NonNull ArchivedActivity setMonochromeIcon(@NonNull Drawable value) { + public @NonNull ArchivedActivityInfo setMonochromeIcon(@NonNull Drawable value) { mMonochromeIcon = value; return this; } @DataClass.Generated( - time = 1698173429911L, + time = 1698789991876L, codegenVersion = "1.0.23", - sourceFile = "frameworks/base/core/java/android/content/pm/ArchivedActivity.java", - inputSignatures = "private @android.annotation.NonNull java.lang.CharSequence mLabel\nprivate @android.annotation.NonNull android.content.ComponentName mComponentName\nprivate @android.annotation.Nullable android.graphics.drawable.Drawable mIcon\nprivate @android.annotation.Nullable android.graphics.drawable.Drawable mMonochromeIcon\n @android.annotation.NonNull android.content.pm.ArchivedActivityParcel getParcel()\npublic static android.graphics.Bitmap drawableToBitmap(android.graphics.drawable.Drawable)\npublic static android.graphics.Bitmap drawableToBitmap(android.graphics.drawable.Drawable,int)\npublic static byte[] bytesFromBitmap(android.graphics.Bitmap)\nprivate static android.graphics.drawable.Drawable drawableFromCompressedBitmap(byte[])\nclass ArchivedActivity extends java.lang.Object implements []\n@com.android.internal.util.DataClass(genBuilder=false, genConstructor=false, genSetters=true)") + sourceFile = "frameworks/base/core/java/android/content/pm/ArchivedActivityInfo.java", + inputSignatures = "private @android.annotation.NonNull java.lang.CharSequence mLabel\nprivate @android.annotation.NonNull android.content.ComponentName mComponentName\nprivate @android.annotation.Nullable android.graphics.drawable.Drawable mIcon\nprivate @android.annotation.Nullable android.graphics.drawable.Drawable mMonochromeIcon\n @android.annotation.NonNull android.content.pm.ArchivedActivityParcel getParcel()\npublic static android.graphics.Bitmap drawableToBitmap(android.graphics.drawable.Drawable)\npublic static android.graphics.Bitmap drawableToBitmap(android.graphics.drawable.Drawable,int)\npublic static byte[] bytesFromBitmap(android.graphics.Bitmap)\nprivate static android.graphics.drawable.Drawable drawableFromCompressedBitmap(byte[])\nclass ArchivedActivityInfo extends java.lang.Object implements []\n@com.android.internal.util.DataClass(genBuilder=false, genConstructor=false, genSetters=true)") @Deprecated private void __metadata() {} diff --git a/core/java/android/content/pm/ArchivedPackage.java b/core/java/android/content/pm/ArchivedPackageInfo.java index 42795db35684..f432598ef887 100644 --- a/core/java/android/content/pm/ArchivedPackage.java +++ b/core/java/android/content/pm/ArchivedPackageInfo.java @@ -27,9 +27,13 @@ import java.util.ArrayList; import java.util.List; import java.util.Objects; +/** + * Contains fields required for archived package installation, + * i.e. installation without an APK. + */ @DataClass(genBuilder = false, genConstructor = false, genSetters = true) @FlaggedApi(Flags.FLAG_ARCHIVING) -public final class ArchivedPackage { +public final class ArchivedPackageInfo { /** Name of the package as used to identify it in the system */ private @NonNull String mPackageName; /** Signing certificates used to sign the package. */ @@ -74,10 +78,10 @@ public final class ArchivedPackage { * {@link Intent#CATEGORY_LAUNCHER}. * @see LauncherApps#getActivityList */ - private @NonNull List<ArchivedActivity> mLauncherActivities; + private @NonNull List<ArchivedActivityInfo> mLauncherActivities; - public ArchivedPackage(@NonNull String packageName, @NonNull SigningInfo signingInfo, - @NonNull List<ArchivedActivity> launcherActivities) { + public ArchivedPackageInfo(@NonNull String packageName, @NonNull SigningInfo signingInfo, + @NonNull List<ArchivedActivityInfo> launcherActivities) { Objects.requireNonNull(packageName); Objects.requireNonNull(signingInfo); Objects.requireNonNull(launcherActivities); @@ -90,7 +94,7 @@ public final class ArchivedPackage { * Constructs the archived package from parcel. * @hide */ - public ArchivedPackage(@NonNull ArchivedPackageParcel parcel) { + public ArchivedPackageInfo(@NonNull ArchivedPackageParcel parcel) { mPackageName = parcel.packageName; mSigningInfo = new SigningInfo(parcel.signingDetails); mVersionCode = parcel.versionCode; @@ -102,7 +106,7 @@ public final class ArchivedPackage { mLauncherActivities = new ArrayList<>(); if (parcel.archivedActivities != null) { for (var activityParcel : parcel.archivedActivities) { - mLauncherActivities.add(new ArchivedActivity(activityParcel)); + mLauncherActivities.add(new ArchivedActivityInfo(activityParcel)); } } } @@ -135,7 +139,7 @@ public final class ArchivedPackage { // CHECKSTYLE:OFF Generated code // // To regenerate run: - // $ codegen $ANDROID_BUILD_TOP/frameworks/base/core/java/android/content/pm/ArchivedPackage.java + // $ codegen $ANDROID_BUILD_TOP/frameworks/base/core/java/android/content/pm/ArchivedPackageInfo.java // // To exclude the generated code from IntelliJ auto-formatting enable (one-time): // Settings > Editor > Code Style > Formatter Control @@ -224,7 +228,7 @@ public final class ArchivedPackage { * @see LauncherApps#getActivityList */ @DataClass.Generated.Member - public @NonNull List<ArchivedActivity> getLauncherActivities() { + public @NonNull List<ArchivedActivityInfo> getLauncherActivities() { return mLauncherActivities; } @@ -232,7 +236,7 @@ public final class ArchivedPackage { * Name of the package as used to identify it in the system */ @DataClass.Generated.Member - public @NonNull ArchivedPackage setPackageName(@NonNull String value) { + public @NonNull ArchivedPackageInfo setPackageName(@NonNull String value) { mPackageName = value; com.android.internal.util.AnnotationValidations.validate( NonNull.class, null, mPackageName); @@ -243,7 +247,7 @@ public final class ArchivedPackage { * Signing certificates used to sign the package. */ @DataClass.Generated.Member - public @NonNull ArchivedPackage setSigningInfo(@NonNull SigningInfo value) { + public @NonNull ArchivedPackageInfo setSigningInfo(@NonNull SigningInfo value) { mSigningInfo = value; com.android.internal.util.AnnotationValidations.validate( NonNull.class, null, mSigningInfo); @@ -255,7 +259,7 @@ public final class ArchivedPackage { * {@link android.R.styleable#AndroidManifest_versionCode versionCode} attribute. */ @DataClass.Generated.Member - public @NonNull ArchivedPackage setVersionCode( int value) { + public @NonNull ArchivedPackageInfo setVersionCode( int value) { mVersionCode = value; return this; } @@ -265,7 +269,7 @@ public final class ArchivedPackage { * {@link android.R.styleable#AndroidManifest_versionCode versionCodeMajor} attribute. */ @DataClass.Generated.Member - public @NonNull ArchivedPackage setVersionCodeMajor( int value) { + public @NonNull ArchivedPackageInfo setVersionCodeMajor( int value) { mVersionCodeMajor = value; return this; } @@ -276,7 +280,7 @@ public final class ArchivedPackage { * attribute. */ @DataClass.Generated.Member - public @NonNull ArchivedPackage setTargetSdkVersion( int value) { + public @NonNull ArchivedPackageInfo setTargetSdkVersion( int value) { mTargetSdkVersion = value; return this; } @@ -287,7 +291,7 @@ public final class ArchivedPackage { * attribute. */ @DataClass.Generated.Member - public @NonNull ArchivedPackage setDefaultToDeviceProtectedStorage(@NonNull String value) { + public @NonNull ArchivedPackageInfo setDefaultToDeviceProtectedStorage(@NonNull String value) { mDefaultToDeviceProtectedStorage = value; return this; } @@ -299,7 +303,7 @@ public final class ArchivedPackage { * attribute. */ @DataClass.Generated.Member - public @NonNull ArchivedPackage setRequestLegacyExternalStorage(@NonNull String value) { + public @NonNull ArchivedPackageInfo setRequestLegacyExternalStorage(@NonNull String value) { mRequestLegacyExternalStorage = value; return this; } @@ -310,7 +314,7 @@ public final class ArchivedPackage { * {@link android.R.styleable#AndroidManifestApplication_hasFragileUserData} attribute. */ @DataClass.Generated.Member - public @NonNull ArchivedPackage setUserDataFragile(@NonNull String value) { + public @NonNull ArchivedPackageInfo setUserDataFragile(@NonNull String value) { mUserDataFragile = value; return this; } @@ -322,7 +326,7 @@ public final class ArchivedPackage { * @see LauncherApps#getActivityList */ @DataClass.Generated.Member - public @NonNull ArchivedPackage setLauncherActivities(@NonNull List<ArchivedActivity> value) { + public @NonNull ArchivedPackageInfo setLauncherActivities(@NonNull List<ArchivedActivityInfo> value) { mLauncherActivities = value; com.android.internal.util.AnnotationValidations.validate( NonNull.class, null, mLauncherActivities); @@ -330,10 +334,10 @@ public final class ArchivedPackage { } @DataClass.Generated( - time = 1697824890503L, + time = 1698789995536L, codegenVersion = "1.0.23", - sourceFile = "frameworks/base/core/java/android/content/pm/ArchivedPackage.java", - inputSignatures = "private @android.annotation.NonNull java.lang.String mPackageName\nprivate @android.annotation.NonNull android.content.pm.SigningInfo mSigningInfo\nprivate int mVersionCode\nprivate int mVersionCodeMajor\nprivate int mTargetSdkVersion\nprivate @android.annotation.Nullable java.lang.String mDefaultToDeviceProtectedStorage\nprivate @android.annotation.Nullable java.lang.String mRequestLegacyExternalStorage\nprivate @android.annotation.Nullable java.lang.String mUserDataFragile\nprivate @android.annotation.NonNull java.util.List<android.content.pm.ArchivedActivity> mLauncherActivities\n android.content.pm.ArchivedPackageParcel getParcel()\nclass ArchivedPackage extends java.lang.Object implements []\n@com.android.internal.util.DataClass(genBuilder=false, genConstructor=false, genSetters=true)") + sourceFile = "frameworks/base/core/java/android/content/pm/ArchivedPackageInfo.java", + inputSignatures = "private @android.annotation.NonNull java.lang.String mPackageName\nprivate @android.annotation.NonNull android.content.pm.SigningInfo mSigningInfo\nprivate int mVersionCode\nprivate int mVersionCodeMajor\nprivate int mTargetSdkVersion\nprivate @android.annotation.Nullable java.lang.String mDefaultToDeviceProtectedStorage\nprivate @android.annotation.Nullable java.lang.String mRequestLegacyExternalStorage\nprivate @android.annotation.Nullable java.lang.String mUserDataFragile\nprivate @android.annotation.NonNull java.util.List<android.content.pm.ArchivedActivityInfo> mLauncherActivities\n android.content.pm.ArchivedPackageParcel getParcel()\nclass ArchivedPackageInfo extends java.lang.Object implements []\n@com.android.internal.util.DataClass(genBuilder=false, genConstructor=false, genSetters=true)") @Deprecated private void __metadata() {} diff --git a/core/java/android/content/pm/PackageInstaller.java b/core/java/android/content/pm/PackageInstaller.java index cbb20e08f368..1114b358e08a 100644 --- a/core/java/android/content/pm/PackageInstaller.java +++ b/core/java/android/content/pm/PackageInstaller.java @@ -343,7 +343,10 @@ public class PackageInstaller { * point at the existing base APK (when adding splits to an existing app). * * @hide + * @deprecated Resolved base path of an install session should not be available to unauthorized + * callers. Use {@link SessionInfo#getResolvedBaseApkPath()} instead. */ + @Deprecated @SystemApi public static final String EXTRA_RESOLVED_BASE_PATH = "android.content.pm.extra.RESOLVED_BASE_PATH"; @@ -1003,7 +1006,7 @@ public class PackageInstaller { /** * Install package in an archived state. * - * @param archivedPackage archived package data such as package name, signature etc. + * @param archivedPackageInfo archived package data such as package name, signature etc. * @param sessionParams used to create an underlying installation session * @param statusReceiver Called when the state of the session changes. Intents * sent to this receiver contain {@link #EXTRA_STATUS}. Refer to the @@ -1013,15 +1016,15 @@ public class PackageInstaller { */ @RequiresPermission(Manifest.permission.INSTALL_PACKAGES) @FlaggedApi(Flags.FLAG_ARCHIVING) - public void installPackageArchived(@NonNull ArchivedPackage archivedPackage, + public void installPackageArchived(@NonNull ArchivedPackageInfo archivedPackageInfo, @NonNull SessionParams sessionParams, @NonNull IntentSender statusReceiver) { - Objects.requireNonNull(archivedPackage, "archivedPackage cannot be null"); + Objects.requireNonNull(archivedPackageInfo, "archivedPackageInfo cannot be null"); Objects.requireNonNull(sessionParams, "sessionParams cannot be null"); Objects.requireNonNull(statusReceiver, "statusReceiver cannot be null"); try { mInstaller.installPackageArchived( - archivedPackage.getParcel(), + archivedPackageInfo.getParcel(), sessionParams, statusReceiver, mInstallerPackageName, diff --git a/core/java/android/content/pm/PackageManager.java b/core/java/android/content/pm/PackageManager.java index ad7dd513b382..dea4a12541e5 100644 --- a/core/java/android/content/pm/PackageManager.java +++ b/core/java/android/content/pm/PackageManager.java @@ -11032,7 +11032,7 @@ public abstract class PackageManager { * @see PackageInstaller#installPackageArchived */ @FlaggedApi(android.content.pm.Flags.FLAG_ARCHIVING) - public @Nullable ArchivedPackage getArchivedPackage(@NonNull String packageName) { + public @Nullable ArchivedPackageInfo getArchivedPackage(@NonNull String packageName) { throw new UnsupportedOperationException( "getArchivedPackage not implemented in subclass"); } diff --git a/core/java/android/content/res/StringBlock.java b/core/java/android/content/res/StringBlock.java index c143acb34c5f..0070a6f920db 100644 --- a/core/java/android/content/res/StringBlock.java +++ b/core/java/android/content/res/StringBlock.java @@ -24,6 +24,7 @@ import android.graphics.Color; import android.graphics.Paint; import android.graphics.Rect; import android.graphics.Typeface; +import android.graphics.text.LineBreakConfig; import android.text.Annotation; import android.text.Spannable; import android.text.SpannableString; @@ -35,6 +36,7 @@ import android.text.style.BackgroundColorSpan; import android.text.style.BulletSpan; import android.text.style.CharacterStyle; import android.text.style.ForegroundColorSpan; +import android.text.style.LineBreakConfigSpan; import android.text.style.LineHeightSpan; import android.text.style.RelativeSizeSpan; import android.text.style.StrikethroughSpan; @@ -176,6 +178,10 @@ public final class StringBlock implements Closeable { mStyleIDs.listItemId = styleId; } else if (styleTag.equals("marquee")) { mStyleIDs.marqueeId = styleId; + } else if (styleTag.equals("nobreak")) { + mStyleIDs.mNoBreakId = styleId; + } else if (styleTag.equals("nohyphen")) { + mStyleIDs.mNoHyphenId = styleId; } } @@ -224,6 +230,8 @@ public final class StringBlock implements Closeable { private int strikeId = -1; private int listItemId = -1; private int marqueeId = -1; + private int mNoBreakId = -1; + private int mNoHyphenId = -1; } @Nullable @@ -285,12 +293,19 @@ public final class StringBlock implements Closeable { buffer.setSpan(TextUtils.TruncateAt.MARQUEE, style[i+1], style[i+2]+1, Spannable.SPAN_INCLUSIVE_INCLUSIVE); + } else if (type == ids.mNoBreakId) { + buffer.setSpan(LineBreakConfigSpan.createNoBreakSpan(), + style[i + 1], style[i + 2] + 1, + Spannable.SPAN_INCLUSIVE_EXCLUSIVE); + } else if (type == ids.mNoHyphenId) { + buffer.setSpan(LineBreakConfigSpan.createNoHyphenationSpan(), + style[i + 1], style[i + 2] + 1, + Spannable.SPAN_INCLUSIVE_EXCLUSIVE); } else { String tag = nativeGetString(mNative, type); if (tag == null) { return null; } - if (tag.startsWith("font;")) { String sub; @@ -367,6 +382,44 @@ public final class StringBlock implements Closeable { style[i+1], style[i+2]+1, Spannable.SPAN_EXCLUSIVE_EXCLUSIVE); } + } else if (tag.startsWith("lineBreakConfig;")) { + String lbStyleStr = subtag(tag, ";style="); + int lbStyle = LineBreakConfig.LINE_BREAK_STYLE_UNSPECIFIED; + if (lbStyleStr != null) { + if (lbStyleStr.equals("none")) { + lbStyle = LineBreakConfig.LINE_BREAK_STYLE_NONE; + } else if (lbStyleStr.equals("normal")) { + lbStyle = LineBreakConfig.LINE_BREAK_STYLE_NORMAL; + } else if (lbStyleStr.equals("loose")) { + lbStyle = LineBreakConfig.LINE_BREAK_STYLE_LOOSE; + } else if (lbStyleStr.equals("strict")) { + lbStyle = LineBreakConfig.LINE_BREAK_STYLE_STRICT; + } else { + Log.w(TAG, "Unknown LineBreakConfig style: " + lbStyleStr); + } + } + + String lbWordStyleStr = subtag(tag, ";wordStyle="); + int lbWordStyle = LineBreakConfig.LINE_BREAK_STYLE_UNSPECIFIED; + if (lbWordStyleStr != null) { + if (lbWordStyleStr.equals("none")) { + lbWordStyle = LineBreakConfig.LINE_BREAK_WORD_STYLE_NONE; + } else if (lbWordStyleStr.equals("phrase")) { + lbWordStyle = LineBreakConfig.LINE_BREAK_WORD_STYLE_PHRASE; + } else { + Log.w(TAG, "Unknown LineBreakConfig word style: " + lbWordStyleStr); + } + } + + // Attach span only when the both lbStyle and lbWordStyle are valid. + if (lbStyle != LineBreakConfig.LINE_BREAK_STYLE_UNSPECIFIED + || lbWordStyle != LineBreakConfig.LINE_BREAK_WORD_STYLE_UNSPECIFIED) { + buffer.setSpan(new LineBreakConfigSpan( + new LineBreakConfig(lbStyle, lbWordStyle, + LineBreakConfig.HYPHENATION_UNSPECIFIED)), + style[i + 1], style[i + 2] + 1, + Spannable.SPAN_EXCLUSIVE_EXCLUSIVE); + } } } 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/BatteryManager.java b/core/java/android/os/BatteryManager.java index 6a4ec9b7605a..25fba60b9bb5 100644 --- a/core/java/android/os/BatteryManager.java +++ b/core/java/android/os/BatteryManager.java @@ -21,6 +21,7 @@ import static android.os.Flags.FLAG_STATE_OF_HEALTH_PUBLIC; import android.Manifest.permission; import android.annotation.FlaggedApi; import android.annotation.RequiresPermission; +import android.annotation.SuppressLint; import android.annotation.SystemApi; import android.annotation.SystemService; import android.annotation.TestApi; @@ -236,6 +237,7 @@ public class BatteryManager { OsProtoEnums.CHARGING_POLICY_ADAPTIVE_LONGLIFE; // = 4 /** @hide */ + @SuppressLint("UnflaggedApi") // TestApi without associated feature. @TestApi public static final int BATTERY_PLUGGED_ANY = BATTERY_PLUGGED_AC | BATTERY_PLUGGED_USB | BATTERY_PLUGGED_WIRELESS diff --git a/core/java/android/text/TextUtils.java b/core/java/android/text/TextUtils.java index 4e3deb61761e..c0a5629f9220 100644 --- a/core/java/android/text/TextUtils.java +++ b/core/java/android/text/TextUtils.java @@ -47,6 +47,7 @@ import android.text.style.EasyEditSpan; import android.text.style.ForegroundColorSpan; import android.text.style.LeadingMarginSpan; import android.text.style.LineBackgroundSpan; +import android.text.style.LineBreakConfigSpan; import android.text.style.LineHeightSpan; import android.text.style.LocaleSpan; import android.text.style.ParagraphStyle; @@ -787,7 +788,9 @@ public class TextUtils { /** @hide */ public static final int ACCESSIBILITY_REPLACEMENT_SPAN = 29; /** @hide */ - public static final int LAST_SPAN = ACCESSIBILITY_REPLACEMENT_SPAN; + public static final int LINE_BREAK_CONFIG_SPAN = 30; + /** @hide */ + public static final int LAST_SPAN = LINE_BREAK_CONFIG_SPAN; /** * Flatten a CharSequence and whatever styles can be copied across processes @@ -991,6 +994,10 @@ public class TextUtils { span = new AccessibilityReplacementSpan(p); break; + case LINE_BREAK_CONFIG_SPAN: + span = LineBreakConfigSpan.CREATOR.createFromParcel(p); + break; + default: throw new RuntimeException("bogus span encoding " + kind); } diff --git a/core/java/android/text/style/LineBreakConfigSpan.java b/core/java/android/text/style/LineBreakConfigSpan.java index 682ffa180c0b..eeb638389271 100644 --- a/core/java/android/text/style/LineBreakConfigSpan.java +++ b/core/java/android/text/style/LineBreakConfigSpan.java @@ -21,6 +21,9 @@ import static com.android.text.flags.Flags.FLAG_NO_BREAK_NO_HYPHENATION_SPAN; import android.annotation.FlaggedApi; import android.annotation.NonNull; import android.graphics.text.LineBreakConfig; +import android.os.Parcel; +import android.text.ParcelableSpan; +import android.text.TextUtils; import java.util.Objects; @@ -28,7 +31,7 @@ import java.util.Objects; * LineBreakSpan for changing line break style of the specific region of the text. */ @FlaggedApi(FLAG_NO_BREAK_NO_HYPHENATION_SPAN) -public class LineBreakConfigSpan { +public final class LineBreakConfigSpan implements ParcelableSpan { private final LineBreakConfig mLineBreakConfig; /** @@ -49,6 +52,28 @@ public class LineBreakConfigSpan { return mLineBreakConfig; } + /** + * A specialized {@link LineBreakConfigSpan} that used for preventing line break. + * + * This is useful when you want to preserve some words in the same line. + * Note that even if this style is specified, the grapheme based line break is still performed + * for preventing clipping text. + * + * @see LineBreakConfigSpan + */ + @FlaggedApi(FLAG_NO_BREAK_NO_HYPHENATION_SPAN) + public static @NonNull LineBreakConfigSpan createNoBreakSpan() { + return new LineBreakConfigSpan(sNoBreakConfig); + } + + /** + * A specialized {@link LineBreakConfigSpan} that used for preventing hyphenation. + */ + @FlaggedApi(FLAG_NO_BREAK_NO_HYPHENATION_SPAN) + public static @NonNull LineBreakConfigSpan createNoHyphenationSpan() { + return new LineBreakConfigSpan(sNoHyphenationConfig); + } + @Override public boolean equals(Object o) { if (this == o) return true; @@ -75,37 +100,46 @@ public class LineBreakConfigSpan { .setLineBreakStyle(LineBreakConfig.LINE_BREAK_STYLE_NO_BREAK) .build(); - /** - * A specialized {@link LineBreakConfigSpan} that used for preventing hyphenation. - */ - @FlaggedApi(FLAG_NO_BREAK_NO_HYPHENATION_SPAN) - public static final class NoHyphenationSpan extends LineBreakConfigSpan { - /** - * Construct a new {@link NoHyphenationSpan}. - */ - @FlaggedApi(FLAG_NO_BREAK_NO_HYPHENATION_SPAN) - public NoHyphenationSpan() { - super(sNoHyphenationConfig); - } + @Override + public int describeContents() { + return 0; } - /** - * A specialized {@link LineBreakConfigSpan} that used for preventing line break. - * - * This is useful when you want to preserve some words in the same line. - * Note that even if this style is specified, the grapheme based line break is still performed - * for preventing clipping text. - * - * @see LineBreakConfigSpan - */ - @FlaggedApi(FLAG_NO_BREAK_NO_HYPHENATION_SPAN) - public static final class NoBreakSpan extends LineBreakConfigSpan { - /** - * Construct a new {@link NoBreakSpan}. - */ - @FlaggedApi(FLAG_NO_BREAK_NO_HYPHENATION_SPAN) - public NoBreakSpan() { - super(sNoBreakConfig); - } + @Override + public void writeToParcel(@NonNull Parcel dest, int flags) { + writeToParcelInternal(dest, flags); } + + @Override + public int getSpanTypeId() { + return getSpanTypeIdInternal(); + } + + /** @hide */ + @Override + public int getSpanTypeIdInternal() { + return TextUtils.LINE_BREAK_CONFIG_SPAN; + } + + /** @hide */ + @Override + public void writeToParcelInternal(@NonNull Parcel dest, int flags) { + dest.writeParcelable(mLineBreakConfig, flags); + } + + @NonNull + public static final Creator<LineBreakConfigSpan> CREATOR = new Creator<>() { + + @Override + public LineBreakConfigSpan createFromParcel(Parcel source) { + LineBreakConfig lbc = source.readParcelable( + LineBreakConfig.class.getClassLoader(), LineBreakConfig.class); + return new LineBreakConfigSpan(lbc); + } + + @Override + public LineBreakConfigSpan[] newArray(int size) { + return new LineBreakConfigSpan[size]; + } + }; } diff --git a/core/java/android/view/AttachedSurfaceControl.java b/core/java/android/view/AttachedSurfaceControl.java index 71d382e19e2b..d5457511876b 100644 --- a/core/java/android/view/AttachedSurfaceControl.java +++ b/core/java/android/view/AttachedSurfaceControl.java @@ -15,14 +15,18 @@ */ package android.view; +import android.annotation.FlaggedApi; import android.annotation.NonNull; import android.annotation.Nullable; import android.annotation.UiThread; import android.graphics.Rect; import android.graphics.Region; import android.hardware.HardwareBuffer; +import android.os.IBinder; import android.window.SurfaceSyncGroup; +import com.android.window.flags.Flags; + import java.util.concurrent.Executor; import java.util.function.Consumer; @@ -178,6 +182,21 @@ public interface AttachedSurfaceControl { } /** + * Gets the token used for associating this {@link AttachedSurfaceControl} with + * {@link SurfaceControlViewHost} instances. + * + * <p>This token should be passed to {@link SurfaceControlViewHost}'s constructor. + * + * @return The SurfaceControlViewHost link token. + */ + @Nullable + @FlaggedApi(Flags.FLAG_GET_HOST_TOKEN_API) + default IBinder getHostToken() { + throw new UnsupportedOperationException("The getHostToken needs to be " + + "implemented before making this call."); + } + + /** * Add a trusted presentation listener on the SurfaceControl associated with this window. * * @param t Transaction that the trusted presentation listener is added on. This should 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/ViewRootImpl.java b/core/java/android/view/ViewRootImpl.java index 4da02f902e60..24223694e421 100644 --- a/core/java/android/view/ViewRootImpl.java +++ b/core/java/android/view/ViewRootImpl.java @@ -93,6 +93,7 @@ import android.accessibilityservice.AccessibilityService; import android.animation.AnimationHandler; import android.animation.LayoutTransition; import android.annotation.AnyThread; +import android.annotation.FlaggedApi; import android.annotation.NonNull; import android.annotation.Nullable; import android.annotation.Size; @@ -227,6 +228,7 @@ import com.android.internal.policy.PhoneFallbackEventHandler; import com.android.internal.view.BaseSurfaceHolder; import com.android.internal.view.RootViewSurfaceTaker; import com.android.internal.view.SurfaceCallbackHelper; +import com.android.window.flags.Flags; import java.io.IOException; import java.io.OutputStream; @@ -3962,9 +3964,15 @@ public final class ViewRootImpl implements ViewParent, // on a different thread. However, when the current process is system, the finishDraw in // system server will be run on the current thread, which could result in a deadlock. if (mWindowSession instanceof Binder) { - reportDrawFinished(t, seqId); + // The transaction should be copied to a local reference when posting onto a new + // thread because up until now the SSG is holding a lock on the transaction. Once + // the call jumps onto a new thread, the lock is no longer held and the transaction + // send back may be modified or used again. + Transaction transactionCopy = new Transaction(); + transactionCopy.merge(t); + mHandler.postAtFrontOfQueue(() -> reportDrawFinished(transactionCopy, seqId)); } else { - mHandler.postAtFrontOfQueue(() -> reportDrawFinished(t, seqId)); + reportDrawFinished(t, seqId); } }); if (DEBUG_BLAST) { @@ -3975,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++) { @@ -4890,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 = @@ -4916,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"); @@ -10858,6 +10877,17 @@ public final class ViewRootImpl implements ViewParent, return mInputEventReceiver.getToken(); } + /** + * @return Returns a token used for associating the root surface + * to {@link SurfaceControlViewHost}. + */ + @Nullable + @Override + @FlaggedApi(Flags.FLAG_GET_HOST_TOKEN_API) + public IBinder getHostToken() { + return getInputToken(); + } + @NonNull public IBinder getWindowToken() { return mAttachInfo.mWindowToken; diff --git a/core/java/android/view/accessibility/flags/accessibility_flags.aconfig b/core/java/android/view/accessibility/flags/accessibility_flags.aconfig index 6888b50bb744..ab9566e1ece0 100644 --- a/core/java/android/view/accessibility/flags/accessibility_flags.aconfig +++ b/core/java/android/view/accessibility/flags/accessibility_flags.aconfig @@ -22,3 +22,10 @@ flag { description: "Enable force force-dark for smart inversion and dark theme everywhere" bug: "282821643" } + +flag { + namespace: "accessibility" + name: "update_always_on_a11y_service" + description: "Updates the Always-On A11yService state when the user changes the enablement of the shortcut." + bug: "298869916" +} 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/WindowTokenClient.java b/core/java/android/window/WindowTokenClient.java index f4f1b3b9b27b..c20b278f7eaa 100644 --- a/core/java/android/window/WindowTokenClient.java +++ b/core/java/android/window/WindowTokenClient.java @@ -31,10 +31,8 @@ import android.content.res.Configuration; import android.inputmethodservice.AbstractInputMethodService; import android.os.Binder; import android.os.Build; -import android.os.Bundle; import android.os.Debug; import android.os.Handler; -import android.os.IBinder; import android.util.Log; import com.android.internal.annotations.GuardedBy; @@ -76,8 +74,7 @@ public class WindowTokenClient extends Binder { * Attaches {@code context} to this {@link WindowTokenClient}. Each {@link WindowTokenClient} * can only attach one {@link Context}. * <p>This method must be called before invoking - * {@link android.view.IWindowManager#attachWindowContextToDisplayArea(IBinder, int, int, - * Bundle)}.<p/> + * {@link android.view.IWindowManager#attachWindowContextToDisplayArea}.<p/> * * @param context context to be attached * @throws IllegalStateException if attached context has already existed. diff --git a/core/java/android/window/flags/responsible_apis.aconfig b/core/java/android/window/flags/responsible_apis.aconfig new file mode 100644 index 000000000000..4bfb17700a76 --- /dev/null +++ b/core/java/android/window/flags/responsible_apis.aconfig @@ -0,0 +1,22 @@ +package: "com.android.window.flags" + +flag { + name: "bal_require_opt_in_by_pending_intent_creator" + namespace: "responsible_apis" + description: "Require the PendingIntent creator to opt in starting with Android 15" + bug: "296478951" +} + +flag { + name: "bal_dont_bring_existing_background_task_stack_to_fg" + namespace: "responsible_apis" + description: "When starting a PendingIntent with ONLY creator privileges, don't bring the existing task stack to foreground" + bug: "296478675" +} + +flag { + name: "bal_show_toasts" + namespace: "responsible_apis" + description: "Enable toasts to indicate (potential) BAL blocking." + bug: "308059069" +}
\ 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/android/window/flags/window_surfaces.aconfig b/core/java/android/window/flags/window_surfaces.aconfig index ccbf4a9b3d21..5ad5c79f2d42 100644 --- a/core/java/android/window/flags/window_surfaces.aconfig +++ b/core/java/android/window/flags/window_surfaces.aconfig @@ -17,3 +17,11 @@ flag { is_fixed_read_only: true bug: "300019131" } + +flag { + namespace: "window_surfaces" + name: "get_host_token_api" + description: "Feature flag to associate the host and embedded windows" + is_fixed_read_only: true + bug: "304508760" +} diff --git a/core/java/com/android/internal/accessibility/AccessibilityShortcutController.java b/core/java/com/android/internal/accessibility/AccessibilityShortcutController.java index 2efe44544f37..de0f070b01a3 100644 --- a/core/java/com/android/internal/accessibility/AccessibilityShortcutController.java +++ b/core/java/com/android/internal/accessibility/AccessibilityShortcutController.java @@ -53,10 +53,13 @@ import android.util.Slog; import android.view.Window; import android.view.WindowManager; import android.view.accessibility.AccessibilityManager; +import android.view.accessibility.Flags; import android.widget.Toast; import com.android.internal.R; +import com.android.internal.accessibility.common.ShortcutConstants; import com.android.internal.accessibility.dialog.AccessibilityTarget; +import com.android.internal.accessibility.util.ShortcutUtils; import com.android.internal.util.function.pooled.PooledLambda; import java.lang.annotation.Retention; @@ -66,6 +69,7 @@ import java.util.Collections; import java.util.List; import java.util.Locale; import java.util.Map; +import java.util.Set; /** * Class to help manage the accessibility shortcut key @@ -364,9 +368,23 @@ public class AccessibilityShortcutController { }) .setPositiveButton(R.string.accessibility_shortcut_off, (DialogInterface d, int which) -> { - Settings.Secure.putStringForUser(mContext.getContentResolver(), - Settings.Secure.ACCESSIBILITY_SHORTCUT_TARGET_SERVICE, "", - userId); + if (Flags.updateAlwaysOnA11yService()) { + Set<String> targetServices = + ShortcutUtils.getShortcutTargetsFromSettings( + mContext, + ShortcutConstants.UserShortcutType.HARDWARE, + userId); + + Settings.Secure.putStringForUser(mContext.getContentResolver(), + Settings.Secure.ACCESSIBILITY_SHORTCUT_TARGET_SERVICE, "", + userId); + ShortcutUtils.updateInvisibleToggleAccessibilityServiceEnableState( + mContext, targetServices, userId); + } else { + Settings.Secure.putStringForUser(mContext.getContentResolver(), + Settings.Secure.ACCESSIBILITY_SHORTCUT_TARGET_SERVICE, "", + userId); + } // If canceled, treat as if the dialog has never been shown Settings.Secure.putIntForUser(mContext.getContentResolver(), diff --git a/core/java/com/android/internal/accessibility/common/ShortcutConstants.java b/core/java/com/android/internal/accessibility/common/ShortcutConstants.java index e6360048706b..7ec8838699b3 100644 --- a/core/java/com/android/internal/accessibility/common/ShortcutConstants.java +++ b/core/java/com/android/internal/accessibility/common/ShortcutConstants.java @@ -60,6 +60,17 @@ public final class ShortcutConstants { } /** + * A list of possible {@link UserShortcutType}. Should stay in sync with the + * non-default IntDef types. + */ + public static final int[] USER_SHORTCUT_TYPES = { + UserShortcutType.SOFTWARE, + UserShortcutType.HARDWARE, + UserShortcutType.TRIPLETAP + }; + + + /** * Annotation for the different accessibility fragment type. * * {@code VOLUME_SHORTCUT_TOGGLE} for displaying appearance with switch bar and only one diff --git a/core/java/com/android/internal/accessibility/dialog/InvisibleToggleAccessibilityServiceTarget.java b/core/java/com/android/internal/accessibility/dialog/InvisibleToggleAccessibilityServiceTarget.java index 9d5c374e98f5..1bc8b84e6869 100644 --- a/core/java/com/android/internal/accessibility/dialog/InvisibleToggleAccessibilityServiceTarget.java +++ b/core/java/com/android/internal/accessibility/dialog/InvisibleToggleAccessibilityServiceTarget.java @@ -27,17 +27,25 @@ import android.accessibilityservice.AccessibilityServiceInfo; import android.annotation.NonNull; import android.content.ComponentName; import android.content.Context; +import android.os.UserHandle; import android.view.accessibility.AccessibilityManager.ShortcutType; +import android.view.accessibility.Flags; import com.android.internal.accessibility.common.ShortcutConstants.AccessibilityFragmentType; +import com.android.internal.accessibility.util.ShortcutUtils; +import com.android.internal.annotations.VisibleForTesting; + +import java.util.Set; /** * Extension for {@link AccessibilityServiceTarget} with * {@link AccessibilityFragmentType#INVISIBLE_TOGGLE} type. */ -class InvisibleToggleAccessibilityServiceTarget extends AccessibilityServiceTarget { +@VisibleForTesting(visibility = VisibleForTesting.Visibility.PACKAGE) +public class InvisibleToggleAccessibilityServiceTarget extends AccessibilityServiceTarget { - InvisibleToggleAccessibilityServiceTarget(Context context, @ShortcutType int shortcutType, + public InvisibleToggleAccessibilityServiceTarget( + Context context, @ShortcutType int shortcutType, @NonNull AccessibilityServiceInfo serviceInfo) { super(context, shortcutType, @@ -49,11 +57,17 @@ class InvisibleToggleAccessibilityServiceTarget extends AccessibilityServiceTarg public void onCheckedChanged(boolean isChecked) { final ComponentName componentName = ComponentName.unflattenFromString(getId()); - if (!isComponentIdExistingInOtherShortcut()) { - setAccessibilityServiceState(getContext(), componentName, isChecked); - } + if (Flags.updateAlwaysOnA11yService()) { + super.onCheckedChanged(isChecked); + ShortcutUtils.updateInvisibleToggleAccessibilityServiceEnableState( + getContext(), Set.of(componentName.flattenToString()), UserHandle.myUserId()); + } else { + if (!isComponentIdExistingInOtherShortcut()) { + setAccessibilityServiceState(getContext(), componentName, isChecked); + } - super.onCheckedChanged(isChecked); + super.onCheckedChanged(isChecked); + } } private boolean isComponentIdExistingInOtherShortcut() { diff --git a/core/java/com/android/internal/accessibility/util/ShortcutUtils.java b/core/java/com/android/internal/accessibility/util/ShortcutUtils.java index 31ccb6c32bab..3fd303038c57 100644 --- a/core/java/com/android/internal/accessibility/util/ShortcutUtils.java +++ b/core/java/com/android/internal/accessibility/util/ShortcutUtils.java @@ -15,20 +15,29 @@ */ package com.android.internal.accessibility.util; + import static android.view.accessibility.AccessibilityManager.ACCESSIBILITY_BUTTON; import static android.view.accessibility.AccessibilityManager.ACCESSIBILITY_SHORTCUT_KEY; +import static com.android.internal.accessibility.AccessibilityShortcutController.MAGNIFICATION_CONTROLLER_NAME; +import static com.android.internal.accessibility.common.ShortcutConstants.AccessibilityFragmentType.INVISIBLE_TOGGLE; import static com.android.internal.accessibility.common.ShortcutConstants.SERVICES_SEPARATOR; +import static com.android.internal.accessibility.common.ShortcutConstants.USER_SHORTCUT_TYPES; import static com.android.internal.accessibility.common.ShortcutConstants.UserShortcutType; +import android.accessibilityservice.AccessibilityServiceInfo; import android.annotation.NonNull; +import android.content.ComponentName; import android.content.Context; import android.provider.Settings; import android.text.TextUtils; +import android.util.ArraySet; import android.view.accessibility.AccessibilityManager; import android.view.accessibility.AccessibilityManager.ShortcutType; +import java.util.Collections; import java.util.List; +import java.util.Set; import java.util.StringJoiner; /** @@ -180,4 +189,92 @@ public final class ShortcutUtils { "Unsupported shortcut type:" + type); } } + + /** + * Updates an accessibility state if the accessibility service is a Always-On a11y service, + * a.k.a. AccessibilityServices that has FLAG_REQUEST_ACCESSIBILITY_BUTTON + * <p> + * Turn on the accessibility service when there is any shortcut associated to it. + * <p> + * Turn off the accessibility service when there is no shortcut associated to it. + * + * @param componentNames the a11y shortcut target's component names + */ + public static void updateInvisibleToggleAccessibilityServiceEnableState( + Context context, Set<String> componentNames, int userId) { + final AccessibilityManager am = (AccessibilityManager) context.getSystemService( + Context.ACCESSIBILITY_SERVICE); + if (am == null) return; + + final List<AccessibilityServiceInfo> installedServices = + am.getInstalledAccessibilityServiceList(); + + final Set<String> invisibleToggleServices = new ArraySet<>(); + for (AccessibilityServiceInfo serviceInfo : installedServices) { + if (AccessibilityUtils.getAccessibilityServiceFragmentType(serviceInfo) + == INVISIBLE_TOGGLE) { + invisibleToggleServices.add(serviceInfo.getComponentName().flattenToString()); + } + } + + final Set<String> servicesWithShortcuts = new ArraySet<>(); + for (int shortcutType: USER_SHORTCUT_TYPES) { + // The call to update always-on service might modify the shortcut setting right before + // calling #updateAccessibilityServiceStateIfNeeded in the same call. + // To avoid getting the shortcut target from out-dated value, use values from Settings + // instead. + servicesWithShortcuts.addAll( + getShortcutTargetsFromSettings(context, shortcutType, userId)); + } + + for (String componentName : componentNames) { + // Only needs to update the Always-On A11yService's state when the shortcut changes. + if (invisibleToggleServices.contains(componentName)) { + + boolean enableA11yService = servicesWithShortcuts.contains(componentName); + AccessibilityUtils.setAccessibilityServiceState( + context, + ComponentName.unflattenFromString(componentName), enableA11yService); + } + } + } + + /** + * Returns the target component names of a given user shortcut type from Settings. + * + * <p> + * Note: grab shortcut targets from Settings is only needed + * if you depends on a value being set in the same call. + * For example, you disable a single shortcut, + * and you're checking if there is any shortcut remaining. + * + * <p> + * If you just want to know the current state, you can use + * {@link AccessibilityManager#getAccessibilityShortcutTargets(int)} + */ + public static Set<String> getShortcutTargetsFromSettings( + Context context, @UserShortcutType int shortcutType, int userId) { + final String targetKey = convertToKey(shortcutType); + if (Settings.Secure.ACCESSIBILITY_DISPLAY_MAGNIFICATION_ENABLED.equals(targetKey)) { + boolean magnificationEnabled = Settings.Secure.getIntForUser( + context.getContentResolver(), targetKey, /* def= */ 0, userId) == 1; + return magnificationEnabled ? Set.of(MAGNIFICATION_CONTROLLER_NAME) + : Collections.emptySet(); + + } else { + final String targetString = Settings.Secure.getStringForUser( + context.getContentResolver(), targetKey, userId); + + if (TextUtils.isEmpty(targetString)) { + return Collections.emptySet(); + } + + Set<String> targets = new ArraySet<>(); + sStringColonSplitter.setString(targetString); + while (sStringColonSplitter.hasNext()) { + targets.add(sStringColonSplitter.next()); + } + return Collections.unmodifiableSet(targets); + } + } } diff --git a/core/java/com/android/internal/app/IAppOpsService.aidl b/core/java/com/android/internal/app/IAppOpsService.aidl index 492e2ac7cc28..1b05982a7569 100644 --- a/core/java/com/android/internal/app/IAppOpsService.aidl +++ b/core/java/com/android/internal/app/IAppOpsService.aidl @@ -42,18 +42,22 @@ import com.android.internal.app.MessageSamplingConfig; // frameworks/native/libs/permission/include/binder/IAppOpsService.h must match the order here. // Please be careful to respect both these issues when modifying this file. interface IAppOpsService { - // These methods are also called by native code, so please be careful that the number in - // frameworks/native/libs/permission/include/binder/IAppOpsService.h matches the ordering here. + // Deprecated, use checkOperationWithState instead. int checkOperation(int code, int uid, String packageName); + // Deprecated, use noteOperationWithState instead. SyncNotedAppOp noteOperation(int code, int uid, String packageName, @nullable String attributionTag, boolean shouldCollectAsyncNotedOp, String message, boolean shouldCollectMessage); + // Deprecated, use startOperationWithState instead. SyncNotedAppOp startOperation(IBinder clientId, int code, int uid, String packageName, @nullable String attributionTag, boolean startIfModeDefault, boolean shouldCollectAsyncNotedOp, String message, boolean shouldCollectMessage, int attributionFlags, int attributionChainId); + // Deprecated, use finishOperationWithState instead. @UnsupportedAppUsage void finishOperation(IBinder clientId, int code, int uid, String packageName, @nullable String attributionTag); + // These methods are also called by native code, so please be careful that the number in + // frameworks/native/libs/permission/include/binder/IAppOpsService.h matches the ordering here. void startWatchingMode(int op, String packageName, IAppOpsCallback callback); void stopWatchingMode(IAppOpsCallback callback); int permissionToOpCode(String permission); @@ -134,20 +138,33 @@ interface IAppOpsService { void stopWatchingAsyncNoted(String packageName, IAppOpsAsyncNotedCallback callback); List<AsyncNotedAppOp> extractAsyncOps(String packageName); + // Deprecated, use checkOperationWithStateRaw instead. int checkOperationRaw(int code, int uid, String packageName, @nullable String attributionTag); void reloadNonHistoricalState(); void collectNoteOpCallsForValidation(String stackTrace, int op, String packageName, long version); - + // These methods are also called by native code, so please be careful that the number in + // frameworks/native/libs/permission/include/binder/IAppOpsService.h matches the ordering here. + int checkOperationWithState(int code, in AttributionSourceState attributionSourceState); + int checkOperationWithStateRaw(int code, in AttributionSourceState attributionSourceState); + SyncNotedAppOp noteOperationWithState(int code, in AttributionSourceState attributionSourceState, + boolean shouldCollectAsyncNotedOp, String message, boolean shouldCollectMessage); + SyncNotedAppOp startOperationWithState(IBinder clientId, int code, + in AttributionSourceState attributionSourceState, boolean startIfModeDefault, + boolean shouldCollectAsyncNotedOp, String message, boolean shouldCollectMessage, + int attributionFlags, int attributionChainId); + void finishOperationWithState(IBinder clientId, int code, in AttributionSourceState attributionSourceState); + // End of methods also called by native code (there may be more blocks like this of native + // methods later in this file). SyncNotedAppOp noteProxyOperationWithState(int code, - in AttributionSourceState attributionSourceStateState, - boolean shouldCollectAsyncNotedOp, String message, boolean shouldCollectMessage, - boolean skipProxyOperation); + in AttributionSourceState attributionSourceStateState, + boolean shouldCollectAsyncNotedOp, String message, boolean shouldCollectMessage, + boolean skipProxyOperation); SyncNotedAppOp startProxyOperationWithState(IBinder clientId, int code, - in AttributionSourceState attributionSourceStateState, boolean startIfModeDefault, - boolean shouldCollectAsyncNotedOp, String message, boolean shouldCollectMessage, - boolean skipProxyOperation, int proxyAttributionFlags, int proxiedAttributionFlags, - int attributionChainId); + in AttributionSourceState attributionSourceStateState, boolean startIfModeDefault, + boolean shouldCollectAsyncNotedOp, String message, boolean shouldCollectMessage, + boolean skipProxyOperation, int proxyAttributionFlags, int proxiedAttributionFlags, + int attributionChainId); void finishProxyOperationWithState(IBinder clientId, int code, - in AttributionSourceState attributionSourceStateState, boolean skipProxyOperation); + in AttributionSourceState attributionSourceStateState, boolean skipProxyOperation); } 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/content/PackageMonitor.java b/core/java/com/android/internal/content/PackageMonitor.java index 0b69030d384f..9d88a2341fad 100644 --- a/core/java/com/android/internal/content/PackageMonitor.java +++ b/core/java/com/android/internal/content/PackageMonitor.java @@ -401,6 +401,12 @@ public abstract class PackageMonitor extends android.content.BroadcastReceiver { if (intent.getBooleanExtra(Intent.EXTRA_REPLACING, false)) { mChangeType = PACKAGE_UPDATING; onPackageUpdateStarted(pkg, uid); + if (intent.getBooleanExtra(Intent.EXTRA_ARCHIVAL, false)) { + // In case it is a removal event due to archiving, we trigger package + // update event to refresh details like icons, title etc. corresponding to + // the archived app. + onPackageModified(pkg); + } } else { mChangeType = PACKAGE_PERMANENT_CHANGE; // We only consider something to have changed if this is 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/drawable/archived_app_cloud_overlay.xml b/core/res/res/drawable/archived_app_cloud_overlay.xml new file mode 100644 index 000000000000..611e0f39bb5c --- /dev/null +++ b/core/res/res/drawable/archived_app_cloud_overlay.xml @@ -0,0 +1,15 @@ +<vector xmlns:android="http://schemas.android.com/apk/res/android" + android:width="20dp" + android:height="20dp" + android:viewportWidth="60" + android:viewportHeight="60"> + <group + android:scaleX="1.2" + android:scaleY="1.2" + android:translateX="15" + android:translateY="14"> + <path + android:fillColor="@android:color/white" + android:pathData="M19.35,10.04C18.67,6.59 15.64,4 12,4 9.11,4 6.6,5.64 5.35,8.04 2.34,8.36 0,10.91 0,14c0,3.31 2.69,6 6,6h13c2.76,0 5,-2.24 5,-5 0,-2.64 -2.05,-4.78 -4.65,-4.96zM19,18L6,18c-2.21,0 -4,-1.79 -4,-4 0,-2.05 1.53,-3.76 3.56,-3.97l1.07,-0.11 0.5,-0.95C8.08,7.14 9.94,6 12,6c2.62,0 4.88,1.86 5.39,4.43l0.3,1.5 1.53,0.11c1.56,0.1 2.78,1.41 2.78,2.96 0,1.65 -1.35,3 -3,3zM13.45,10h-2.9v3L8,13l4,4 4,-4h-2.55z"/> + </group> +</vector>
\ No newline at end of file diff --git a/core/res/res/values/symbols.xml b/core/res/res/values/symbols.xml index 14bbb966f750..1aa1fea95049 100644 --- a/core/res/res/values/symbols.xml +++ b/core/res/res/values/symbols.xml @@ -1405,6 +1405,7 @@ <java-symbol type="drawable" name="ic_test_badge_no_background" /> <java-symbol type="drawable" name="ic_test_icon_badge_experiment" /> <java-symbol type="drawable" name="ic_instant_icon_badge_bolt" /> + <java-symbol type="drawable" name="archived_app_cloud_overlay" /> <java-symbol type="drawable" name="emulator_circular_window_overlay" /> <java-symbol type="drawable" name="ic_qs_battery_saver" /> <java-symbol type="drawable" name="ic_qs_bluetooth" /> diff --git a/core/tests/coretests/src/android/app/OWNERS b/core/tests/coretests/src/android/app/OWNERS index 64f5e6c68a95..5636f9bc436c 100644 --- a/core/tests/coretests/src/android/app/OWNERS +++ b/core/tests/coretests/src/android/app/OWNERS @@ -10,3 +10,7 @@ per-file *UiAutomation* = file:/services/accessibility/OWNERS # KeyguardManagerTest per-file KeyguardManagerTest.java = file:/services/core/java/com/android/server/locksettings/OWNERS + +# Files related to background activity launches +per-file Background*Start* = file:/BAL_OWNERS + 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/ViewRootImplTest.java b/core/tests/coretests/src/android/view/ViewRootImplTest.java index 6a9fc04230f8..40fd34e7d072 100644 --- a/core/tests/coretests/src/android/view/ViewRootImplTest.java +++ b/core/tests/coretests/src/android/view/ViewRootImplTest.java @@ -48,6 +48,9 @@ import android.hardware.display.DisplayManagerGlobal; import android.os.Binder; import android.os.SystemProperties; import android.platform.test.annotations.Presubmit; +import android.platform.test.annotations.RequiresFlagsEnabled; +import android.platform.test.flag.junit.CheckFlagsRule; +import android.platform.test.flag.junit.DeviceFlagsValueProvider; import android.platform.test.flag.junit.SetFlagsRule; import android.provider.Settings; import android.util.Log; @@ -60,6 +63,7 @@ import androidx.test.filters.SmallTest; import androidx.test.platform.app.InstrumentationRegistry; import com.android.compatibility.common.util.ShellIdentityUtils; +import com.android.window.flags.Flags; import org.junit.After; import org.junit.AfterClass; @@ -97,6 +101,9 @@ public class ViewRootImplTest { // state after the test completes. private static boolean sOriginalTouchMode; + @Rule + public final CheckFlagsRule mCheckFlagsRule = DeviceFlagsValueProvider.createCheckFlagsRule(); + @BeforeClass public static void setUpClass() { sContext = sInstrumentation.getTargetContext(); @@ -338,6 +345,19 @@ public class ViewRootImplTest { assertThat(view.hasWindowFocus()).isFalse(); } + @Test + @RequiresFlagsEnabled(Flags.FLAG_GET_HOST_TOKEN_API) + public void whenViewIsAttachedToWindow_getHostToken() { + View view = new View(sContext); + attachViewToWindow(view); + + mViewRootImpl = view.getViewRootImpl(); + + assertThat(mViewRootImpl.getHostToken()).isNotEqualTo(null); + assertThat(mViewRootImpl.getHostToken()) + .isEqualTo(mViewRootImpl.getInputToken()); + } + /** * When window doesn't have focus, keys should be dropped. */ 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/core/tests/coretests/src/com/android/internal/accessibility/AccessibilityShortcutControllerTest.java b/core/tests/coretests/src/com/android/internal/accessibility/AccessibilityShortcutControllerTest.java index cd5ec851e9eb..75b0d4a159d9 100644 --- a/core/tests/coretests/src/com/android/internal/accessibility/AccessibilityShortcutControllerTest.java +++ b/core/tests/coretests/src/com/android/internal/accessibility/AccessibilityShortcutControllerTest.java @@ -16,9 +16,11 @@ package com.android.internal.accessibility; +import static android.provider.Settings.Secure.ACCESSIBILITY_BUTTON_TARGETS; import static android.provider.Settings.Secure.ACCESSIBILITY_SHORTCUT_DIALOG_SHOWN; import static android.provider.Settings.Secure.ACCESSIBILITY_SHORTCUT_ON_LOCK_SCREEN; import static android.provider.Settings.Secure.ACCESSIBILITY_SHORTCUT_TARGET_SERVICE; +import static android.provider.Settings.Secure.ENABLED_ACCESSIBILITY_SERVICES; import static android.view.accessibility.AccessibilityManager.ACCESSIBILITY_SHORTCUT_KEY; import static com.android.internal.accessibility.AccessibilityShortcutController.ACCESSIBILITY_HEARING_AIDS_COMPONENT_NAME; @@ -62,6 +64,9 @@ import android.os.Build; import android.os.Handler; import android.os.Message; import android.os.Vibrator; +import android.platform.test.annotations.RequiresFlagsEnabled; +import android.platform.test.flag.junit.CheckFlagsRule; +import android.platform.test.flag.junit.DeviceFlagsValueProvider; import android.provider.Settings; import android.speech.tts.TextToSpeech; import android.speech.tts.Voice; @@ -69,6 +74,7 @@ import android.test.mock.MockContentResolver; import android.view.Window; import android.view.WindowManager; import android.view.accessibility.AccessibilityManager; +import android.view.accessibility.Flags; import android.view.accessibility.IAccessibilityManager; import android.widget.Toast; @@ -81,6 +87,7 @@ import com.android.internal.util.test.FakeSettingsProvider; import org.junit.AfterClass; import org.junit.Before; +import org.junit.Rule; import org.junit.Test; import org.junit.runner.RunWith; import org.mockito.ArgumentCaptor; @@ -96,6 +103,9 @@ import java.util.Set; @RunWith(AndroidJUnit4.class) public class AccessibilityShortcutControllerTest { + @Rule + public final CheckFlagsRule mCheckFlagsRule = DeviceFlagsValueProvider.createCheckFlagsRule(); + private static final String SERVICE_NAME_STRING = "fake.package/fake.service.name"; private static final CharSequence PACKAGE_NAME_STRING = "Service name"; private static final String SERVICE_NAME_SUMMARY = "Summary"; @@ -430,6 +440,43 @@ public class AccessibilityShortcutControllerTest { } @Test + @RequiresFlagsEnabled(Flags.FLAG_UPDATE_ALWAYS_ON_A11Y_SERVICE) + public void turnOffVolumeShortcutForAlwaysOnA11yService_shouldTurnOffA11yService() + throws Exception { + configureApplicationTargetSdkVersion(Build.VERSION_CODES.R); + turnOffVolumeKeyShortcutForA11yService(/* alwaysOnService= */ true); + + assertThat( + Settings.Secure.getString(mContentResolver, ENABLED_ACCESSIBILITY_SERVICES) + ).isEmpty(); + } + + @Test + @RequiresFlagsEnabled(Flags.FLAG_UPDATE_ALWAYS_ON_A11Y_SERVICE) + public void turnOffVolumeShortcutForAlwaysOnA11yService_hasOtherTypesShortcut_shouldNotTurnOffA11yService() + throws Exception { + configureApplicationTargetSdkVersion(Build.VERSION_CODES.R); + Settings.Secure.putString( + mContentResolver, ACCESSIBILITY_BUTTON_TARGETS, SERVICE_NAME_STRING); + + turnOffVolumeKeyShortcutForA11yService(/* alwaysOnService= */ true); + + assertThat( + Settings.Secure.getString(mContentResolver, ENABLED_ACCESSIBILITY_SERVICES) + ).isEqualTo(SERVICE_NAME_STRING); + } + + @Test + public void turnOffVolumeShortcutForStandardA11yService_shouldNotTurnOffA11yService() + throws Exception { + turnOffVolumeKeyShortcutForA11yService(/* alwaysOnService= */ false); + + assertThat( + Settings.Secure.getString(mContentResolver, ENABLED_ACCESSIBILITY_SERVICES) + ).isEqualTo(SERVICE_NAME_STRING); + } + + @Test public void testClickingTurnOnButtonInDialog_shouldLeaveShortcutReady() throws Exception { configureShortcutEnabled(ENABLED_EXCEPT_LOCK_SCREEN); configureValidShortcutService(); @@ -746,6 +793,8 @@ public class AccessibilityShortcutControllerTest { private void configureEnabledService() throws Exception { when(mAccessibilityManagerService.getEnabledAccessibilityServiceList(anyInt(), anyInt())) .thenReturn(Collections.singletonList(mServiceInfo)); + Settings.Secure.putString( + mContentResolver, ENABLED_ACCESSIBILITY_SERVICES, SERVICE_NAME_STRING); } private AccessibilityShortcutController getController() { @@ -763,4 +812,21 @@ public class AccessibilityShortcutControllerTest { when(mResources.getString(R.string.config_defaultAccessibilityService)).thenReturn( SERVICE_NAME_STRING); } + + private void turnOffVolumeKeyShortcutForA11yService(boolean alwaysOnService) throws Exception { + configureValidShortcutService(); + Settings.Secure.putInt(mContentResolver, ACCESSIBILITY_SHORTCUT_DIALOG_SHOWN, + AccessibilityShortcutController.DialogStatus.NOT_SHOWN); + if (alwaysOnService) { + configureRequestAccessibilityButton(); + } + configureEnabledService(); + getController().performAccessibilityShortcut(); + + ArgumentCaptor<DialogInterface.OnClickListener> captor = + ArgumentCaptor.forClass(DialogInterface.OnClickListener.class); + verify(mAlertDialogBuilder).setPositiveButton(eq(R.string.accessibility_shortcut_off), + captor.capture()); + captor.getValue().onClick(null, DialogInterface.BUTTON_POSITIVE); + } } diff --git a/core/tests/coretests/src/com/android/internal/accessibility/TestUtils.java b/core/tests/coretests/src/com/android/internal/accessibility/TestUtils.java index ff014add793a..1bb03fcc99e5 100644 --- a/core/tests/coretests/src/com/android/internal/accessibility/TestUtils.java +++ b/core/tests/coretests/src/com/android/internal/accessibility/TestUtils.java @@ -16,6 +16,17 @@ package com.android.internal.accessibility; +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.when; + +import android.accessibilityservice.AccessibilityServiceInfo; +import android.content.ComponentName; +import android.content.pm.ApplicationInfo; +import android.content.pm.ResolveInfo; +import android.content.pm.ServiceInfo; +import android.os.Build; + import com.android.internal.os.RoSystemProperties; import java.lang.reflect.Field; @@ -38,4 +49,32 @@ public class TestUtils { throw new RuntimeException(e); } } + + /** + * Creates fake accessibility service info. + */ + public static AccessibilityServiceInfo createFakeServiceInfo( + String packageLabel, String serviceComponent, + String serviceSummary, boolean isAlwaysOnService) { + ApplicationInfo applicationInfo = mock(ApplicationInfo.class); + applicationInfo.targetSdkVersion = Build.VERSION_CODES.R; + ServiceInfo serviceInfo = mock(ServiceInfo.class); + ResolveInfo resolveInfo = mock(ResolveInfo.class); + resolveInfo.serviceInfo = serviceInfo; + resolveInfo.serviceInfo.applicationInfo = applicationInfo; + when(resolveInfo.loadLabel(any())).thenReturn(packageLabel); + + AccessibilityServiceInfo a11yServiceInfo = mock(AccessibilityServiceInfo.class); + when(a11yServiceInfo.getResolveInfo()).thenReturn(resolveInfo); + when(a11yServiceInfo.getComponentName()) + .thenReturn(ComponentName.unflattenFromString(serviceComponent)); + when(a11yServiceInfo.loadSummary(any())).thenReturn(serviceSummary); + + if (isAlwaysOnService) { + a11yServiceInfo.flags |= AccessibilityServiceInfo + .FLAG_REQUEST_ACCESSIBILITY_BUTTON; + } + + return a11yServiceInfo; + } } diff --git a/core/tests/coretests/src/com/android/internal/accessibility/dialog/InvisibleToggleAccessibilityServiceTargetTest.java b/core/tests/coretests/src/com/android/internal/accessibility/dialog/InvisibleToggleAccessibilityServiceTargetTest.java new file mode 100644 index 000000000000..69b6a9b7aa87 --- /dev/null +++ b/core/tests/coretests/src/com/android/internal/accessibility/dialog/InvisibleToggleAccessibilityServiceTargetTest.java @@ -0,0 +1,182 @@ +/* + * Copyright 2023 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.internal.accessibility.dialog; + +import static com.google.common.truth.Truth.assertThat; + +import static org.mockito.ArgumentMatchers.anyInt; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.spy; +import static org.mockito.Mockito.when; + +import android.accessibilityservice.AccessibilityServiceInfo; +import android.content.ContentResolver; +import android.content.Context; +import android.content.ContextWrapper; +import android.content.pm.ParceledListSlice; +import android.os.Handler; +import android.os.RemoteException; +import android.os.UserHandle; +import android.provider.Settings; +import android.view.accessibility.AccessibilityManager; +import android.view.accessibility.IAccessibilityManager; + +import androidx.test.platform.app.InstrumentationRegistry; +import androidx.test.runner.AndroidJUnit4; + +import com.android.internal.accessibility.TestUtils; +import com.android.internal.util.test.FakeSettingsProvider; +import com.android.internal.util.test.FakeSettingsProviderRule; + +import org.junit.Before; +import org.junit.Rule; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.mockito.Mock; +import org.mockito.MockitoAnnotations; + +import java.util.Collections; + +/** + * Unit Tests for + * {@link com.android.internal.accessibility.dialog.InvisibleToggleAccessibilityServiceTarget} + */ +@RunWith(AndroidJUnit4.class) +public class InvisibleToggleAccessibilityServiceTargetTest { + @Rule + public FakeSettingsProviderRule mSettingsProviderRule = FakeSettingsProvider.rule(); + @Mock + private IAccessibilityManager mAccessibilityManagerService; + + private static final String ALWAYS_ON_SERVICE_PACKAGE_LABEL = "always on a11y service"; + private static final String ALWAYS_ON_SERVICE_COMPONENT_NAME = + "fake.package/fake.alwayson.service.name"; + private static final String FAKE_A11Y_SERVICE_SUMMARY = "A11yService summary"; + + private ContextWrapper mContextSpy; + private InvisibleToggleAccessibilityServiceTarget mSut; + + @Before + public void setUp() throws RemoteException { + MockitoAnnotations.initMocks(this); + mContextSpy = spy( + new ContextWrapper(InstrumentationRegistry.getInstrumentation().getContext())); + + ContentResolver contentResolver = mSettingsProviderRule.mockContentResolver(mContextSpy); + when(mContextSpy.getContentResolver()).thenReturn(contentResolver); + + AccessibilityManager accessibilityManager = + new AccessibilityManager( + mContextSpy, mock(Handler.class), + mAccessibilityManagerService, UserHandle.myUserId(), + /* serviceConnect= */ true); + when(mContextSpy.getSystemService(Context.ACCESSIBILITY_SERVICE)) + .thenReturn(accessibilityManager); + + AccessibilityServiceInfo accessibilityServiceInfo = TestUtils.createFakeServiceInfo( + ALWAYS_ON_SERVICE_PACKAGE_LABEL, + ALWAYS_ON_SERVICE_COMPONENT_NAME, + FAKE_A11Y_SERVICE_SUMMARY, + /* isAlwaysOnService*/ true); + when(mAccessibilityManagerService.getInstalledAccessibilityServiceList(anyInt())) + .thenReturn( + new ParceledListSlice<>( + Collections.singletonList(accessibilityServiceInfo))); + + mSut = new InvisibleToggleAccessibilityServiceTarget( + mContextSpy, + AccessibilityManager.ACCESSIBILITY_SHORTCUT_KEY, accessibilityServiceInfo); + } + + @Test + public void onCheckedChanged_turnOnShortcut_hasOtherShortcut_serviceKeepsOn() { + enableA11yService(/* enable= */ true); + addShortcutForA11yService( + Settings.Secure.ACCESSIBILITY_SHORTCUT_TARGET_SERVICE, /* add= */ false); + addShortcutForA11yService(Settings.Secure.ACCESSIBILITY_BUTTON_TARGETS, /* add= */ true); + + mSut.onCheckedChanged(/* isChecked= */ true); + + assertA11yServiceState(/* enabled= */ true); + } + + @Test + public void onCheckedChanged_turnOnShortcut_noOtherShortcut_shouldTurnOnService() { + enableA11yService(/* enable= */ false); + addShortcutForA11yService( + Settings.Secure.ACCESSIBILITY_SHORTCUT_TARGET_SERVICE, /* add= */ false); + addShortcutForA11yService(Settings.Secure.ACCESSIBILITY_BUTTON_TARGETS, /* add= */ false); + + mSut.onCheckedChanged(/* isChecked= */ true); + + assertA11yServiceState(/* enabled= */ true); + } + + @Test + public void onCheckedChanged_turnOffShortcut_hasOtherShortcut_serviceKeepsOn() { + enableA11yService(/* enable= */ true); + addShortcutForA11yService( + Settings.Secure.ACCESSIBILITY_SHORTCUT_TARGET_SERVICE, /* add= */ true); + addShortcutForA11yService(Settings.Secure.ACCESSIBILITY_BUTTON_TARGETS, /* add= */ true); + + mSut.onCheckedChanged(/* isChecked= */ false); + + assertA11yServiceState(/* enabled= */ true); + } + + @Test + public void onCheckedChanged_turnOffShortcut_noOtherShortcut_shouldTurnOffService() { + enableA11yService(/* enable= */ true); + addShortcutForA11yService( + Settings.Secure.ACCESSIBILITY_SHORTCUT_TARGET_SERVICE, /* add= */ true); + addShortcutForA11yService(Settings.Secure.ACCESSIBILITY_BUTTON_TARGETS, /* add= */ false); + + mSut.onCheckedChanged(/* isChecked= */ false); + + assertA11yServiceState(/* enabled= */ false); + } + + private void enableA11yService(boolean enable) { + Settings.Secure.putString( + mContextSpy.getContentResolver(), + Settings.Secure.ENABLED_ACCESSIBILITY_SERVICES, + enable ? ALWAYS_ON_SERVICE_COMPONENT_NAME : ""); + } + + private void addShortcutForA11yService(String shortcutKey, boolean add) { + Settings.Secure.putString( + mContextSpy.getContentResolver(), + shortcutKey, + add ? ALWAYS_ON_SERVICE_COMPONENT_NAME : ""); + } + + private void assertA11yServiceState(boolean enabled) { + if (enabled) { + assertThat( + Settings.Secure.getString( + mContextSpy.getContentResolver(), + Settings.Secure.ENABLED_ACCESSIBILITY_SERVICES) + ).contains(ALWAYS_ON_SERVICE_COMPONENT_NAME); + } else { + assertThat( + Settings.Secure.getString( + mContextSpy.getContentResolver(), + Settings.Secure.ENABLED_ACCESSIBILITY_SERVICES) + ).doesNotContain(ALWAYS_ON_SERVICE_COMPONENT_NAME); + } + } +} diff --git a/core/tests/coretests/src/com/android/internal/accessibility/AccessibilityUtilsTest.java b/core/tests/coretests/src/com/android/internal/accessibility/util/AccessibilityUtilsTest.java index 3ea7f471e4bd..58ab92af7dbd 100644 --- a/core/tests/coretests/src/com/android/internal/accessibility/AccessibilityUtilsTest.java +++ b/core/tests/coretests/src/com/android/internal/accessibility/util/AccessibilityUtilsTest.java @@ -1,5 +1,5 @@ /* - * Copyright (C) 2021 The Android Open Source Project + * Copyright 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. @@ -14,7 +14,7 @@ * limitations under the License. */ -package com.android.internal.accessibility; +package com.android.internal.accessibility.util; import static com.android.internal.accessibility.util.AccessibilityUtils.ACCESSIBILITY_MENU_IN_SYSTEM; import static com.android.internal.accessibility.util.AccessibilityUtils.MENU_SERVICE_RELATIVE_CLASS_NAME; @@ -35,8 +35,6 @@ import android.text.style.LocaleSpan; import androidx.test.runner.AndroidJUnit4; -import com.android.internal.accessibility.util.AccessibilityUtils; - import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; diff --git a/core/tests/coretests/src/com/android/internal/accessibility/util/ShortcutUtilsTest.java b/core/tests/coretests/src/com/android/internal/accessibility/util/ShortcutUtilsTest.java new file mode 100644 index 000000000000..708f246fea75 --- /dev/null +++ b/core/tests/coretests/src/com/android/internal/accessibility/util/ShortcutUtilsTest.java @@ -0,0 +1,358 @@ +/* + * Copyright 2023 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.internal.accessibility.util; + +import static android.provider.Settings.Secure.ACCESSIBILITY_DISPLAY_MAGNIFICATION_ENABLED; +import static android.provider.Settings.Secure.ACCESSIBILITY_SHORTCUT_TARGET_MAGNIFICATION_CONTROLLER; + +import static com.android.internal.accessibility.common.ShortcutConstants.SERVICES_SEPARATOR; + +import static com.google.common.truth.Truth.assertThat; + +import static org.mockito.ArgumentMatchers.anyInt; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.spy; +import static org.mockito.Mockito.when; + +import android.accessibilityservice.AccessibilityServiceInfo; +import android.content.ComponentName; +import android.content.ContentResolver; +import android.content.Context; +import android.content.ContextWrapper; +import android.content.pm.ParceledListSlice; +import android.os.Handler; +import android.os.RemoteException; +import android.os.UserHandle; +import android.provider.Settings; +import android.view.accessibility.AccessibilityManager; +import android.view.accessibility.IAccessibilityManager; + +import androidx.test.platform.app.InstrumentationRegistry; +import androidx.test.runner.AndroidJUnit4; + +import com.android.internal.accessibility.AccessibilityShortcutController; +import com.android.internal.accessibility.TestUtils; +import com.android.internal.accessibility.common.ShortcutConstants; +import com.android.internal.util.test.FakeSettingsProvider; +import com.android.internal.util.test.FakeSettingsProviderRule; + +import org.junit.Before; +import org.junit.Rule; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.mockito.Mock; +import org.mockito.MockitoAnnotations; + +import java.util.List; +import java.util.Set; +import java.util.StringJoiner; + +/** + * Unit Tests for {@link com.android.internal.accessibility.util.ShortcutUtils} + */ +@RunWith(AndroidJUnit4.class) +public class ShortcutUtilsTest { + private static final Set<String> ONE_COMPONENT = Set.of( + new ComponentName("pkg", "serv").flattenToString()); + private static final Set<String> TWO_COMPONENTS = Set.of( + new ComponentName("pkg", "serv").flattenToString(), + AccessibilityShortcutController.MAGNIFICATION_CONTROLLER_NAME); + private static final String ALWAYS_ON_SERVICE_PACKAGE_LABEL = "always on a11y service"; + private static final String ALWAYS_ON_SERVICE_COMPONENT_NAME = + "fake.package/fake.alwayson.service.name"; + + private static final String STANDARD_SERVICE_PACKAGE_LABEL = "standard a11y service"; + private static final String STANDARD_SERVICE_COMPONENT_NAME = + "fake.package/fake.standard.service.name"; + private static final String SERVICE_NAME_SUMMARY = "Summary"; + + @Rule + public FakeSettingsProviderRule mSettingsProviderRule = FakeSettingsProvider.rule(); + @Mock + private IAccessibilityManager mAccessibilityManagerService; + private ContextWrapper mContextSpy; + + @Before + public void setUp() throws RemoteException { + MockitoAnnotations.initMocks(this); + mContextSpy = spy( + new ContextWrapper(InstrumentationRegistry.getInstrumentation().getContext())); + + ContentResolver contentResolver = mSettingsProviderRule.mockContentResolver(mContextSpy); + when(mContextSpy.getContentResolver()).thenReturn(contentResolver); + + AccessibilityManager accessibilityManager = + new AccessibilityManager( + mContextSpy, mock(Handler.class), + mAccessibilityManagerService, UserHandle.myUserId(), + /* serviceConnect= */ true); + when(mContextSpy.getSystemService(Context.ACCESSIBILITY_SERVICE)) + .thenReturn(accessibilityManager); + + setupFakeA11yServiceInfos(); + } + + @Test + public void getShortcutTargets_softwareShortcutNoService_emptyResult() { + assertThat( + ShortcutUtils.getShortcutTargetsFromSettings( + mContextSpy, + ShortcutConstants.UserShortcutType.SOFTWARE, UserHandle.myUserId()) + ).isEmpty(); + } + + @Test + public void getShortcutTargets_volumeKeyShortcutNoService_emptyResult() { + assertThat( + ShortcutUtils.getShortcutTargetsFromSettings( + mContextSpy, ShortcutConstants.UserShortcutType.HARDWARE, + UserHandle.myUserId()) + ).isEmpty(); + } + + @Test + public void getShortcutTargets_softwareShortcut1Service_return1Service() { + setupShortcutTargets(ONE_COMPONENT, Settings.Secure.ACCESSIBILITY_BUTTON_TARGETS); + setupShortcutTargets(TWO_COMPONENTS, Settings.Secure.ACCESSIBILITY_SHORTCUT_TARGET_SERVICE); + + assertThat( + ShortcutUtils.getShortcutTargetsFromSettings( + mContextSpy, ShortcutConstants.UserShortcutType.SOFTWARE, + UserHandle.myUserId()) + ).containsExactlyElementsIn(ONE_COMPONENT); + } + + @Test + public void getShortcutTargets_volumeShortcut2Service_return2Service() { + setupShortcutTargets(ONE_COMPONENT, Settings.Secure.ACCESSIBILITY_BUTTON_TARGETS); + setupShortcutTargets(TWO_COMPONENTS, Settings.Secure.ACCESSIBILITY_SHORTCUT_TARGET_SERVICE); + + assertThat( + ShortcutUtils.getShortcutTargetsFromSettings( + mContextSpy, ShortcutConstants.UserShortcutType.HARDWARE, + UserHandle.myUserId()) + ).containsExactlyElementsIn(TWO_COMPONENTS); + } + + @Test + public void getShortcutTargets_tripleTapShortcut_magnificationDisabled_emptyResult() { + enableTripleTapShortcutForMagnification(/* enable= */ false); + setupShortcutTargets(ONE_COMPONENT, Settings.Secure.ACCESSIBILITY_BUTTON_TARGETS); + setupShortcutTargets(TWO_COMPONENTS, Settings.Secure.ACCESSIBILITY_SHORTCUT_TARGET_SERVICE); + + assertThat( + ShortcutUtils.getShortcutTargetsFromSettings( + mContextSpy, ShortcutConstants.UserShortcutType.TRIPLETAP, + UserHandle.myUserId()) + ).isEmpty(); + } + + @Test + public void getShortcutTargets_tripleTapShortcut_magnificationEnabled_returnMagnification() { + setupShortcutTargets(ONE_COMPONENT, Settings.Secure.ACCESSIBILITY_BUTTON_TARGETS); + setupShortcutTargets(TWO_COMPONENTS, Settings.Secure.ACCESSIBILITY_SHORTCUT_TARGET_SERVICE); + enableTripleTapShortcutForMagnification(/* enable= */ true); + + assertThat( + ShortcutUtils.getShortcutTargetsFromSettings( + mContextSpy, ShortcutConstants.UserShortcutType.TRIPLETAP, + UserHandle.myUserId()) + ).containsExactly(ACCESSIBILITY_SHORTCUT_TARGET_MAGNIFICATION_CONTROLLER); + } + + @Test + public void updateAccessibilityServiceStateIfNeeded_alwaysOnServiceOn_noShortcuts_serviceTurnedOff() { + setupA11yServiceAndShortcutState( + ALWAYS_ON_SERVICE_COMPONENT_NAME, /* serviceOn= */ true, /* shortcutOn= */ false); + + ShortcutUtils.updateInvisibleToggleAccessibilityServiceEnableState( + mContextSpy, + Set.of(ALWAYS_ON_SERVICE_COMPONENT_NAME), + UserHandle.myUserId() + ); + + assertA11yServiceState(ALWAYS_ON_SERVICE_COMPONENT_NAME, /* enabled= */ false); + } + + @Test + public void updateAccessibilityServiceStateIfNeeded_alwaysOnServiceOn_hasShortcut_serviceKeepsOn() { + setupA11yServiceAndShortcutState( + ALWAYS_ON_SERVICE_COMPONENT_NAME, /* serviceOn= */ true, /* shortcutOn= */ true); + + ShortcutUtils.updateInvisibleToggleAccessibilityServiceEnableState( + mContextSpy, + Set.of(ALWAYS_ON_SERVICE_COMPONENT_NAME), + UserHandle.myUserId() + ); + + assertA11yServiceState(ALWAYS_ON_SERVICE_COMPONENT_NAME, /* enabled= */ true); + } + + @Test + public void updateAccessibilityServiceStateIfNeeded_alwaysOnServiceOff_noShortcuts_serviceKeepsOff() { + setupA11yServiceAndShortcutState( + ALWAYS_ON_SERVICE_COMPONENT_NAME, /* serviceOn= */ false, /* shortcutOn= */ false); + + ShortcutUtils.updateInvisibleToggleAccessibilityServiceEnableState( + mContextSpy, + Set.of(ALWAYS_ON_SERVICE_COMPONENT_NAME), + UserHandle.myUserId() + ); + + assertA11yServiceState(ALWAYS_ON_SERVICE_COMPONENT_NAME, /* enabled= */ false); + } + + @Test + public void updateAccessibilityServiceStateIfNeeded_alwaysOnServiceOff_hasShortcuts_serviceTurnsOn() { + setupA11yServiceAndShortcutState( + ALWAYS_ON_SERVICE_COMPONENT_NAME, /* serviceOn= */ false, /* shortcutOn= */ true); + + ShortcutUtils.updateInvisibleToggleAccessibilityServiceEnableState( + mContextSpy, + Set.of(ALWAYS_ON_SERVICE_COMPONENT_NAME), + UserHandle.myUserId() + ); + + assertA11yServiceState(ALWAYS_ON_SERVICE_COMPONENT_NAME, /* enabled= */ true); + } + + @Test + public void updateAccessibilityServiceStateIfNeeded_standardA11yServiceOn_noShortcuts_serviceKeepsOn() { + setupA11yServiceAndShortcutState( + STANDARD_SERVICE_COMPONENT_NAME, /* serviceOn= */ true, /* shortcutOn= */ false); + + ShortcutUtils.updateInvisibleToggleAccessibilityServiceEnableState( + mContextSpy, + Set.of(STANDARD_SERVICE_COMPONENT_NAME), + UserHandle.myUserId() + ); + + assertA11yServiceState(STANDARD_SERVICE_COMPONENT_NAME, /* enabled= */ true); + } + + @Test + public void updateAccessibilityServiceStateIfNeeded_standardA11yServiceOn_hasShortcuts_serviceKeepsOn() { + setupA11yServiceAndShortcutState( + STANDARD_SERVICE_COMPONENT_NAME, /* serviceOn= */ true, /* shortcutOn= */ true); + + ShortcutUtils.updateInvisibleToggleAccessibilityServiceEnableState( + mContextSpy, + Set.of(STANDARD_SERVICE_COMPONENT_NAME), + UserHandle.myUserId() + ); + + assertA11yServiceState(STANDARD_SERVICE_COMPONENT_NAME, /* enabled= */ true); + } + + @Test + public void updateAccessibilityServiceStateIfNeeded_standardA11yServiceOff_noShortcuts_serviceKeepsOff() { + setupA11yServiceAndShortcutState( + STANDARD_SERVICE_COMPONENT_NAME, /* serviceOn= */ false, /* shortcutOn= */ false); + + ShortcutUtils.updateInvisibleToggleAccessibilityServiceEnableState( + mContextSpy, + Set.of(STANDARD_SERVICE_COMPONENT_NAME), + UserHandle.myUserId() + ); + + assertA11yServiceState(STANDARD_SERVICE_COMPONENT_NAME, /* enabled= */ false); + } + + @Test + public void updateAccessibilityServiceStateIfNeeded_standardA11yServiceOff_hasShortcuts_serviceKeepsOff() { + setupA11yServiceAndShortcutState( + STANDARD_SERVICE_COMPONENT_NAME, /* serviceOn= */ false, /* shortcutOn= */ true); + + ShortcutUtils.updateInvisibleToggleAccessibilityServiceEnableState( + mContextSpy, + Set.of(STANDARD_SERVICE_COMPONENT_NAME), + UserHandle.myUserId() + ); + + assertA11yServiceState(STANDARD_SERVICE_COMPONENT_NAME, /* enabled= */ false); + } + + private void setupShortcutTargets(Set<String> components, String shortcutSettingsKey) { + final StringJoiner stringJoiner = new StringJoiner(String.valueOf(SERVICES_SEPARATOR)); + for (String target : components) { + stringJoiner.add(target); + } + Settings.Secure.putStringForUser( + mContextSpy.getContentResolver(), shortcutSettingsKey, + stringJoiner.toString(), + UserHandle.myUserId()); + } + + private void enableTripleTapShortcutForMagnification(boolean enable) { + Settings.Secure.putInt( + mContextSpy.getContentResolver(), + ACCESSIBILITY_DISPLAY_MAGNIFICATION_ENABLED, enable ? 1 : 0); + } + + private void setupFakeA11yServiceInfos() throws RemoteException { + List<AccessibilityServiceInfo> serviceInfos = List.of( + TestUtils.createFakeServiceInfo( + ALWAYS_ON_SERVICE_PACKAGE_LABEL, + ALWAYS_ON_SERVICE_COMPONENT_NAME, + SERVICE_NAME_SUMMARY, + /* isAlwaysOnService*/ true), + TestUtils.createFakeServiceInfo( + STANDARD_SERVICE_PACKAGE_LABEL, + STANDARD_SERVICE_COMPONENT_NAME, + SERVICE_NAME_SUMMARY, + /* isAlwaysOnService*/ false) + ); + when(mAccessibilityManagerService.getInstalledAccessibilityServiceList(anyInt())) + .thenReturn(new ParceledListSlice<>(serviceInfos)); + } + + private void setupA11yServiceAndShortcutState( + String a11yServiceComponentName, boolean serviceOn, boolean shortcutOn) { + enableA11yService(a11yServiceComponentName, serviceOn); + addShortcutForA11yService(a11yServiceComponentName, shortcutOn); + } + + private void assertA11yServiceState(String a11yServiceComponentName, boolean enabled) { + if (enabled) { + assertThat( + Settings.Secure.getString( + mContextSpy.getContentResolver(), + Settings.Secure.ENABLED_ACCESSIBILITY_SERVICES) + ).contains(a11yServiceComponentName); + } else { + assertThat( + Settings.Secure.getString( + mContextSpy.getContentResolver(), + Settings.Secure.ENABLED_ACCESSIBILITY_SERVICES) + ).doesNotContain(a11yServiceComponentName); + } + } + + private void enableA11yService(String a11yServiceComponentName, boolean enable) { + Settings.Secure.putString( + mContextSpy.getContentResolver(), + Settings.Secure.ENABLED_ACCESSIBILITY_SERVICES, + enable ? a11yServiceComponentName : ""); + } + + private void addShortcutForA11yService(String a11yServiceComponentName, boolean add) { + Settings.Secure.putString( + mContextSpy.getContentResolver(), + Settings.Secure.ACCESSIBILITY_SHORTCUT_TARGET_SERVICE, + add ? a11yServiceComponentName : ""); + } +} diff --git a/core/tests/packagemonitortests/src/com/android/internal/content/PackageMonitorTest.java b/core/tests/packagemonitortests/src/com/android/internal/content/PackageMonitorTest.java index a3399070ebcd..8e653f5e828f 100644 --- a/core/tests/packagemonitortests/src/com/android/internal/content/PackageMonitorTest.java +++ b/core/tests/packagemonitortests/src/com/android/internal/content/PackageMonitorTest.java @@ -298,6 +298,43 @@ public class PackageMonitorTest { } @Test + public void testPackageMonitorDoHandlePackageEventPackageRemovedReplacingArchived() { + PackageMonitor spyPackageMonitor = spy(new TestPackageMonitor()); + + Intent intent = new Intent(Intent.ACTION_PACKAGE_REMOVED); + intent.setData(Uri.fromParts("package", FAKE_PACKAGE_NAME, null)); + intent.putExtra(Intent.EXTRA_USER_HANDLE, FAKE_USER_ID); + intent.putExtra(Intent.EXTRA_UID, FAKE_PACKAGE_UID); + intent.putExtra(Intent.EXTRA_REPLACING, true); + intent.putExtra(Intent.EXTRA_ARCHIVAL, true); + intent.putExtra(Intent.EXTRA_REMOVED_FOR_ALL_USERS, true); + spyPackageMonitor.doHandlePackageEvent(intent); + + verify(spyPackageMonitor, times(1)).onBeginPackageChanges(); + verify(spyPackageMonitor, times(1)) + .onPackageUpdateStarted(eq(FAKE_PACKAGE_NAME), eq(FAKE_PACKAGE_UID)); + verify(spyPackageMonitor, times(1)).onPackageModified(eq(FAKE_PACKAGE_NAME)); + + ArgumentCaptor<Bundle> argumentCaptor = ArgumentCaptor.forClass(Bundle.class); + verify(spyPackageMonitor, times(1)) + .onPackageDisappearedWithExtras(eq(FAKE_PACKAGE_NAME), argumentCaptor.capture()); + Bundle capturedExtras = argumentCaptor.getValue(); + Bundle expectedExtras = intent.getExtras(); + assertThat(capturedExtras.getInt(Intent.EXTRA_USER_HANDLE)) + .isEqualTo(expectedExtras.getInt(Intent.EXTRA_USER_HANDLE)); + assertThat(capturedExtras.getInt(Intent.EXTRA_UID)) + .isEqualTo(expectedExtras.getInt(Intent.EXTRA_UID)); + assertThat(capturedExtras.getInt(Intent.EXTRA_REPLACING)) + .isEqualTo(expectedExtras.getInt(Intent.EXTRA_REPLACING)); + assertThat(capturedExtras.getInt(Intent.EXTRA_REMOVED_FOR_ALL_USERS)) + .isEqualTo(expectedExtras.getInt(Intent.EXTRA_REMOVED_FOR_ALL_USERS)); + + verify(spyPackageMonitor, times(1)) + .onPackageDisappeared(eq(FAKE_PACKAGE_NAME), eq(PackageMonitor.PACKAGE_UPDATING)); + verify(spyPackageMonitor, times(1)).onFinishPackageChanges(); + } + + @Test public void testPackageMonitorDoHandlePackageEventPackageRemovedNotReplacing() throws Exception { PackageMonitor spyPackageMonitor = spy(new TestPackageMonitor()); diff --git a/data/etc/services.core.protolog.json b/data/etc/services.core.protolog.json index 87be13ab4a93..dc2b0561957d 100644 --- a/data/etc/services.core.protolog.json +++ b/data/etc/services.core.protolog.json @@ -2653,6 +2653,12 @@ "group": "WM_DEBUG_WINDOW_TRANSITIONS", "at": "com\/android\/server\/wm\/TransitionController.java" }, + "261227010": { + "message": "Content Recording: Unable to tell log windowing mode change: %s", + "level": "ERROR", + "group": "WM_DEBUG_CONTENT_RECORDING", + "at": "com\/android\/server\/wm\/ContentRecorder.java" + }, "269576220": { "message": "Resuming rotation after drag", "level": "DEBUG", diff --git a/graphics/java/android/graphics/text/LineBreakConfig.java b/graphics/java/android/graphics/text/LineBreakConfig.java index 621958562b94..c5e451a5ec3a 100644 --- a/graphics/java/android/graphics/text/LineBreakConfig.java +++ b/graphics/java/android/graphics/text/LineBreakConfig.java @@ -28,6 +28,8 @@ import android.compat.annotation.ChangeId; import android.compat.annotation.EnabledSince; import android.os.Build; import android.os.LocaleList; +import android.os.Parcel; +import android.os.Parcelable; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; @@ -40,7 +42,7 @@ import java.util.Objects; * <a href="https://www.w3.org/TR/css-text-3/#line-break-property" class="external"> * line-break property</a> for more information. */ -public final class LineBreakConfig { +public final class LineBreakConfig implements Parcelable { /** * A feature ID for automatic line break word style. @@ -161,12 +163,12 @@ public final class LineBreakConfig { * * This is useful when you want to preserve some words in the same line by using * {@link android.text.style.LineBreakConfigSpan} or - * {@link android.text.style.LineBreakConfigSpan.NoBreakSpan} as a shorthand. + * {@link android.text.style.LineBreakConfigSpan#createNoBreakSpan()} as a shorthand. * Note that even if this style is specified, the grapheme based line break is still performed * for preventing clipping text. * * @see android.text.style.LineBreakConfigSpan - * @see android.text.style.LineBreakConfigSpan.NoBreakSpan + * @see android.text.style.LineBreakConfigSpan#createNoBreakSpan() */ @FlaggedApi(FLAG_NO_BREAK_NO_HYPHENATION_SPAN) public static final int LINE_BREAK_STYLE_NO_BREAK = 4; @@ -457,8 +459,9 @@ public final class LineBreakConfig { * * <p>Use {@link LineBreakConfig.Builder} to create the * {@code LineBreakConfig} instance. + * @hide */ - private LineBreakConfig(@LineBreakStyle int lineBreakStyle, + public LineBreakConfig(@LineBreakStyle int lineBreakStyle, @LineBreakWordStyle int lineBreakWordStyle, @Hyphenation int hyphenation) { mLineBreakStyle = lineBreakStyle; @@ -606,4 +609,35 @@ public final class LineBreakConfig { + ", mHyphenation= " + mHyphenation + '}'; } + + @FlaggedApi(FLAG_NO_BREAK_NO_HYPHENATION_SPAN) + @Override + public int describeContents() { + return 0; + } + + @FlaggedApi(FLAG_NO_BREAK_NO_HYPHENATION_SPAN) + @Override + public void writeToParcel(@NonNull Parcel dest, int flags) { + dest.writeInt(mLineBreakStyle); + dest.writeInt(mLineBreakWordStyle); + dest.writeInt(mHyphenation); + } + + @FlaggedApi(FLAG_NO_BREAK_NO_HYPHENATION_SPAN) + public static final @NonNull Creator<LineBreakConfig> CREATOR = new Creator<>() { + + @Override + public LineBreakConfig createFromParcel(Parcel source) { + final int lineBreakStyle = source.readInt(); + final int lineBreakWordStyle = source.readInt(); + final int hyphenation = source.readInt(); + return new LineBreakConfig(lineBreakStyle, lineBreakWordStyle, hyphenation); + } + + @Override + public LineBreakConfig[] newArray(int size) { + return new LineBreakConfig[size]; + } + }; } 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/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/AndroidManifestSplitScreen.xml b/libs/WindowManager/Shell/tests/flicker/service/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/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.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/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/AndroidManifestService.xml b/libs/WindowManager/Shell/tests/flicker/splitscreen/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/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.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/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/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/location/api/system-lint-baseline.txt b/location/api/system-lint-baseline.txt index a5e5752d7cf5..043a082409ac 100644 --- a/location/api/system-lint-baseline.txt +++ b/location/api/system-lint-baseline.txt @@ -9,3 +9,9 @@ SamShouldBeLast: android.location.LocationManager#requestSingleUpdate(String, an SAM-compatible parameters (such as parameter 2, "listener", in android.location.LocationManager.requestSingleUpdate) should be last to improve Kotlin interoperability; see https://kotlinlang.org/docs/reference/java-interop.html#sam-conversions SamShouldBeLast: android.location.LocationManager#requestSingleUpdate(android.location.Criteria, android.location.LocationListener, android.os.Looper): SAM-compatible parameters (such as parameter 2, "listener", in android.location.LocationManager.requestSingleUpdate) should be last to improve Kotlin interoperability; see https://kotlinlang.org/docs/reference/java-interop.html#sam-conversions + + +UnflaggedApi: android.location.GnssMeasurementRequest#getWorkSource(): + New API must be flagged with @FlaggedApi: method android.location.GnssMeasurementRequest.getWorkSource() +UnflaggedApi: android.location.GnssMeasurementRequest.Builder#setWorkSource(android.os.WorkSource): + New API must be flagged with @FlaggedApi: method android.location.GnssMeasurementRequest.Builder.setWorkSource(android.os.WorkSource) diff --git a/media/java/android/media/projection/IMediaProjectionManager.aidl b/media/java/android/media/projection/IMediaProjectionManager.aidl index 24efbd14bc02..a7ec6c692416 100644 --- a/media/java/android/media/projection/IMediaProjectionManager.aidl +++ b/media/java/android/media/projection/IMediaProjectionManager.aidl @@ -212,4 +212,9 @@ interface IMediaProjectionManager { @JavaPassthrough(annotation = "@android.annotation.RequiresPermission(android.Manifest" + ".permission.MANAGE_MEDIA_PROJECTION)") oneway void notifyAppSelectorDisplayed(int hostUid); + + @EnforcePermission("MANAGE_MEDIA_PROJECTION") + @JavaPassthrough(annotation = "@android.annotation.RequiresPermission(android.Manifest" + + ".permission.MANAGE_MEDIA_PROJECTION)") + void notifyWindowingModeChanged(int contentToRecord, int targetUid, int windowingMode); } 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/res/values/strings.xml b/packages/SettingsLib/res/values/strings.xml index 6eaabbb389c2..96029c813528 100644 --- a/packages/SettingsLib/res/values/strings.xml +++ b/packages/SettingsLib/res/values/strings.xml @@ -202,10 +202,18 @@ <string name="bluetooth_active_battery_level_untethered">Active, L: <xliff:g id="battery_level_as_percentage" example="25%">%1$s</xliff:g> battery, R: <xliff:g id="battery_level_as_percentage" example="25%">%2$s</xliff:g> battery</string> <!-- Connected devices settings. Message when Bluetooth is connected but not in use, showing remote device battery level. [CHAR LIMIT=NONE] --> <string name="bluetooth_battery_level"><xliff:g id="battery_level_as_percentage">%1$s</xliff:g> battery</string> + <!-- Connected devices settings. Message on TV when Bluetooth is connected but not in use, showing remote device battery level. [CHAR LIMIT=NONE] --> + <string name="tv_bluetooth_battery_level">Battery <xliff:g id="battery_level_as_percentage">%1$s</xliff:g></string> <!-- Connected devices settings. Message when Bluetooth is connected but not in use, showing remote device battery level for untethered headset. [CHAR LIMIT=NONE] --> <string name="bluetooth_battery_level_untethered">L: <xliff:g id="battery_level_as_percentage" example="25%">%1$s</xliff:g> battery, R: <xliff:g id="battery_level_as_percentage" example="25%">%2$s</xliff:g> battery</string> + <!-- Connected devices settings. Message when Bluetooth is connected but not in use, showing remote device battery level for the left part of the untethered headset. [CHAR LIMIT=NONE] --> + <string name="bluetooth_battery_level_untethered_left">Left <xliff:g id="battery_level_as_percentage" example="25%">%1$s</xliff:g></string> + <!-- Connected devices settings. Message when Bluetooth is connected but not in use, showing remote device battery level for the right part of the untethered headset. [CHAR LIMIT=NONE] --> + <string name="bluetooth_battery_level_untethered_right">Right <xliff:g id="battery_level_as_percentage" example="25%">%1$s</xliff:g></string> <!-- Connected devices settings. Message when Bluetooth is connected and active but no battery information, showing remote device status. [CHAR LIMIT=NONE] --> <string name="bluetooth_active_no_battery_level">Active</string> + <!-- Connected devices settings. Message shown when bluetooth device is disconnected but is a known, previously connected device [CHAR LIMIT=NONE] --> + <string name="bluetooth_saved_device">Saved</string> <!-- Connected device settings. Message when the left-side hearing aid device is active. [CHAR LIMIT=NONE] --> <string name="bluetooth_hearing_aid_left_active">Active, left only</string> @@ -1019,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/bluetooth/CachedBluetoothDevice.java b/packages/SettingsLib/src/com/android/settingslib/bluetooth/CachedBluetoothDevice.java index 66efb1ceaf19..24083b682397 100644 --- a/packages/SettingsLib/src/com/android/settingslib/bluetooth/CachedBluetoothDevice.java +++ b/packages/SettingsLib/src/com/android/settingslib/bluetooth/CachedBluetoothDevice.java @@ -35,7 +35,9 @@ import android.os.Looper; import android.os.Message; import android.os.ParcelUuid; import android.os.SystemClock; +import android.text.SpannableStringBuilder; import android.text.TextUtils; +import android.text.style.ForegroundColorSpan; import android.util.Log; import android.util.LruCache; import android.util.Pair; @@ -46,6 +48,7 @@ import androidx.annotation.VisibleForTesting; import com.android.internal.util.ArrayUtils; import com.android.settingslib.R; import com.android.settingslib.Utils; +import com.android.settingslib.media.flags.Flags; import com.android.settingslib.utils.ThreadUtils; import com.android.settingslib.widget.AdaptiveOutlineDrawable; @@ -83,6 +86,12 @@ public class CachedBluetoothDevice implements Comparable<CachedBluetoothDevice> private static final long MAX_LEAUDIO_DELAY_FOR_AUTO_CONNECT = 30000; private static final long MAX_MEDIA_PROFILE_CONNECT_DELAY = 60000; + private static final int DEFAULT_LOW_BATTERY_THRESHOLD = 20; + + // To be used instead of a resource id to indicate that low battery states should not be + // changed to a different color. + private static final int SUMMARY_NO_COLOR_FOR_LOW_BATTERY = 0; + private final Context mContext; private final BluetoothAdapter mLocalAdapter; private final LocalBluetoothProfileManager mProfileManager; @@ -1189,6 +1198,46 @@ public class CachedBluetoothDevice implements Comparable<CachedBluetoothDevice> * @param shortSummary {@code true} if need to return short version summary */ public String getConnectionSummary(boolean shortSummary) { + CharSequence summary = getConnectionSummary(shortSummary, false /* isTvSummary */, + SUMMARY_NO_COLOR_FOR_LOW_BATTERY); + if (summary != null) { + return summary.toString(); + } + return null; + } + + /** + * Returns android tv string that describes the connection state of this device. + */ + public CharSequence getTvConnectionSummary() { + return getTvConnectionSummary(SUMMARY_NO_COLOR_FOR_LOW_BATTERY); + } + + /** + * Returns android tv string that describes the connection state of this device, with low + * battery states highlighted in color. + * + * @param lowBatteryColorRes - resource id for the color that should be used for the part of the + * CharSequence that contains low battery information. + */ + public CharSequence getTvConnectionSummary(int lowBatteryColorRes) { + return getConnectionSummary(false /* shortSummary */, true /* isTvSummary */, + lowBatteryColorRes); + } + + /** + * Return summary that describes connection state of this device. Summary depends on: + * 1. Whether device has battery info + * 2. Whether device is in active usage(or in phone call) + * + * @param shortSummary {@code true} if need to return short version summary + * @param isTvSummary {@code true} if the summary should be TV specific + * @param lowBatteryColorRes Resource id of the color to be used for low battery strings. Use + * {@link SUMMARY_NO_COLOR_FOR_LOW_BATTERY} if no separate color + * should be used. + */ + private CharSequence getConnectionSummary(boolean shortSummary, boolean isTvSummary, + int lowBatteryColorRes) { boolean profileConnected = false; // Updated as long as BluetoothProfile is connected boolean a2dpConnected = true; // A2DP is connected boolean hfpConnected = true; // HFP is connected @@ -1315,17 +1364,82 @@ public class CachedBluetoothDevice implements Comparable<CachedBluetoothDevice> } } - if (stringRes != R.string.bluetooth_pairing - || getBondState() == BluetoothDevice.BOND_BONDING) { - if (isTwsBatteryAvailable(leftBattery, rightBattery)) { - return mContext.getString(stringRes, Utils.formatPercentage(leftBattery), + if (stringRes == R.string.bluetooth_pairing + && getBondState() != BluetoothDevice.BOND_BONDING) { + return null; + } + + boolean summaryIncludesBatteryLevel = stringRes == R.string.bluetooth_battery_level + || stringRes == R.string.bluetooth_active_battery_level + || stringRes == R.string.bluetooth_active_battery_level_untethered + || stringRes == R.string.bluetooth_battery_level_untethered; + if (isTvSummary && summaryIncludesBatteryLevel && Flags.enableTvMediaOutputDialog()) { + return getTvBatterySummary(batteryLevel, leftBattery, rightBattery, lowBatteryColorRes); + } + + if (isTwsBatteryAvailable(leftBattery, rightBattery)) { + return mContext.getString(stringRes, Utils.formatPercentage(leftBattery), + Utils.formatPercentage(rightBattery)); + } else { + return mContext.getString(stringRes, batteryLevelPercentageString); + } + } + + private CharSequence getTvBatterySummary(int mainBattery, int leftBattery, int rightBattery, + int lowBatteryColorRes) { + // Since there doesn't seem to be a way to use format strings to add the + // percentages and also mark which part of the string is left and right to color + // them, we are using one string resource per battery. + Resources res = mContext.getResources(); + SpannableStringBuilder spannableBuilder = new SpannableStringBuilder(); + if (leftBattery >= 0 || rightBattery >= 0) { + // Not switching the left and right for RTL to keep the left earbud always on + // the left. + if (leftBattery >= 0) { + String left = res.getString( + R.string.bluetooth_battery_level_untethered_left, + Utils.formatPercentage(leftBattery)); + addBatterySpan(spannableBuilder, left, isBatteryLow(leftBattery, + BluetoothDevice.METADATA_UNTETHERED_LEFT_LOW_BATTERY_THRESHOLD), + lowBatteryColorRes); + } + if (rightBattery >= 0) { + if (!spannableBuilder.isEmpty()) { + spannableBuilder.append(" "); + } + String right = res.getString( + R.string.bluetooth_battery_level_untethered_right, Utils.formatPercentage(rightBattery)); - } else { - return mContext.getString(stringRes, batteryLevelPercentageString); + addBatterySpan(spannableBuilder, right, isBatteryLow(rightBattery, + BluetoothDevice.METADATA_UNTETHERED_RIGHT_LOW_BATTERY_THRESHOLD), + lowBatteryColorRes); } } else { - return null; + addBatterySpan(spannableBuilder, res.getString(R.string.tv_bluetooth_battery_level, + Utils.formatPercentage(mainBattery)), + isBatteryLow(mainBattery, BluetoothDevice.METADATA_MAIN_LOW_BATTERY_THRESHOLD), + lowBatteryColorRes); + } + return spannableBuilder; + } + + private void addBatterySpan(SpannableStringBuilder builder, + String batteryString, boolean lowBattery, int lowBatteryColorRes) { + if (lowBattery && lowBatteryColorRes != SUMMARY_NO_COLOR_FOR_LOW_BATTERY) { + builder.append(batteryString, + new ForegroundColorSpan(mContext.getResources().getColor(lowBatteryColorRes)), + 0 /* flags */); + } else { + builder.append(batteryString); + } + } + + private boolean isBatteryLow(int batteryLevel, int metadataKey) { + int lowBatteryThreshold = BluetoothUtils.getIntMetaData(mDevice, metadataKey); + if (lowBatteryThreshold <= 0) { + lowBatteryThreshold = DEFAULT_LOW_BATTERY_THRESHOLD; } + return batteryLevel <= lowBatteryThreshold; } private boolean isTwsBatteryAvailable(int leftBattery, int rightBattery) { diff --git a/packages/SettingsLib/src/com/android/settingslib/media/BluetoothMediaDevice.java b/packages/SettingsLib/src/com/android/settingslib/media/BluetoothMediaDevice.java index ed518f79156b..9560b8dc802e 100644 --- a/packages/SettingsLib/src/com/android/settingslib/media/BluetoothMediaDevice.java +++ b/packages/SettingsLib/src/com/android/settingslib/media/BluetoothMediaDevice.java @@ -72,6 +72,13 @@ public class BluetoothMediaDevice extends MediaDevice { } @Override + public CharSequence getSummaryForTv(int lowBatteryColorRes) { + return isConnected() || mCachedDevice.isBusy() + ? mCachedDevice.getTvConnectionSummary(lowBatteryColorRes) + : mContext.getString(R.string.bluetooth_saved_device); + } + + @Override public int getSelectionBehavior() { // We don't allow apps to override the selection behavior of system routes. return SELECTION_BEHAVIOR_TRANSFER; diff --git a/packages/SettingsLib/src/com/android/settingslib/media/MediaDevice.java b/packages/SettingsLib/src/com/android/settingslib/media/MediaDevice.java index 8085c998abea..c8e4c0c93789 100644 --- a/packages/SettingsLib/src/com/android/settingslib/media/MediaDevice.java +++ b/packages/SettingsLib/src/com/android/settingslib/media/MediaDevice.java @@ -208,6 +208,17 @@ public abstract class MediaDevice implements Comparable<MediaDevice> { public abstract String getSummary(); /** + * Get summary from MediaDevice for TV with low batter states in a different color if + * applicable. + * + * @param lowBatteryColorRes Color resource for the part of the CharSequence that describes a + * low battery state. + */ + public CharSequence getSummaryForTv(int lowBatteryColorRes) { + return getSummary(); + } + + /** * Get icon of MediaDevice. * * @return drawable of icon. diff --git a/packages/SettingsLib/src/com/android/settingslib/qrcode/QrCamera.java b/packages/SettingsLib/src/com/android/settingslib/qrcode/QrCamera.java index e65109003856..ae17acb5104b 100644 --- a/packages/SettingsLib/src/com/android/settingslib/qrcode/QrCamera.java +++ b/packages/SettingsLib/src/com/android/settingslib/qrcode/QrCamera.java @@ -116,8 +116,13 @@ public class QrCamera extends Handler { mDecodeTask = null; } if (mCamera != null) { - mCamera.stopPreview(); - releaseCamera(); + try { + mCamera.stopPreview(); + releaseCamera(); + } catch (RuntimeException e) { + Log.e(TAG, "Stop previewing camera failed:" + e); + mCamera = null; + } } } diff --git a/packages/SettingsLib/tests/robotests/Android.bp b/packages/SettingsLib/tests/robotests/Android.bp index 2d875cf7244d..732c33615dd0 100644 --- a/packages/SettingsLib/tests/robotests/Android.bp +++ b/packages/SettingsLib/tests/robotests/Android.bp @@ -49,6 +49,8 @@ android_robolectric_test { "androidx.fragment_fragment", "androidx.test.core", "androidx.core_core", + "flag-junit", + "settingslib_flags_lib", "testng", // TODO: remove once JUnit on Android provides assertThrows ], java_resource_dirs: ["config"], diff --git a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/bluetooth/CachedBluetoothDeviceTest.java b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/bluetooth/CachedBluetoothDeviceTest.java index 85efe69529b4..ed545ab5c81d 100644 --- a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/bluetooth/CachedBluetoothDeviceTest.java +++ b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/bluetooth/CachedBluetoothDeviceTest.java @@ -35,13 +35,18 @@ import android.bluetooth.BluetoothStatusCodes; import android.content.Context; import android.graphics.drawable.BitmapDrawable; import android.media.AudioManager; +import android.platform.test.flag.junit.SetFlagsRule; +import android.text.Spannable; +import android.text.style.ForegroundColorSpan; import android.util.LruCache; import com.android.settingslib.R; +import com.android.settingslib.media.flags.Flags; import com.android.settingslib.testutils.shadow.ShadowBluetoothAdapter; import com.android.settingslib.widget.AdaptiveOutlineDrawable; import org.junit.Before; +import org.junit.Rule; import org.junit.Test; import org.junit.runner.RunWith; import org.mockito.Mock; @@ -60,10 +65,13 @@ public class CachedBluetoothDeviceTest { private static final String DEVICE_ALIAS_NEW = "TestAliasNew"; private static final String TWS_BATTERY_LEFT = "15"; private static final String TWS_BATTERY_RIGHT = "25"; + private static final String TWS_LOW_BATTERY_THRESHOLD_LOW = "10"; + private static final String TWS_LOW_BATTERY_THRESHOLD_HIGH = "25"; private static final short RSSI_1 = 10; private static final short RSSI_2 = 11; private static final boolean JUSTDISCOVERED_1 = true; private static final boolean JUSTDISCOVERED_2 = false; + private static final int LOW_BATTERY_COLOR = android.R.color.holo_red_dark; @Mock private LocalBluetoothProfileManager mProfileManager; @Mock @@ -89,9 +97,13 @@ public class CachedBluetoothDeviceTest { private int mBatteryLevel = BluetoothDevice.BATTERY_LEVEL_UNKNOWN; private ShadowBluetoothAdapter mShadowBluetoothAdapter; + @Rule + public final SetFlagsRule mSetFlagsRule = new SetFlagsRule(); + @Before public void setUp() { MockitoAnnotations.initMocks(this); + mSetFlagsRule.enableFlags(Flags.FLAG_ENABLE_TV_MEDIA_OUTPUT_DIALOG); mContext = RuntimeEnvironment.application; mAudioManager = mContext.getSystemService(AudioManager.class); mShadowBluetoothAdapter = Shadow.extract(BluetoothAdapter.getDefaultAdapter()); @@ -179,6 +191,17 @@ public class CachedBluetoothDeviceTest { } @Test + public void getTvConnectionSummary_testProfilesInactive_returnPairing() { + // Arrange: + // Bond State: Bonding + when(mDevice.getBondState()).thenReturn(BluetoothDevice.BOND_BONDING); + + // Act & Assert: + // Get "Pairing…" result without Battery Level. + assertThat(mCachedDevice.getTvConnectionSummary().toString()).isEqualTo("Pairing…"); + } + + @Test public void getConnectionSummary_testSingleProfileConnectDisconnect() { // Test without battery level // Set PAN profile to be connected and test connection state summary @@ -212,6 +235,39 @@ public class CachedBluetoothDeviceTest { } @Test + public void getTvConnectionSummary_testSingleProfileConnectDisconnect() { + // Test without battery level + // Set PAN profile to be connected and test connection state summary + updateProfileStatus(mPanProfile, BluetoothProfile.STATE_CONNECTED); + assertThat(mCachedDevice.getTvConnectionSummary()).isNull(); + + // Set PAN profile to be disconnected and test connection state summary + updateProfileStatus(mPanProfile, BluetoothProfile.STATE_DISCONNECTED); + assertThat(mCachedDevice.getTvConnectionSummary()).isNull(); + + // Test with battery level + mBatteryLevel = 10; + // Set PAN profile to be connected and test connection state summary + updateProfileStatus(mPanProfile, BluetoothProfile.STATE_CONNECTED); + assertThat(mCachedDevice.getTvConnectionSummary().toString()).isEqualTo("Battery 10%"); + + // Set PAN profile to be disconnected and test connection state summary + updateProfileStatus(mPanProfile, BluetoothProfile.STATE_DISCONNECTED); + assertThat(mCachedDevice.getTvConnectionSummary()).isNull(); + + // Test with BluetoothDevice.BATTERY_LEVEL_UNKNOWN battery level + mBatteryLevel = BluetoothDevice.BATTERY_LEVEL_UNKNOWN; + + // Set PAN profile to be connected and test connection state summary + updateProfileStatus(mPanProfile, BluetoothProfile.STATE_CONNECTED); + assertThat(mCachedDevice.getTvConnectionSummary()).isNull(); + + // Set PAN profile to be disconnected and test connection state summary + updateProfileStatus(mPanProfile, BluetoothProfile.STATE_DISCONNECTED); + assertThat(mCachedDevice.getTvConnectionSummary()).isNull(); + } + + @Test public void getConnectionSummary_testMultipleProfileConnectDisconnect() { mBatteryLevel = 10; @@ -243,6 +299,37 @@ public class CachedBluetoothDeviceTest { } @Test + public void getTvConnectionSummary_testMultipleProfileConnectDisconnect() { + mBatteryLevel = 10; + + // Set HFP, A2DP and PAN profile to be connected and test connection state summary + updateProfileStatus(mHfpProfile, BluetoothProfile.STATE_CONNECTED); + updateProfileStatus(mA2dpProfile, BluetoothProfile.STATE_CONNECTED); + updateProfileStatus(mPanProfile, BluetoothProfile.STATE_CONNECTED); + assertThat(mCachedDevice.getTvConnectionSummary().toString()).isEqualTo("Battery 10%"); + + // Disconnect HFP only and test connection state summary + updateProfileStatus(mHfpProfile, BluetoothProfile.STATE_DISCONNECTED); + assertThat(mCachedDevice.getTvConnectionSummary().toString()).isEqualTo( + "Battery 10%"); + + // Disconnect A2DP only and test connection state summary + updateProfileStatus(mHfpProfile, BluetoothProfile.STATE_CONNECTED); + updateProfileStatus(mA2dpProfile, BluetoothProfile.STATE_DISCONNECTED); + assertThat(mCachedDevice.getTvConnectionSummary().toString()).isEqualTo( + "Battery 10%"); + + // Disconnect both HFP and A2DP and test connection state summary + updateProfileStatus(mHfpProfile, BluetoothProfile.STATE_DISCONNECTED); + assertThat(mCachedDevice.getTvConnectionSummary().toString()).isEqualTo( + "Battery 10%"); + + // Disconnect all profiles and test connection state summary + updateProfileStatus(mPanProfile, BluetoothProfile.STATE_DISCONNECTED); + assertThat(mCachedDevice.getTvConnectionSummary()).isNull(); + } + + @Test public void getConnectionSummary_testSingleProfileActiveDeviceA2dp() { // Test without battery level // Set A2DP profile to be connected and test connection state summary @@ -275,6 +362,37 @@ public class CachedBluetoothDeviceTest { } @Test + public void getTvConnectionSummary_testSingleProfileActiveDeviceA2dp() { + // Test without battery level + // Set A2DP profile to be connected and test connection state summary + updateProfileStatus(mA2dpProfile, BluetoothProfile.STATE_CONNECTED); + assertThat(mCachedDevice.getTvConnectionSummary()).isNull(); + + // Set device as Active for A2DP and test connection state summary + mCachedDevice.onActiveDeviceChanged(true, BluetoothProfile.A2DP); + assertThat(mCachedDevice.getConnectionSummary()).isEqualTo("Active"); + + // Test with battery level + mBatteryLevel = 10; + assertThat(mCachedDevice.getTvConnectionSummary().toString()).isEqualTo("Battery 10%"); + + // Set A2DP profile to be disconnected and test connection state summary + updateProfileStatus(mA2dpProfile, BluetoothProfile.STATE_DISCONNECTED); + assertThat(mCachedDevice.getTvConnectionSummary()).isNull(); + + // Test with BluetoothDevice.BATTERY_LEVEL_UNKNOWN battery level + mBatteryLevel = BluetoothDevice.BATTERY_LEVEL_UNKNOWN; + // Set A2DP profile to be connected, Active and test connection state summary + updateProfileStatus(mA2dpProfile, BluetoothProfile.STATE_CONNECTED); + mCachedDevice.onActiveDeviceChanged(true, BluetoothProfile.A2DP); + assertThat(mCachedDevice.getTvConnectionSummary().toString()).isEqualTo("Active"); + + // Set A2DP profile to be disconnected and test connection state summary + updateProfileStatus(mA2dpProfile, BluetoothProfile.STATE_DISCONNECTED); + assertThat(mCachedDevice.getTvConnectionSummary()).isNull(); + } + + @Test public void getConnectionSummary_shortSummary_returnShortSummary() { // Test without battery level // Set A2DP profile to be connected and test connection state summary @@ -309,6 +427,18 @@ public class CachedBluetoothDeviceTest { } @Test + public void getTvConnectionSummary_testA2dpBatteryInactive_returnBattery() { + // Arrange: + // 1. Profile: {A2DP, CONNECTED, Inactive} + // 2. Battery Level: 10 + updateProfileStatus(mA2dpProfile, BluetoothProfile.STATE_CONNECTED); + mBatteryLevel = 10; + + // Act & Assert: + assertThat(mCachedDevice.getTvConnectionSummary().toString()).isEqualTo("Battery 10%"); + } + + @Test public void getConnectionSummary_testA2dpInCall_returnNull() { // Arrange: // 1. Profile: {A2DP, Connected, Active} @@ -323,6 +453,20 @@ public class CachedBluetoothDeviceTest { } @Test + public void getTvConnectionSummary_testA2dpInCall_returnNull() { + // Arrange: + // 1. Profile: {A2DP, Connected, Active} + // 2. Audio Manager: In Call + updateProfileStatus(mA2dpProfile, BluetoothProfile.STATE_CONNECTED); + mCachedDevice.onActiveDeviceChanged(true, BluetoothProfile.A2DP); + mAudioManager.setMode(AudioManager.MODE_IN_CALL); + + // Act & Assert: + // Get null result without Battery Level. + assertThat(mCachedDevice.getTvConnectionSummary()).isNull(); + } + + @Test public void getConnectionSummary_testA2dpBatteryInCall_returnBattery() { // Arrange: // 1. Profile: {A2DP, Connected, Active} @@ -339,6 +483,22 @@ public class CachedBluetoothDeviceTest { } @Test + public void getTvConnectionSummary_testA2dpBatteryInCall_returnBattery() { + // Arrange: + // 1. Profile: {A2DP, Connected, Active} + // 3. Battery Level: 10 + // 2. Audio Manager: In Call + updateProfileStatus(mA2dpProfile, BluetoothProfile.STATE_CONNECTED); + mCachedDevice.onActiveDeviceChanged(true, BluetoothProfile.A2DP); + mBatteryLevel = 10; + mAudioManager.setMode(AudioManager.MODE_IN_CALL); + + // Act & Assert: + // Get "10% battery" result with Battery Level 10. + assertThat(mCachedDevice.getTvConnectionSummary().toString()).isEqualTo("Battery 10%"); + } + + @Test public void getConnectionSummary_testSingleProfileActiveDeviceHfp() { // Test without battery level // Set HFP profile to be connected and test connection state summary @@ -372,6 +532,39 @@ public class CachedBluetoothDeviceTest { } @Test + public void getTvConnectionSummary_testSingleProfileActiveDeviceHfp() { + // Test without battery level + // Set HFP profile to be connected and test connection state summary + updateProfileStatus(mHfpProfile, BluetoothProfile.STATE_CONNECTED); + assertThat(mCachedDevice.getTvConnectionSummary()).isNull(); + + // Set device as Active for HFP and test connection state summary + mCachedDevice.onAudioModeChanged(); + mAudioManager.setMode(AudioManager.MODE_IN_CALL); + mCachedDevice.onActiveDeviceChanged(true, BluetoothProfile.HEADSET); + assertThat(mCachedDevice.getTvConnectionSummary().toString()).isEqualTo("Active"); + + // Test with battery level + mBatteryLevel = 10; + assertThat(mCachedDevice.getTvConnectionSummary().toString()).isEqualTo("Battery 10%"); + + // Set HFP profile to be disconnected and test connection state summary + updateProfileStatus(mHfpProfile, BluetoothProfile.STATE_DISCONNECTED); + assertThat(mCachedDevice.getTvConnectionSummary()).isNull(); + + // Test with BluetoothDevice.BATTERY_LEVEL_UNKNOWN battery level + mBatteryLevel = BluetoothDevice.BATTERY_LEVEL_UNKNOWN; + // Set HFP profile to be connected, Active and test connection state summary + updateProfileStatus(mHfpProfile, BluetoothProfile.STATE_CONNECTED); + mCachedDevice.onActiveDeviceChanged(true, BluetoothProfile.HEADSET); + assertThat(mCachedDevice.getTvConnectionSummary().toString()).isEqualTo("Active"); + + // Set HFP profile to be disconnected and test connection state summary + updateProfileStatus(mHfpProfile, BluetoothProfile.STATE_DISCONNECTED); + assertThat(mCachedDevice.getTvConnectionSummary()).isNull(); + } + + @Test public void getConnectionSummary_testHeadsetBatteryInactive_returnBattery() { // Arrange: // 1. Profile: {HEADSET, CONNECTED, Inactive} @@ -385,6 +578,19 @@ public class CachedBluetoothDeviceTest { } @Test + public void getTvConnectionSummary_testHeadsetBatteryInactive_returnBattery() { + // Arrange: + // 1. Profile: {HEADSET, CONNECTED, Inactive} + // 2. Battery Level: 10 + updateProfileStatus(mHfpProfile, BluetoothProfile.STATE_CONNECTED); + mBatteryLevel = 10; + + // Act & Assert: + // Get "10% battery" result without Battery Level. + assertThat(mCachedDevice.getTvConnectionSummary().toString()).isEqualTo("Battery 10%"); + } + + @Test public void getConnectionSummary_testHeadsetWithoutInCall_returnNull() { // Arrange: // 1. Profile: {HEADSET, Connected, Active} @@ -398,6 +604,19 @@ public class CachedBluetoothDeviceTest { } @Test + public void getTvConnectionSummary_testHeadsetWithoutInCall_returnNull() { + // Arrange: + // 1. Profile: {HEADSET, Connected, Active} + // 2. Audio Manager: Normal (Without In Call) + updateProfileStatus(mHfpProfile, BluetoothProfile.STATE_CONNECTED); + mCachedDevice.onActiveDeviceChanged(true, BluetoothProfile.HEADSET); + + // Act & Assert: + // Get null result without Battery Level. + assertThat(mCachedDevice.getTvConnectionSummary()).isNull(); + } + + @Test public void getConnectionSummary_testHeadsetBatteryWithoutInCall_returnBattery() { // Arrange: // 1. Profile: {HEADSET, Connected, Active} @@ -413,6 +632,22 @@ public class CachedBluetoothDeviceTest { } @Test + public void getTvConnectionSummary_testHeadsetBatteryWithoutInCall_returnBattery() { + // Arrange: + // 1. Profile: {HEADSET, Connected, Active} + // 2. Battery Level: 10 + // 3. Audio Manager: Normal (Without In Call) + updateProfileStatus(mHfpProfile, BluetoothProfile.STATE_CONNECTED); + mCachedDevice.onActiveDeviceChanged(true, BluetoothProfile.HEADSET); + mBatteryLevel = 10; + + // Act & Assert: + // Get "10% battery" result with Battery Level 10. + assertThat(mCachedDevice.getTvConnectionSummary().toString()).isEqualTo("Battery 10%"); + } + + + @Test public void getConnectionSummary_testSingleProfileActiveDeviceHearingAid() { // Test without battery level // Set Hearing Aid profile to be connected and test connection state summary @@ -432,6 +667,26 @@ public class CachedBluetoothDeviceTest { } @Test + public void getTvConnectionSummary_testSingleProfileActiveDeviceHearingAid() { + // Test without battery level + // Set Hearing Aid profile to be connected and test connection state summary + updateProfileStatus(mHearingAidProfile, BluetoothProfile.STATE_CONNECTED); + assertThat(mCachedDevice.getTvConnectionSummary()).isNull(); + + // Set device as Active for Hearing Aid and test connection state summary + mCachedDevice.setHearingAidInfo(getLeftAshaHearingAidInfo()); + mCachedDevice.onActiveDeviceChanged(true, BluetoothProfile.HEARING_AID); + assertThat(mCachedDevice.getTvConnectionSummary().toString()).isEqualTo( + "Active, left only"); + + // Set Hearing Aid profile to be disconnected and test connection state summary + mCachedDevice.onActiveDeviceChanged(false, BluetoothProfile.HEARING_AID); + mCachedDevice.onProfileStateChanged(mHearingAidProfile, + BluetoothProfile.STATE_DISCONNECTED); + assertThat(mCachedDevice.getTvConnectionSummary()).isNull(); + } + + @Test public void getConnectionSummary_testHearingAidBatteryInactive_returnBattery() { // Arrange: // 1. Profile: {HEARING_AID, CONNECTED, Inactive} @@ -445,6 +700,19 @@ public class CachedBluetoothDeviceTest { } @Test + public void getTvConnectionSummary_testHearingAidBatteryInactive_returnBattery() { + // Arrange: + // 1. Profile: {HEARING_AID, CONNECTED, Inactive} + // 2. Battery Level: 10 + updateProfileStatus(mHearingAidProfile, BluetoothProfile.STATE_CONNECTED); + mBatteryLevel = 10; + + // Act & Assert: + // Get "10% battery" result without Battery Level. + assertThat(mCachedDevice.getTvConnectionSummary().toString()).isEqualTo("Battery 10%"); + } + + @Test public void getConnectionSummary_testHearingAidBatteryWithoutInCall_returnActiveBattery() { // Arrange: // 1. Profile: {HEARING_AID, Connected, Active} @@ -460,6 +728,21 @@ public class CachedBluetoothDeviceTest { } @Test + public void getTvConnectionSummary_testHearingAidBatteryWithoutInCall_returnBattery() { + // Arrange: + // 1. Profile: {HEARING_AID, Connected, Active} + // 2. Battery Level: 10 + // 3. Audio Manager: Normal (Without In Call) + updateProfileStatus(mHearingAidProfile, BluetoothProfile.STATE_CONNECTED); + mCachedDevice.onActiveDeviceChanged(true, BluetoothProfile.HEARING_AID); + mBatteryLevel = 10; + + // Act & Assert: + // Get "Active, 10% battery" result with Battery Level 10. + assertThat(mCachedDevice.getTvConnectionSummary().toString()).isEqualTo("Battery 10%"); + } + + @Test public void getConnectionSummary_testHearingAidRightEarInCall_returnActiveRightEar() { // Arrange: // 1. Profile: {HEARING_AID, Connected, Active, Right ear} @@ -475,6 +758,22 @@ public class CachedBluetoothDeviceTest { } @Test + public void getTvConnectionSummary_testHearingAidRightEarInCall_returnActiveRightEar() { + // Arrange: + // 1. Profile: {HEARING_AID, Connected, Active, Right ear} + // 2. Audio Manager: In Call + updateProfileStatus(mHearingAidProfile, BluetoothProfile.STATE_CONNECTED); + mCachedDevice.setHearingAidInfo(getRightAshaHearingAidInfo()); + mCachedDevice.onActiveDeviceChanged(true, BluetoothProfile.HEARING_AID); + mAudioManager.setMode(AudioManager.MODE_IN_CALL); + + // Act & Assert: + // Get "Active" result without Battery Level. + assertThat(mCachedDevice.getTvConnectionSummary().toString()).isEqualTo( + "Active, right only"); + } + + @Test public void getConnectionSummary_testHearingAidBothEarInCall_returnActiveBothEar() { // Arrange: // 1. Profile: {HEARING_AID, Connected, Active, Both ear} @@ -493,6 +792,25 @@ public class CachedBluetoothDeviceTest { } @Test + public void getTvConnectionSummary_testHearingAidBothEarInCall_returnActiveBothEar() { + // Arrange: + // 1. Profile: {HEARING_AID, Connected, Active, Both ear} + // 2. Audio Manager: In Call + mCachedDevice.setHearingAidInfo(getRightAshaHearingAidInfo()); + updateProfileStatus(mHearingAidProfile, BluetoothProfile.STATE_CONNECTED); + mSubCachedDevice.setHearingAidInfo(getLeftAshaHearingAidInfo()); + updateSubDeviceProfileStatus(mHearingAidProfile, BluetoothProfile.STATE_CONNECTED); + mCachedDevice.setSubDevice(mSubCachedDevice); + mCachedDevice.onActiveDeviceChanged(true, BluetoothProfile.HEARING_AID); + mAudioManager.setMode(AudioManager.MODE_IN_CALL); + + // Act & Assert: + // Get "Active" result without Battery Level. + assertThat(mCachedDevice.getTvConnectionSummary().toString()) + .isEqualTo("Active, left and right"); + } + + @Test public void getConnectionSummary_testHearingAidBatteryInCall_returnActiveBattery() { // Arrange: // 1. Profile: {HEARING_AID, Connected, Active} @@ -509,6 +827,22 @@ public class CachedBluetoothDeviceTest { } @Test + public void getTvConnectionSummary_testHearingAidBatteryInCall_returnBattery() { + // Arrange: + // 1. Profile: {HEARING_AID, Connected, Active} + // 2. Battery Level: 10 + // 3. Audio Manager: In Call + updateProfileStatus(mHearingAidProfile, BluetoothProfile.STATE_CONNECTED); + mCachedDevice.onActiveDeviceChanged(true, BluetoothProfile.HEARING_AID); + mAudioManager.setMode(AudioManager.MODE_IN_CALL); + mBatteryLevel = 10; + + // Act & Assert: + // Get "Active, 10% battery" result with Battery Level 10. + assertThat(mCachedDevice.getTvConnectionSummary().toString()).isEqualTo("Battery 10%"); + } + + @Test public void getConnectionSummary_testActiveDeviceLeAudioHearingAid() { // Test without battery level // Set HAP Client and LE Audio profile to be connected and test connection state summary @@ -529,6 +863,27 @@ public class CachedBluetoothDeviceTest { } @Test + public void getTvConnectionSummary_testActiveDeviceLeAudioHearingAid() { + // Test without battery level + // Set HAP Client and LE Audio profile to be connected and test connection state summary + when(mProfileManager.getHapClientProfile()).thenReturn(mHapClientProfile); + updateProfileStatus(mHapClientProfile, BluetoothProfile.STATE_CONNECTED); + updateProfileStatus(mLeAudioProfile, BluetoothProfile.STATE_CONNECTED); + assertThat(mCachedDevice.getTvConnectionSummary()).isNull(); + + // Set device as Active for LE Audio and test connection state summary + mCachedDevice.setHearingAidInfo(getLeftLeAudioHearingAidInfo()); + mCachedDevice.onActiveDeviceChanged(true, BluetoothProfile.LE_AUDIO); + assertThat(mCachedDevice.getTvConnectionSummary().toString()).isEqualTo( + "Active, left only"); + + // Set LE Audio profile to be disconnected and test connection state summary + mCachedDevice.onActiveDeviceChanged(false, BluetoothProfile.LE_AUDIO); + mCachedDevice.onProfileStateChanged(mLeAudioProfile, BluetoothProfile.STATE_DISCONNECTED); + assertThat(mCachedDevice.getTvConnectionSummary()).isNull(); + } + + @Test public void getConnectionSummary_testMemberDevicesExist_returnMinBattery() { // One device is active with battery level 70. mBatteryLevel = 70; @@ -545,6 +900,22 @@ public class CachedBluetoothDeviceTest { } @Test + public void getTvConnectionSummary_testMemberDevicesExist_returnMinBattery() { + // One device is active with battery level 70. + mBatteryLevel = 70; + updateProfileStatus(mA2dpProfile, BluetoothProfile.STATE_CONNECTED); + mCachedDevice.onActiveDeviceChanged(true, BluetoothProfile.A2DP); + + + // Add a member device with battery level 30. + int lowerBatteryLevel = 30; + mCachedDevice.addMemberDevice(mSubCachedDevice); + doAnswer((invocation) -> lowerBatteryLevel).when(mSubCachedDevice).getBatteryLevel(); + + assertThat(mCachedDevice.getTvConnectionSummary().toString()).isEqualTo("Battery 30%"); + } + + @Test public void getConnectionSummary_testMemberDevicesBatteryUnknown_returnMinBattery() { // One device is active with battery level 70. mBatteryLevel = 70; @@ -560,6 +931,21 @@ public class CachedBluetoothDeviceTest { } @Test + public void getTvConnectionSummary_testMemberDevicesBatteryUnknown_returnMinBattery() { + // One device is active with battery level 70. + mBatteryLevel = 70; + updateProfileStatus(mA2dpProfile, BluetoothProfile.STATE_CONNECTED); + mCachedDevice.onActiveDeviceChanged(true, BluetoothProfile.A2DP); + + // Add a member device with battery level unknown. + mCachedDevice.addMemberDevice(mSubCachedDevice); + doAnswer((invocation) -> BluetoothDevice.BATTERY_LEVEL_UNKNOWN).when( + mSubCachedDevice).getBatteryLevel(); + + assertThat(mCachedDevice.getTvConnectionSummary().toString()).isEqualTo("Battery 70%"); + } + + @Test public void getConnectionSummary_testAllDevicesBatteryUnknown_returnNoBattery() { // One device is active with battery level unknown. updateProfileStatus(mA2dpProfile, BluetoothProfile.STATE_CONNECTED); @@ -574,6 +960,20 @@ public class CachedBluetoothDeviceTest { } @Test + public void getTvConnectionSummary_testAllDevicesBatteryUnknown_returnNoBattery() { + // One device is active with battery level unknown. + updateProfileStatus(mA2dpProfile, BluetoothProfile.STATE_CONNECTED); + mCachedDevice.onActiveDeviceChanged(true, BluetoothProfile.A2DP); + + // Add a member device with battery level unknown. + mCachedDevice.addMemberDevice(mSubCachedDevice); + doAnswer((invocation) -> BluetoothDevice.BATTERY_LEVEL_UNKNOWN).when( + mSubCachedDevice).getBatteryLevel(); + + assertThat(mCachedDevice.getTvConnectionSummary().toString()).isEqualTo("Active"); + } + + @Test public void getConnectionSummary_testMultipleProfilesActiveDevice() { // Test without battery level // Set A2DP and HFP profiles to be connected and test connection state summary @@ -621,6 +1021,53 @@ public class CachedBluetoothDeviceTest { } @Test + public void getTvConnectionSummary_testMultipleProfilesActiveDevice() { + // Test without battery level + // Set A2DP and HFP profiles to be connected and test connection state summary + updateProfileStatus(mA2dpProfile, BluetoothProfile.STATE_CONNECTED); + updateProfileStatus(mHfpProfile, BluetoothProfile.STATE_CONNECTED); + assertThat(mCachedDevice.getTvConnectionSummary()).isNull(); + + // Set device as Active for A2DP and HFP and test connection state summary + mCachedDevice.onActiveDeviceChanged(true, BluetoothProfile.A2DP); + mCachedDevice.onActiveDeviceChanged(true, BluetoothProfile.HEADSET); + assertThat(mCachedDevice.getTvConnectionSummary().toString()).isEqualTo("Active"); + + // Test with battery level + mBatteryLevel = 10; + assertThat(mCachedDevice.getTvConnectionSummary().toString()).isEqualTo( + "Battery 10%"); + + // Disconnect A2DP only and test connection state summary + mCachedDevice.onActiveDeviceChanged(false, BluetoothProfile.A2DP); + updateProfileStatus(mA2dpProfile, BluetoothProfile.STATE_DISCONNECTED); + assertThat(mCachedDevice.getTvConnectionSummary().toString()).isEqualTo( + "Battery 10%"); + + // Disconnect HFP only and test connection state summary + mCachedDevice.onActiveDeviceChanged(false, BluetoothProfile.HEADSET); + updateProfileStatus(mHfpProfile, BluetoothProfile.STATE_DISCONNECTED); + updateProfileStatus(mA2dpProfile, BluetoothProfile.STATE_CONNECTED); + mCachedDevice.onActiveDeviceChanged(true, BluetoothProfile.A2DP); + assertThat(mCachedDevice.getTvConnectionSummary().toString()).isEqualTo( + "Battery 10%"); + + // Test with BluetoothDevice.BATTERY_LEVEL_UNKNOWN battery level + mBatteryLevel = BluetoothDevice.BATTERY_LEVEL_UNKNOWN; + // Set A2DP and HFP profiles to be connected, Active and test connection state summary + updateProfileStatus(mA2dpProfile, BluetoothProfile.STATE_CONNECTED); + updateProfileStatus(mHfpProfile, BluetoothProfile.STATE_CONNECTED); + mCachedDevice.onActiveDeviceChanged(true, BluetoothProfile.A2DP); + mCachedDevice.onActiveDeviceChanged(true, BluetoothProfile.HEADSET); + assertThat(mCachedDevice.getTvConnectionSummary().toString()).isEqualTo("Active"); + + // Set A2DP and HFP profiles to be disconnected and test connection state summary + updateProfileStatus(mA2dpProfile, BluetoothProfile.STATE_DISCONNECTED); + updateProfileStatus(mHfpProfile, BluetoothProfile.STATE_DISCONNECTED); + assertThat(mCachedDevice.getTvConnectionSummary()).isNull(); + } + + @Test public void getConnectionSummary_testMultipleProfilesInactive_returnPairing() { // Arrange: // 1. Profile 1: {A2DP, CONNECTED, Inactive} @@ -638,6 +1085,23 @@ public class CachedBluetoothDeviceTest { } @Test + public void getTvConnectionSummary_testMultipleProfilesInactive_returnPairing() { + // Arrange: + // 1. Profile 1: {A2DP, CONNECTED, Inactive} + // 2. Profile 2: {HEADSET, CONNECTED, Inactive} + // 3. Profile 3: {HEARING_AID, CONNECTED, Inactive} + // 4. Bond State: Bonding + updateProfileStatus(mA2dpProfile, BluetoothProfile.STATE_CONNECTED); + updateProfileStatus(mHfpProfile, BluetoothProfile.STATE_CONNECTED); + updateProfileStatus(mHearingAidProfile, BluetoothProfile.STATE_CONNECTED); + when(mDevice.getBondState()).thenReturn(BluetoothDevice.BOND_BONDING); + + // Act & Assert: + // Get "Pairing…" result without Battery Level. + assertThat(mCachedDevice.getTvConnectionSummary().toString()).isEqualTo("Pairing…"); + } + + @Test public void getConnectionSummary_trueWirelessActiveDeviceWithBattery_returnActiveWithBattery() { updateProfileStatus(mA2dpProfile, BluetoothProfile.STATE_CONNECTED); updateProfileStatus(mHfpProfile, BluetoothProfile.STATE_CONNECTED); @@ -656,6 +1120,24 @@ public class CachedBluetoothDeviceTest { } @Test + public void getTvConnectionSummary_trueWirelessActiveDeviceWithBattery_returnBattery() { + updateProfileStatus(mA2dpProfile, BluetoothProfile.STATE_CONNECTED); + updateProfileStatus(mHfpProfile, BluetoothProfile.STATE_CONNECTED); + updateProfileStatus(mHearingAidProfile, BluetoothProfile.STATE_CONNECTED); + when(mDevice.getBondState()).thenReturn(BluetoothDevice.BOND_BONDED); + mCachedDevice.onActiveDeviceChanged(true, BluetoothProfile.HEARING_AID); + when(mDevice.getMetadata(BluetoothDevice.METADATA_IS_UNTETHERED_HEADSET)).thenReturn( + "true".getBytes()); + when(mDevice.getMetadata(BluetoothDevice.METADATA_UNTETHERED_LEFT_BATTERY)).thenReturn( + TWS_BATTERY_LEFT.getBytes()); + when(mDevice.getMetadata(BluetoothDevice.METADATA_UNTETHERED_RIGHT_BATTERY)).thenReturn( + TWS_BATTERY_RIGHT.getBytes()); + + assertThat(mCachedDevice.getTvConnectionSummary().toString()).isEqualTo( + "Left 15% Right 25%"); + } + + @Test public void getConnectionSummary_trueWirelessDeviceWithBattery_returnActiveWithBattery() { updateProfileStatus(mA2dpProfile, BluetoothProfile.STATE_CONNECTED); updateProfileStatus(mHfpProfile, BluetoothProfile.STATE_CONNECTED); @@ -673,6 +1155,84 @@ public class CachedBluetoothDeviceTest { } @Test + public void getTvConnectionSummary_trueWirelessDeviceWithBattery_returnBattery() { + updateProfileStatus(mA2dpProfile, BluetoothProfile.STATE_CONNECTED); + updateProfileStatus(mHfpProfile, BluetoothProfile.STATE_CONNECTED); + updateProfileStatus(mHearingAidProfile, BluetoothProfile.STATE_CONNECTED); + when(mDevice.getBondState()).thenReturn(BluetoothDevice.BOND_BONDED); + when(mDevice.getMetadata(BluetoothDevice.METADATA_IS_UNTETHERED_HEADSET)).thenReturn( + "true".getBytes()); + when(mDevice.getMetadata(BluetoothDevice.METADATA_UNTETHERED_LEFT_BATTERY)).thenReturn( + TWS_BATTERY_LEFT.getBytes()); + when(mDevice.getMetadata(BluetoothDevice.METADATA_UNTETHERED_RIGHT_BATTERY)).thenReturn( + TWS_BATTERY_RIGHT.getBytes()); + + assertThat(mCachedDevice.getTvConnectionSummary().toString()).isEqualTo( + "Left 15% Right 25%"); + } + + @Test + public void getTvConnectionSummary_trueWirelessDeviceWithLowBattery() { + updateProfileStatus(mA2dpProfile, BluetoothProfile.STATE_CONNECTED); + updateProfileStatus(mHfpProfile, BluetoothProfile.STATE_CONNECTED); + updateProfileStatus(mHearingAidProfile, BluetoothProfile.STATE_CONNECTED); + when(mDevice.getBondState()).thenReturn(BluetoothDevice.BOND_BONDED); + when(mDevice.getMetadata(BluetoothDevice.METADATA_IS_UNTETHERED_HEADSET)).thenReturn( + "true".getBytes()); + when(mDevice.getMetadata(BluetoothDevice.METADATA_UNTETHERED_LEFT_BATTERY)).thenReturn( + TWS_BATTERY_LEFT.getBytes()); + when(mDevice.getMetadata(BluetoothDevice.METADATA_UNTETHERED_RIGHT_BATTERY)).thenReturn( + TWS_BATTERY_RIGHT.getBytes()); + + int lowBatteryColor = mContext.getColor(LOW_BATTERY_COLOR); + + // Default low battery threshold, only left battery is low + CharSequence summary = mCachedDevice.getTvConnectionSummary(LOW_BATTERY_COLOR); + assertForegroundColorSpan(summary, 0, 0, 8, lowBatteryColor); + assertThat(summary.toString()).isEqualTo("Left 15% Right 25%"); + + // Lower threshold, neither battery should be low + when(mDevice.getMetadata(BluetoothDevice.METADATA_UNTETHERED_LEFT_LOW_BATTERY_THRESHOLD)) + .thenReturn(TWS_LOW_BATTERY_THRESHOLD_LOW.getBytes()); + when(mDevice.getMetadata(BluetoothDevice.METADATA_UNTETHERED_RIGHT_LOW_BATTERY_THRESHOLD)) + .thenReturn(TWS_LOW_BATTERY_THRESHOLD_LOW.getBytes()); + summary = mCachedDevice.getTvConnectionSummary(LOW_BATTERY_COLOR); + assertNoForegroundColorSpans(summary); + assertThat(summary.toString()).isEqualTo("Left 15% Right 25%"); + + + // Higher Threshold, both batteries are low + when(mDevice.getMetadata(BluetoothDevice.METADATA_UNTETHERED_LEFT_LOW_BATTERY_THRESHOLD)) + .thenReturn(TWS_LOW_BATTERY_THRESHOLD_HIGH.getBytes()); + when(mDevice.getMetadata(BluetoothDevice.METADATA_UNTETHERED_RIGHT_LOW_BATTERY_THRESHOLD)) + .thenReturn(TWS_LOW_BATTERY_THRESHOLD_HIGH.getBytes()); + summary = mCachedDevice.getTvConnectionSummary(LOW_BATTERY_COLOR); + assertForegroundColorSpan(summary, 0, 0, 8, lowBatteryColor); + assertForegroundColorSpan(summary, 1, 9, 18, lowBatteryColor); + assertThat(summary.toString()).isEqualTo("Left 15% Right 25%"); + } + + private void assertNoForegroundColorSpans(CharSequence charSequence) { + if (charSequence instanceof Spannable) { + Spannable summarySpan = (Spannable) charSequence; + ForegroundColorSpan[] spans = summarySpan.getSpans(0, summarySpan.length(), + ForegroundColorSpan.class); + assertThat(spans).isEmpty(); + } + } + + private void assertForegroundColorSpan(CharSequence charSequence, int indexInSpannable, + int start, int end, int color) { + assertThat(charSequence).isInstanceOf(Spannable.class); + Spannable summarySpan = (Spannable) charSequence; + ForegroundColorSpan[] spans = summarySpan.getSpans(0, summarySpan.length(), + ForegroundColorSpan.class); + assertThat(spans[indexInSpannable].getForegroundColor()).isEqualTo(color); + assertThat(summarySpan.getSpanStart(spans[indexInSpannable])).isEqualTo(start); + assertThat(summarySpan.getSpanEnd(spans[indexInSpannable])).isEqualTo(end); + } + + @Test public void getCarConnectionSummary_singleProfileConnectDisconnect() { // Test without battery level // Set PAN profile to be connected and test connection state summary @@ -1136,6 +1696,18 @@ public class CachedBluetoothDeviceTest { } @Test + public void getTvConnectionSummary_profileConnectedFail_showErrorMessage() { + final A2dpProfile profile = mock(A2dpProfile.class); + mCachedDevice.onProfileStateChanged(profile, BluetoothProfile.STATE_CONNECTED); + mCachedDevice.setProfileConnectedStatus(BluetoothProfile.A2DP, true); + + when(profile.getConnectionStatus(mDevice)).thenReturn(BluetoothProfile.STATE_CONNECTED); + + assertThat(mCachedDevice.getTvConnectionSummary().toString()).isEqualTo( + mContext.getString(R.string.profile_connect_timeout_subtext)); + } + + @Test public void onUuidChanged_bluetoothClassIsNull_shouldNotCrash() { mShadowBluetoothAdapter.setUuids(PbapServerProfile.PBAB_CLIENT_UUIDS); when(mDevice.getUuids()).thenReturn(PbapServerProfile.PBAB_CLIENT_UUIDS); diff --git a/packages/SettingsProvider/Android.bp b/packages/SettingsProvider/Android.bp index a4a9290b16ab..adebdcdcf26a 100644 --- a/packages/SettingsProvider/Android.bp +++ b/packages/SettingsProvider/Android.bp @@ -33,6 +33,7 @@ android_library { ], static_libs: [ "device_config_service_flags_java", + "libaconfig_java_proto_lite", "SettingsLibDeviceStateRotationLock", "SettingsLibDisplayUtils", ], diff --git a/packages/SettingsProvider/src/com/android/providers/settings/DeviceConfigService.java b/packages/SettingsProvider/src/com/android/providers/settings/DeviceConfigService.java index 969f1fde604e..976ba215d349 100644 --- a/packages/SettingsProvider/src/com/android/providers/settings/DeviceConfigService.java +++ b/packages/SettingsProvider/src/com/android/providers/settings/DeviceConfigService.java @@ -22,6 +22,8 @@ import static android.provider.Settings.Config.SYNC_DISABLED_MODE_UNTIL_REBOOT; import static com.android.providers.settings.Flags.supportOverrides; +import android.aconfig.Aconfig.parsed_flag; +import android.aconfig.Aconfig.parsed_flags; import android.annotation.SuppressLint; import android.app.ActivityManager; import android.content.AttributionSource; @@ -39,12 +41,13 @@ import android.provider.DeviceConfigShellCommandHandler; import android.provider.Settings; import android.provider.Settings.Config.SyncDisabledMode; import android.provider.UpdatableDeviceConfigServiceReadiness; +import android.util.Slog; import com.android.internal.util.FastPrintWriter; import java.io.File; import java.io.FileDescriptor; -import java.io.FileNotFoundException; +import java.io.FileInputStream; import java.io.FileOutputStream; import java.io.IOException; import java.io.PrintWriter; @@ -56,18 +59,17 @@ import java.util.HashMap; import java.util.HashSet; import java.util.List; import java.util.Map; -import java.util.Scanner; /** * Receives shell commands from the command line related to device config flags, and dispatches them * to the SettingsProvider. */ public final class DeviceConfigService extends Binder { - private static final List<String> aconfigTextProtoFilesOnDevice = List.of( - "/system/etc/aconfig_flags.textproto", - "/system_ext/etc/aconfig_flags.textproto", - "/system_ext/etc/aconfig_flags.textproto", - "/vendor/etc/aconfig_flags.textproto"); + 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", + "/vendor/etc/aconfig_flags.pb"); private static final List<String> PRIVATE_NAMESPACES = List.of( "device_config_overrides", @@ -76,6 +78,8 @@ public final class DeviceConfigService extends Binder { final SettingsProvider mProvider; + private static final String TAG = "DeviceConfigService"; + public DeviceConfigService(SettingsProvider provider) { mProvider = provider; } @@ -94,62 +98,55 @@ public final class DeviceConfigService extends Binder { @Override protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) { - final IContentProvider iprovider = mProvider.getIContentProvider(); - pw.println("DeviceConfig flags:"); - for (String line : MyShellCommand.listAll(iprovider)) { - pw.println(line); - } - - ArrayList<String> missingFiles = new ArrayList<String>(); - for (String fileName : aconfigTextProtoFilesOnDevice) { - File aconfigFile = new File(fileName); - if (!aconfigFile.exists()) { - missingFiles.add(fileName); + final IContentProvider iprovider = mProvider.getIContentProvider(); + pw.println("DeviceConfig flags:"); + for (String line : MyShellCommand.listAll(iprovider)) { + pw.println(line); } - } - if (missingFiles.isEmpty()) { - pw.println("\nAconfig flags:"); - for (String name : MyShellCommand.listAllAconfigFlags(iprovider)) { - pw.println(name); + ArrayList<String> missingFiles = new ArrayList<String>(); + for (String fileName : sAconfigTextProtoFilesOnDevice) { + File aconfigFile = new File(fileName); + if (!aconfigFile.exists()) { + missingFiles.add(fileName); + } } - } else { - pw.println("\nFailed to dump aconfig flags due to missing files:"); - for (String fileName : missingFiles) { - pw.println(fileName); + + if (missingFiles.isEmpty()) { + pw.println("\nAconfig flags:"); + for (String name : MyShellCommand.listAllAconfigFlags(iprovider)) { + pw.println(name); + } + } else { + pw.println("\nFailed to dump aconfig flags due to missing files:"); + for (String fileName : missingFiles) { + pw.println(fileName); + } } - } } private static HashSet<String> getAconfigFlagNamesInDeviceConfig() { HashSet<String> nameSet = new HashSet<String>(); - for (String fileName : aconfigTextProtoFilesOnDevice) { - try{ - File aconfigFile = new File(fileName); - String packageName = ""; - String namespace = ""; - String name = ""; - - try (Scanner scanner = new Scanner(aconfigFile)) { - while (scanner.hasNextLine()) { - String data = scanner.nextLine().replaceAll("\\s+",""); - if (data.startsWith("package:\"")) { - packageName = data.substring(9, data.length()-1); - } else if (data.startsWith("name:\"")) { - name = data.substring(6, data.length()-1); - } else if (data.startsWith("namespace:\"")) { - namespace = data.substring(11, data.length()-1); - nameSet.add(namespace + "/" + packageName + "." + name); + try { + for (String fileName : sAconfigTextProtoFilesOnDevice) { + byte[] contents = (new FileInputStream(fileName)).readAllBytes(); + parsed_flags parsedFlags = parsed_flags.parseFrom(contents); + if (parsedFlags == null) { + Slog.e(TAG, "failed to parse aconfig protobuf from " + fileName); + continue; } - } - } - } catch (FileNotFoundException e) { - continue; - } + for (parsed_flag flag : parsedFlags.getParsedFlagList()) { + String namespace = flag.getNamespace(); + String packageName = flag.getPackage(); + String name = flag.getName(); + nameSet.add(namespace + "/" + packageName + "." + name); + } + } + } catch (IOException e) { + Slog.e(TAG, "failed to read aconfig protobuf", e); } - - return nameSet; + return nameSet; } private void callUpdableDeviceConfigShellCommandHandler(FileDescriptor in, FileDescriptor out, diff --git a/packages/SystemUI/Android.bp b/packages/SystemUI/Android.bp index 17cc9f8135f4..f78811f5bb14 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", 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..8eff9bfcf099 100644 --- a/packages/SystemUI/aconfig/systemui.aconfig +++ b/packages/SystemUI/aconfig/systemui.aconfig @@ -51,3 +51,11 @@ 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" +} 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/src/com/android/keyguard/LockIconViewController.java b/packages/SystemUI/src/com/android/keyguard/LockIconViewController.java index 611283f12984..181aa5c1e648 100644 --- a/packages/SystemUI/src/com/android/keyguard/LockIconViewController.java +++ b/packages/SystemUI/src/com/android/keyguard/LockIconViewController.java @@ -26,7 +26,6 @@ import static com.android.systemui.doze.util.BurnInHelperKt.getBurnInOffset; import static com.android.systemui.flags.Flags.DOZING_MIGRATION_1; import static com.android.systemui.flags.Flags.LOCKSCREEN_WALLPAPER_DREAM_ENABLED; import static com.android.systemui.flags.Flags.NEW_AOD_TRANSITION; -import static com.android.systemui.flags.Flags.ONE_WAY_HAPTICS_API_MIGRATION; import static com.android.systemui.util.kotlin.JavaAdapterKt.collectFlow; import android.annotation.SuppressLint; @@ -37,7 +36,6 @@ import android.graphics.Point; import android.graphics.Rect; import android.hardware.biometrics.BiometricAuthenticator; import android.hardware.biometrics.BiometricSourceType; -import android.os.Process; import android.os.VibrationAttributes; import android.util.DisplayMetrics; import android.util.Log; @@ -793,33 +791,15 @@ public class LockIconViewController implements Dumpable { @VisibleForTesting void vibrateOnTouchExploration() { - if (mFeatureFlags.isEnabled(ONE_WAY_HAPTICS_API_MIGRATION)) { - mVibrator.performHapticFeedback( - mView, - HapticFeedbackConstants.CONTEXT_CLICK - ); - } else { - mVibrator.vibrate( - Process.myUid(), - mContext.getOpPackageName(), - UdfpsController.EFFECT_CLICK, - "lock-icon-down", - TOUCH_VIBRATION_ATTRIBUTES); - } + mVibrator.performHapticFeedback( + mView, + HapticFeedbackConstants.CONTEXT_CLICK + ); } @VisibleForTesting void vibrateOnLongPress() { - if (mFeatureFlags.isEnabled(ONE_WAY_HAPTICS_API_MIGRATION)) { - mVibrator.performHapticFeedback(mView, UdfpsController.LONG_PRESS); - } else { - mVibrator.vibrate( - Process.myUid(), - mContext.getOpPackageName(), - UdfpsController.EFFECT_CLICK, - "lock-screen-lock-icon-longpress", - TOUCH_VIBRATION_ATTRIBUTES); - } + mVibrator.performHapticFeedback(mView, UdfpsController.LONG_PRESS); } private final AuthController.Callback mAuthControllerCallback = new AuthController.Callback() { 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/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/doze/DozeScreenBrightness.java b/packages/SystemUI/src/com/android/systemui/doze/DozeScreenBrightness.java index 4cade77c8312..323ed9871dc3 100644 --- a/packages/SystemUI/src/com/android/systemui/doze/DozeScreenBrightness.java +++ b/packages/SystemUI/src/com/android/systemui/doze/DozeScreenBrightness.java @@ -261,6 +261,13 @@ public class DozeScreenBrightness extends BroadcastReceiver implements DozeMachi } //TODO: brightnessfloat change usages to float. private int clampToUserSetting(int brightness) { + int screenBrightnessModeSetting = mSystemSettings.getIntForUser( + Settings.System.SCREEN_BRIGHTNESS_MODE, + Settings.System.SCREEN_BRIGHTNESS_MODE_MANUAL, UserHandle.USER_CURRENT); + if (screenBrightnessModeSetting == Settings.System.SCREEN_BRIGHTNESS_MODE_AUTOMATIC) { + return brightness; + } + int userSetting = mSystemSettings.getIntForUser( Settings.System.SCREEN_BRIGHTNESS, Integer.MAX_VALUE, UserHandle.USER_CURRENT); diff --git a/packages/SystemUI/src/com/android/systemui/flags/Flags.kt b/packages/SystemUI/src/com/android/systemui/flags/Flags.kt index f4a9f739d187..0c364e1e710d 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) @@ -414,15 +413,14 @@ object Flags { 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/ui/binder/KeyguardRootViewBinder.kt b/packages/SystemUI/src/com/android/systemui/keyguard/ui/binder/KeyguardRootViewBinder.kt index 4d5c503d1c4e..67a12b06de0f 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 @@ -22,6 +22,8 @@ import android.view.View import android.view.View.OnLayoutChangeListener import android.view.ViewGroup import android.view.ViewGroup.OnHierarchyChangeListener +import android.view.WindowInsets +import android.view.WindowInsets.Type import androidx.lifecycle.Lifecycle import androidx.lifecycle.repeatOnLifecycle import com.android.internal.jank.InteractionJankMonitor @@ -242,11 +244,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 +297,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,6 +304,11 @@ object KeyguardRootViewBinder { nsslPlaceholder.bottom.toFloat(), ) } + + val ksv = v.findViewById(R.id.keyguard_status_view) as View? + if (ksv != null) { + viewModel.statusViewTop = ksv.top + } } } 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..e12da53287ed 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 @@ -65,7 +65,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 +107,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, ) 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/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/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..7ead4bf3ed66 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 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..d524637443cb 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 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/tests/src/com/android/keyguard/LockIconViewControllerTest.java b/packages/SystemUI/tests/src/com/android/keyguard/LockIconViewControllerTest.java index 4bacc3dfca0d..adcec10f9172 100644 --- a/packages/SystemUI/tests/src/com/android/keyguard/LockIconViewControllerTest.java +++ b/packages/SystemUI/tests/src/com/android/keyguard/LockIconViewControllerTest.java @@ -20,7 +20,6 @@ import static android.hardware.biometrics.BiometricAuthenticator.TYPE_FINGERPRIN import static com.android.keyguard.LockIconView.ICON_LOCK; import static com.android.keyguard.LockIconView.ICON_UNLOCK; -import static com.android.systemui.flags.Flags.ONE_WAY_HAPTICS_API_MIGRATION; import static org.mockito.ArgumentMatchers.any; import static org.mockito.Mockito.anyBoolean; @@ -354,26 +353,8 @@ public class LockIconViewControllerTest extends LockIconViewControllerBaseTest { } @Test - public void playHaptic_onTouchExploration_NoOneWayHaptics_usesVibrate() { - mFeatureFlags.set(ONE_WAY_HAPTICS_API_MIGRATION, false); - - // WHEN request to vibrate on touch exploration - mUnderTest.vibrateOnTouchExploration(); - - // THEN vibrates - verify(mVibrator).vibrate( - anyInt(), - any(), - eq(UdfpsController.EFFECT_CLICK), - eq("lock-icon-down"), - any()); - } - - @Test - public void playHaptic_onTouchExploration_withOneWayHaptics_performHapticFeedback() { - mFeatureFlags.set(ONE_WAY_HAPTICS_API_MIGRATION, true); - - // WHEN request to vibrate on touch exploration + public void playHaptic_onTouchExploration_performHapticFeedback() { + // WHEN request to vibrate on touch exploration mUnderTest.vibrateOnTouchExploration(); // THEN performHapticFeedback is used @@ -381,25 +362,7 @@ public class LockIconViewControllerTest extends LockIconViewControllerBaseTest { } @Test - public void playHaptic_onLongPress_NoOneWayHaptics_usesVibrate() { - mFeatureFlags.set(ONE_WAY_HAPTICS_API_MIGRATION, false); - - // WHEN request to vibrate on long press - mUnderTest.vibrateOnLongPress(); - - // THEN uses vibrate - verify(mVibrator).vibrate( - anyInt(), - any(), - eq(UdfpsController.EFFECT_CLICK), - eq("lock-screen-lock-icon-longpress"), - any()); - } - - @Test - public void playHaptic_onLongPress_withOneWayHaptics_performHapticFeedback() { - mFeatureFlags.set(ONE_WAY_HAPTICS_API_MIGRATION, true); - + public void playHaptic_onLongPress_performHapticFeedback() { // WHEN request to vibrate on long press mUnderTest.vibrateOnLongPress(); @@ -411,7 +374,6 @@ public class LockIconViewControllerTest extends LockIconViewControllerBaseTest { public void longPress_showBouncer_sceneContainerNotEnabled() { init(/* useMigrationFlag= */ false); mSceneTestUtils.getSceneContainerFlags().setEnabled(false); - mFeatureFlags.set(ONE_WAY_HAPTICS_API_MIGRATION, true); when(mFalsingManager.isFalseLongTap(anyInt())).thenReturn(false); // WHEN longPress @@ -426,7 +388,6 @@ public class LockIconViewControllerTest extends LockIconViewControllerBaseTest { public void longPress_showBouncer() { init(/* useMigrationFlag= */ false); mSceneTestUtils.getSceneContainerFlags().setEnabled(true); - mFeatureFlags.set(ONE_WAY_HAPTICS_API_MIGRATION, true); when(mFalsingManager.isFalseLongTap(anyInt())).thenReturn(false); // WHEN longPress @@ -441,7 +402,6 @@ public class LockIconViewControllerTest extends LockIconViewControllerBaseTest { public void longPress_falsingTriggered_doesNotShowBouncer() { init(/* useMigrationFlag= */ false); mSceneTestUtils.getSceneContainerFlags().setEnabled(true); - mFeatureFlags.set(ONE_WAY_HAPTICS_API_MIGRATION, true); when(mFalsingManager.isFalseLongTap(anyInt())).thenReturn(true); // WHEN longPress diff --git a/packages/SystemUI/tests/src/com/android/systemui/accessibility/WindowMagnificationControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/accessibility/WindowMagnificationControllerTest.java index 06421dbbf2bb..044881e57897 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/accessibility/WindowMagnificationControllerTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/accessibility/WindowMagnificationControllerTest.java @@ -1072,6 +1072,7 @@ public class WindowMagnificationControllerTest extends SysuiTestCase { assertTrue(TextUtils.equals(newA11yWindowTitle, getAccessibilityWindowTitle())); } + @Ignore("it's flaky in presubmit but works in abtd, filter for now. b/305654925") @Test public void onSingleTap_enabled_scaleAnimates() { mInstrumentation.runOnMainSync(() -> { 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/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/doze/DozeScreenBrightnessTest.java b/packages/SystemUI/tests/src/com/android/systemui/doze/DozeScreenBrightnessTest.java index 3af444a789c5..27fd3b13d55a 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/doze/DozeScreenBrightnessTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/doze/DozeScreenBrightnessTest.java @@ -165,12 +165,28 @@ public class DozeScreenBrightnessTest extends SysuiTestCase { int maxBrightness = 3; when(mSystemSettings.getIntForUser(eq(Settings.System.SCREEN_BRIGHTNESS), anyInt(), eq(UserHandle.USER_CURRENT))).thenReturn(maxBrightness); + when(mSystemSettings.getIntForUser(eq(Settings.System.SCREEN_BRIGHTNESS_MODE), anyInt(), + eq(UserHandle.USER_CURRENT))) + .thenReturn(Settings.System.SCREEN_BRIGHTNESS_MODE_MANUAL); mScreen.transitionTo(UNINITIALIZED, INITIALIZED); assertEquals(maxBrightness, mServiceFake.screenBrightness); } @Test + public void testAod_usesLightSensorNotClampingToAutoBrightnessValue() { + int maxBrightness = 3; + when(mSystemSettings.getIntForUser(eq(Settings.System.SCREEN_BRIGHTNESS), anyInt(), + eq(UserHandle.USER_CURRENT))).thenReturn(maxBrightness); + when(mSystemSettings.getIntForUser(eq(Settings.System.SCREEN_BRIGHTNESS_MODE), anyInt(), + eq(UserHandle.USER_CURRENT))) + .thenReturn(Settings.System.SCREEN_BRIGHTNESS_MODE_AUTOMATIC); + + mScreen.transitionTo(UNINITIALIZED, INITIALIZED); + assertEquals(DEFAULT_BRIGHTNESS, mServiceFake.screenBrightness); + } + + @Test public void doze_doesNotUseLightSensor() { // GIVEN the device is DOZE and the display state changes to ON mScreen.transitionTo(UNINITIALIZED, INITIALIZED); 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..b80771ff646c 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 @@ -179,6 +179,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 +202,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) 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/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..21de73ac4c7b 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,28 @@ 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, + ) + .also { it.mUseHeadsUp = true } + ) + } // Tests of internals of the wrapper: 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..c0aaa3670ace 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,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.app.ActivityManager @@ -9,12 +25,15 @@ import android.app.NotificationManager.IMPORTANCE_HIGH 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.PowerManager +import android.provider.Settings.Global.HEADS_UP_NOTIFICATIONS_ENABLED +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 @@ -31,8 +50,11 @@ 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 junit.framework.Assert.assertFalse import junit.framework.Assert.assertTrue import org.junit.Before import org.junit.Test @@ -45,6 +67,7 @@ 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() @@ -53,164 +76,363 @@ abstract class VisualInterruptionDecisionProviderTestBase : SysuiTestCase() { protected val mainHandler: Handler = mock() 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) } @Test fun testShouldPeek() { - ensureStateForPeek() + ensurePeekState() + assertShouldHeadsUp(buildPeekEntry()) + } - assertTrue(provider.makeUnloggedHeadsUpDecision(createPeekEntry()).shouldInterrupt) + @Test + fun testShouldPeek_defaultLegacySuppressor() { + ensurePeekState() + provider.addLegacySuppressor(neverSuppresses) + assertShouldHeadsUp(buildPeekEntry()) } @Test - fun testShouldPulse() { - ensureStateForPulse() + fun testShouldNotPeek_legacySuppressInterruptions() { + ensurePeekState() + provider.addLegacySuppressor(alwaysSuppressesInterruptions) + assertShouldNotHeadsUp(buildPeekEntry()) + } - assertTrue(provider.makeUnloggedHeadsUpDecision(createPulseEntry()).shouldInterrupt) + @Test + fun testShouldNotPeek_legacySuppressAwakeInterruptions() { + ensurePeekState() + provider.addLegacySuppressor(alwaysSuppressesAwakeInterruptions) + assertShouldNotHeadsUp(buildPeekEntry()) } @Test - fun testShouldFsi_awake() { - ensureStateForAwakeFsi() + fun testShouldNotPeek_legacySuppressAwakeHeadsUp() { + ensurePeekState() + provider.addLegacySuppressor(alwaysSuppressesAwakeHeadsUp) + assertShouldNotHeadsUp(buildPeekEntry()) + } - assertTrue(provider.makeUnloggedFullScreenIntentDecision(createFsiEntry()).shouldInterrupt) + @Test + fun testShouldPulse() { + ensurePulseState() + assertShouldHeadsUp(buildPulseEntry()) } @Test - fun testShouldFsi_dreaming() { - ensureStateForDreamingFsi() + fun testShouldPulse_defaultLegacySuppressor() { + ensurePulseState() + provider.addLegacySuppressor(neverSuppresses) + assertShouldHeadsUp(buildPulseEntry()) + } - assertTrue(provider.makeUnloggedFullScreenIntentDecision(createFsiEntry()).shouldInterrupt) + @Test + fun testShouldNotPulse_legacySuppressInterruptions() { + ensurePulseState() + provider.addLegacySuppressor(alwaysSuppressesInterruptions) + assertShouldNotHeadsUp(buildPulseEntry()) } @Test - fun testShouldFsi_keyguard() { - ensureStateForKeyguardFsi() + fun testShouldPulse_legacySuppressAwakeInterruptions() { + ensurePulseState() + provider.addLegacySuppressor(alwaysSuppressesAwakeInterruptions) + assertShouldHeadsUp(buildPulseEntry()) + } - assertTrue(provider.makeUnloggedFullScreenIntentDecision(createFsiEntry()).shouldInterrupt) + @Test + fun testShouldPulse_legacySuppressAwakeHeadsUp() { + ensurePulseState() + provider.addLegacySuppressor(alwaysSuppressesAwakeHeadsUp) + assertShouldHeadsUp(buildPulseEntry()) } @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 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 { + hunSnoozed?.let { whenever(headsUpManager.isSnoozed(TEST_PACKAGE)).thenReturn(it) } + + isAodPowerSave?.let { batteryController.setIsAodPowerSave(it) } + + isDozing?.let { statusBarStateController.dozing = it } + + isDreaming?.let { statusBarStateController.dreaming = it } + + isInteractive?.let { whenever(powerManager.isInteractive).thenReturn(it) } + + 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 { + keyguardShouldHideNotification = false + apply(block) } - .setContentTitle(TEST_CONTENT_TITLE) - .setContentText(TEST_CONTENT_TEXT) - .build() + .run(this::setState) + + private fun ensurePeekState(block: State.() -> Unit = {}) = ensureState { + hunSnoozed = false + isDozing = false + isDreaming = false + isScreenOn = true + run(block) } - private fun createBubbleMetadata(): BubbleMetadata { - val pendingIntent = - PendingIntent.getActivity( - context, - /* requestCode = */ 0, - Intent().setPackage(context.packageName), - FLAG_MUTABLE - ) + private fun ensurePulseState(block: State.() -> Unit = {}) = ensureState { + isAodPowerSave = false + isDozing = true + pulseOnNotificationsEnabled = true + run(block) + } - val icon = Icon.createWithResource(context.resources, R.drawable.android) + private fun ensureBubbleState(block: State.() -> Unit = {}) = ensureState(block) - return BubbleMetadata.Builder(pendingIntent, icon).build() + private fun ensureNotInteractiveFsiState(block: State.() -> Unit = {}) = ensureState { + isDreaming = false + isInteractive = false + statusBarState = SHADE + run(block) } - private fun createEntry( - notif: Notification, - importance: Int = IMPORTANCE_DEFAULT, - canBubble: Boolean? = null - ): NotificationEntry { - return NotificationEntryBuilder() - .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) - } - } - .build() + 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 createPeekEntry() = createEntry(notif = createNotif(), importance = IMPORTANCE_HIGH) + private fun assertShouldHeadsUp(entry: NotificationEntry) = + provider.makeUnloggedHeadsUpDecision(entry).let { + assertTrue("unexpected suppressed HUN: ${it.logReason}", it.shouldInterrupt) + } + + private fun assertShouldNotHeadsUp(entry: NotificationEntry) = + provider.makeUnloggedHeadsUpDecision(entry).let { + assertFalse("unexpected unsuppressed HUN: ${it.logReason}", it.shouldInterrupt) + } + + private fun assertShouldBubble(entry: NotificationEntry) = + provider.makeAndLogBubbleDecision(entry).let { + assertTrue("unexpected suppressed bubble: ${it.logReason}", it.shouldInterrupt) + } + + 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 createPulseEntry() = - createEntry(notif = createNotif(), importance = IMPORTANCE_HIGH).also { - modifyRanking(it).setVisibilityOverride(VISIBILITY_NO_OVERRIDE).build() + private fun assertShouldNotFsi(entry: NotificationEntry) = + provider.makeUnloggedFullScreenIntentDecision(entry).let { + assertFalse("unexpected unsuppressed FSI: ${it.logReason}", it.shouldInterrupt) } - private fun createFsiEntry() = - createEntry(notif = createNotif(hasFsi = true), importance = IMPORTANCE_HIGH) + 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 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() + .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 buildFsiEntry(block: EntryBuilder.() -> Unit = {}) = buildEntry { + importance = IMPORTANCE_HIGH + hasFsi = true + run(block) + } + + private fun buildBubbleEntry(block: EntryBuilder.() -> Unit = {}) = buildEntry { + canBubble = true + hasBubbleMetadata = true + run(block) + } - private fun createBubbleEntry() = - createEntry( - notif = createNotif(bubbleMetadata = createBubbleMetadata()), - importance = IMPORTANCE_HIGH, - canBubble = true - ) + 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/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/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/companion/java/com/android/server/companion/virtual/VirtualDeviceManagerService.java b/services/companion/java/com/android/server/companion/virtual/VirtualDeviceManagerService.java index 959f69ea483f..92af68bc40a3 100644 --- a/services/companion/java/com/android/server/companion/virtual/VirtualDeviceManagerService.java +++ b/services/companion/java/com/android/server/companion/virtual/VirtualDeviceManagerService.java @@ -361,14 +361,6 @@ public class VirtualDeviceManagerService extends SystemService { @NonNull IVirtualDeviceSoundEffectListener soundEffectListener) { createVirtualDevice_enforcePermission(); attributionSource.enforceCallingUid(); - final long identity = Binder.clearCallingIdentity(); - try { - if (Flags.moreLogs()) { - Slog.i(TAG, "Creating VirtualDevice"); - } - } finally { - Binder.restoreCallingIdentity(identity); - } final int callingUid = getCallingUid(); final String packageName = attributionSource.getPackageName(); diff --git a/services/core/java/com/android/server/StorageManagerService.java b/services/core/java/com/android/server/StorageManagerService.java index 15fc2dc15d02..02235096ac15 100644 --- a/services/core/java/com/android/server/StorageManagerService.java +++ b/services/core/java/com/android/server/StorageManagerService.java @@ -61,6 +61,7 @@ import android.app.KeyguardManager; import android.app.PendingIntent; import android.app.admin.SecurityLog; import android.app.usage.StorageStatsManager; +import android.content.AttributionSource; import android.content.BroadcastReceiver; import android.content.Context; import android.content.Intent; @@ -2138,8 +2139,13 @@ class StorageManagerService extends IStorageManager.Stub | MATCH_DIRECT_BOOT_UNAWARE | MATCH_UNINSTALLED_PACKAGES | MATCH_ANY_USER, userId, Process.myUid())) { try { - boolean hasLegacy = mIAppOpsService.checkOperation(OP_LEGACY_STORAGE, ai.uid, - ai.packageName) == MODE_ALLOWED; + final AttributionSource attributionSource = new AttributionSource.Builder(ai.uid) + .setPackageName(ai.packageName) + .build(); + boolean hasLegacy = + mIAppOpsService.checkOperationWithState( + OP_LEGACY_STORAGE, attributionSource.asState()) + == MODE_ALLOWED; updateLegacyStorageApps(ai.packageName, ai.uid, hasLegacy); } catch (RemoteException e) { Slog.e(TAG, "Failed to check legacy op for package " + ai.packageName, e); @@ -4540,8 +4546,11 @@ class StorageManagerService extends IStorageManager.Stub // sharing the uid and allow same level of storage access for all packages even if // one of the packages has the appop granted. for (String uidPackageName : packagesForUid) { - if (mIAppOpsService.checkOperation( - OP_REQUEST_INSTALL_PACKAGES, uid, uidPackageName) == MODE_ALLOWED) { + final AttributionSource attributionSource = + new AttributionSource.Builder(uid).setPackageName(uidPackageName).build(); + if (mIAppOpsService.checkOperationWithState( + OP_REQUEST_INSTALL_PACKAGES, attributionSource.asState()) + == MODE_ALLOWED) { hasInstallOp = true; break; } @@ -4838,8 +4847,11 @@ class StorageManagerService extends IStorageManager.Stub @Override public boolean hasExternalStorageAccess(int uid, String packageName) { try { - final int opMode = mIAppOpsService.checkOperation( - OP_MANAGE_EXTERNAL_STORAGE, uid, packageName); + final AttributionSource attributionSource = + new AttributionSource.Builder(uid).setPackageName(packageName).build(); + final int opMode = + mIAppOpsService.checkOperationWithState( + OP_MANAGE_EXTERNAL_STORAGE, attributionSource.asState()); if (opMode == AppOpsManager.MODE_DEFAULT) { return mIPackageManager.checkUidPermission( MANAGE_EXTERNAL_STORAGE, uid) == PERMISSION_GRANTED; diff --git a/services/core/java/com/android/server/am/ActiveServices.java b/services/core/java/com/android/server/am/ActiveServices.java index 5f1a7e7e8123..4bdb4da97144 100644 --- a/services/core/java/com/android/server/am/ActiveServices.java +++ b/services/core/java/com/android/server/am/ActiveServices.java @@ -167,6 +167,7 @@ import android.compat.annotation.ChangeId; import android.compat.annotation.EnabledAfter; import android.compat.annotation.EnabledSince; import android.compat.annotation.Overridable; +import android.content.AttributionSource; import android.content.ComponentName; import android.content.ComponentName.WithComponentName; import android.content.Context; @@ -1100,8 +1101,12 @@ public final class ActiveServices { SystemClock.uptimeMillis()); // Use current time, not lastActivity. } } - mAm.mAppOpsService.startOperation(AppOpsManager.getToken(mAm.mAppOpsService), - AppOpsManager.OP_START_FOREGROUND, r.appInfo.uid, r.packageName, null, + final AttributionSource attributionSource = new AttributionSource.Builder(r.appInfo.uid) + .setPackageName(r.packageName) + .build(); + mAm.mAppOpsService.startOperationWithState(AppOpsManager.getToken(mAm.mAppOpsService), + AppOpsManager.OP_START_FOREGROUND, + attributionSource.asState(), true, false, null, false, AppOpsManager.ATTRIBUTION_FLAGS_NONE, AppOpsManager.ATTRIBUTION_CHAIN_ID_NONE); } @@ -2451,10 +2456,15 @@ public final class ActiveServices { stopProcStatsOp = false; } - mAm.mAppOpsService.startOperation( + final AttributionSource attributionSource = new AttributionSource + .Builder(r.appInfo.uid) + .setPackageName(r.packageName) + .build(); + mAm.mAppOpsService.startOperationWithState( AppOpsManager.getToken(mAm.mAppOpsService), - AppOpsManager.OP_START_FOREGROUND, r.appInfo.uid, r.packageName, - null, true, false, "", false, AppOpsManager.ATTRIBUTION_FLAGS_NONE, + AppOpsManager.OP_START_FOREGROUND, attributionSource.asState(), + true, false, "", false, + AppOpsManager.ATTRIBUTION_FLAGS_NONE, AppOpsManager.ATTRIBUTION_CHAIN_ID_NONE); registerAppOpCallbackLocked(r); mAm.updateForegroundServiceUsageStats(r.name, r.userId, true); @@ -2514,10 +2524,13 @@ public final class ActiveServices { if (alreadyStartedOp) { // If we had previously done a start op for direct foreground start, // we have cleared the flag so can now drop it. - mAm.mAppOpsService.finishOperation( + final AttributionSource attributionSource = new AttributionSource + .Builder(r.appInfo.uid) + .setPackageName(r.packageName) + .build(); + mAm.mAppOpsService.finishOperationWithState( AppOpsManager.getToken(mAm.mAppOpsService), - AppOpsManager.OP_START_FOREGROUND, r.appInfo.uid, r.packageName, - null); + AppOpsManager.OP_START_FOREGROUND, attributionSource.asState()); } } } else { @@ -2560,9 +2573,13 @@ public final class ActiveServices { SystemClock.uptimeMillis()); } } - mAm.mAppOpsService.finishOperation( + final AttributionSource attributionSource = + new AttributionSource.Builder(r.appInfo.uid) + .setPackageName(r.packageName) + .build(); + mAm.mAppOpsService.finishOperationWithState( AppOpsManager.getToken(mAm.mAppOpsService), - AppOpsManager.OP_START_FOREGROUND, r.appInfo.uid, r.packageName, null); + AppOpsManager.OP_START_FOREGROUND, attributionSource.asState()); unregisterAppOpCallbackLocked(r); logFGSStateChangeLocked(r, FOREGROUND_SERVICE_STATE_CHANGED__STATE__EXIT, @@ -5704,8 +5721,12 @@ public final class ActiveServices { SystemClock.uptimeMillis()); } } - mAm.mAppOpsService.finishOperation(AppOpsManager.getToken(mAm.mAppOpsService), - AppOpsManager.OP_START_FOREGROUND, r.appInfo.uid, r.packageName, null); + final AttributionSource attributionSource = new AttributionSource + .Builder(r.appInfo.uid) + .setPackageName(r.packageName) + .build(); + mAm.mAppOpsService.finishOperationWithState(AppOpsManager.getToken(mAm.mAppOpsService), + AppOpsManager.OP_START_FOREGROUND, attributionSource.asState()); mServiceFGAnrTimer.cancel(r); if (r.app != null) { Message msg = mAm.mHandler.obtainMessage( @@ -5770,9 +5791,13 @@ public final class ActiveServices { SystemClock.uptimeMillis()); } } - mAm.mAppOpsService.finishOperation( + final AttributionSource attributionSource = new AttributionSource + .Builder(r.appInfo.uid) + .setPackageName(r.packageName) + .build(); + mAm.mAppOpsService.finishOperationWithState( AppOpsManager.getToken(mAm.mAppOpsService), - AppOpsManager.OP_START_FOREGROUND, r.appInfo.uid, r.packageName, null); + AppOpsManager.OP_START_FOREGROUND, attributionSource.asState()); unregisterAppOpCallbackLocked(r); r.mFgsExitTime = SystemClock.uptimeMillis(); logFGSStateChangeLocked(r, @@ -8491,8 +8516,11 @@ public final class ActiveServices { mAm.mBatteryStatsService.noteServiceStartRunning(callingUid, callingPackage, cn.getClassName()); - mAm.mAppOpsService.startOperation(AppOpsManager.getToken(mAm.mAppOpsService), - AppOpsManager.OP_START_FOREGROUND, r.appInfo.uid, r.packageName, null, + final AttributionSource attributionSource = new AttributionSource.Builder(r.appInfo.uid) + .setPackageName(r.packageName) + .build(); + mAm.mAppOpsService.startOperationWithState(AppOpsManager.getToken(mAm.mAppOpsService), + AppOpsManager.OP_START_FOREGROUND, attributionSource.asState(), true, false, null, false, AppOpsManager.ATTRIBUTION_FLAGS_NONE, AppOpsManager.ATTRIBUTION_CHAIN_ID_NONE); registerAppOpCallbackLocked(r); diff --git a/services/core/java/com/android/server/am/ActivityManagerService.java b/services/core/java/com/android/server/am/ActivityManagerService.java index ae79f19f70f1..88bb66f8ef22 100644 --- a/services/core/java/com/android/server/am/ActivityManagerService.java +++ b/services/core/java/com/android/server/am/ActivityManagerService.java @@ -428,10 +428,11 @@ import com.android.internal.util.FastPrintWriter; import com.android.internal.util.FrameworkStatsLog; import com.android.internal.util.MemInfoReader; import com.android.internal.util.Preconditions; -import com.android.internal.util.function.HeptFunction; import com.android.internal.util.function.HexFunction; +import com.android.internal.util.function.NonaFunction; import com.android.internal.util.function.QuadFunction; import com.android.internal.util.function.QuintFunction; +import com.android.internal.util.function.TriFunction; import com.android.internal.util.function.UndecFunction; import com.android.server.AlarmManagerInternal; import com.android.server.BootReceiver; @@ -3150,8 +3151,11 @@ public class ActivityManagerService extends IActivityManager.Stub } private boolean hasUsageStatsPermission(String callingPackage, int callingUid, int callingPid) { - final int mode = mAppOpsService.noteOperation(AppOpsManager.OP_GET_USAGE_STATS, - callingUid, callingPackage, null, false, "", false).getOpMode(); + final AttributionSource attributionSource = new AttributionSource.Builder(callingUid) + .setPackageName(callingPackage) + .build(); + final int mode = mAppOpsService.noteOperationWithState(AppOpsManager.OP_GET_USAGE_STATS, + attributionSource.asState(), false, "", false).getOpMode(); if (mode == AppOpsManager.MODE_DEFAULT) { return checkPermission(Manifest.permission.PACKAGE_USAGE_STATS, callingPid, callingUid) == PackageManager.PERMISSION_GRANTED; @@ -5929,9 +5933,18 @@ public class ActivityManagerService extends IActivityManager.Stub @Override public int noteOp(String op, int uid, String packageName) { // TODO moltmann: Allow to specify featureId - return mActivityManagerService.mAppOpsService - .noteOperation(AppOpsManager.strOpToOp(op), uid, packageName, null, - false, "", false).getOpMode(); + final AttributionSource attributionSource = new AttributionSource.Builder(uid) + .setPackageName(packageName) + .build(); + return mActivityManagerService + .mAppOpsService + .noteOperationWithState( + AppOpsManager.strOpToOp(op), + attributionSource.asState(), + false, + "", + false) + .getOpMode(); } @Override @@ -15934,7 +15947,7 @@ public class ActivityManagerService extends IActivityManager.Stub try { sdkSandboxInfo = sandboxManagerLocal.getSdkSandboxApplicationInfoForInstrumentation( - sdkSandboxClientAppInfo, userId, isSdkInSandbox); + sdkSandboxClientAppInfo, isSdkInSandbox); } catch (NameNotFoundException e) { reportStartInstrumentationFailureLocked( watcher, className, "Can't find SdkSandbox package"); @@ -20059,20 +20072,26 @@ public class ActivityManagerService extends IActivityManager.Stub } @Override - public int checkOperation(int code, int uid, String packageName, - String attributionTag, boolean raw, - QuintFunction<Integer, Integer, String, String, Boolean, Integer> superImpl) { + public int checkOperation(int code, AttributionSource attributionSource, boolean raw, + TriFunction<Integer, AttributionSource, Boolean, Integer> superImpl) { + final int uid = attributionSource.getUid(); + if (uid == mTargetUid && isTargetOp(code)) { final int shellUid = UserHandle.getUid(UserHandle.getUserId(uid), Process.SHELL_UID); + final AttributionSource shellAttributionSource = + new AttributionSource.Builder(shellUid) + .setPackageName("com.android.shell") + .build(); + final long identity = Binder.clearCallingIdentity(); try { - return superImpl.apply(code, shellUid, "com.android.shell", null, raw); + return superImpl.apply(code, shellAttributionSource, raw); } finally { Binder.restoreCallingIdentity(identity); } } - return superImpl.apply(code, uid, packageName, attributionTag, raw); + return superImpl.apply(code, attributionSource, raw); } @Override @@ -20092,23 +20111,30 @@ public class ActivityManagerService extends IActivityManager.Stub } @Override - public SyncNotedAppOp noteOperation(int code, int uid, @Nullable String packageName, - @Nullable String featureId, boolean shouldCollectAsyncNotedOp, + public SyncNotedAppOp noteOperation(int code, AttributionSource attributionSource, + boolean shouldCollectAsyncNotedOp, @Nullable String message, boolean shouldCollectMessage, - @NonNull HeptFunction<Integer, Integer, String, String, Boolean, String, Boolean, + @NonNull QuintFunction<Integer, AttributionSource, Boolean, String, Boolean, SyncNotedAppOp> superImpl) { + final int uid = attributionSource.getUid(); + final String attributionTag = attributionSource.getAttributionTag(); if (uid == mTargetUid && isTargetOp(code)) { final int shellUid = UserHandle.getUid(UserHandle.getUserId(uid), Process.SHELL_UID); final long identity = Binder.clearCallingIdentity(); + final AttributionSource shellAttributionSource = + new AttributionSource.Builder(shellUid) + .setPackageName("com.android.shell") + .setAttributionTag(attributionTag) + .build(); try { - return superImpl.apply(code, shellUid, "com.android.shell", featureId, + return superImpl.apply(code, shellAttributionSource, shouldCollectAsyncNotedOp, message, shouldCollectMessage); } finally { Binder.restoreCallingIdentity(identity); } } - return superImpl.apply(code, uid, packageName, featureId, shouldCollectAsyncNotedOp, + return superImpl.apply(code, attributionSource, shouldCollectAsyncNotedOp, message, shouldCollectMessage); } @@ -20139,28 +20165,37 @@ public class ActivityManagerService extends IActivityManager.Stub } @Override - public SyncNotedAppOp startOperation(IBinder token, int code, int uid, - @Nullable String packageName, @Nullable String attributionTag, + public SyncNotedAppOp startOperation(IBinder token, int code, + AttributionSource attributionSource, boolean startIfModeDefault, boolean shouldCollectAsyncNotedOp, @Nullable String message, boolean shouldCollectMessage, @AttributionFlags int attributionFlags, int attributionChainId, - @NonNull UndecFunction<IBinder, Integer, Integer, String, String, Boolean, + @NonNull NonaFunction<IBinder, Integer, AttributionSource, Boolean, Boolean, String, Boolean, Integer, Integer, SyncNotedAppOp> superImpl) { + final int uid = attributionSource.getUid(); + final String attributionTag = attributionSource.getAttributionTag(); + if (uid == mTargetUid && isTargetOp(code)) { final int shellUid = UserHandle.getUid(UserHandle.getUserId(uid), Process.SHELL_UID); final long identity = Binder.clearCallingIdentity(); try { - return superImpl.apply(token, code, shellUid, "com.android.shell", - attributionTag, startIfModeDefault, shouldCollectAsyncNotedOp, message, + final AttributionSource shellAttributionSource = + new AttributionSource.Builder(shellUid) + .setPackageName("com.android.shell") + .setAttributionTag(attributionTag) + .build(); + + return superImpl.apply(token, code, shellAttributionSource, + startIfModeDefault, shouldCollectAsyncNotedOp, message, shouldCollectMessage, attributionFlags, attributionChainId); } finally { Binder.restoreCallingIdentity(identity); } } - return superImpl.apply(token, code, uid, packageName, attributionTag, - startIfModeDefault, shouldCollectAsyncNotedOp, message, shouldCollectMessage, - attributionFlags, attributionChainId); + return superImpl.apply(token, code, attributionSource, startIfModeDefault, + shouldCollectAsyncNotedOp, message, shouldCollectMessage, attributionFlags, + attributionChainId); } @Override diff --git a/services/core/java/com/android/server/am/ActivityManagerShellCommand.java b/services/core/java/com/android/server/am/ActivityManagerShellCommand.java index 69bf612f3e54..26b23ff72d9d 100644 --- a/services/core/java/com/android/server/am/ActivityManagerShellCommand.java +++ b/services/core/java/com/android/server/am/ActivityManagerShellCommand.java @@ -1179,7 +1179,7 @@ final class ActivityManagerShellCommand extends ShellCommand { synchronized (mInternal.mOomAdjuster.mCachedAppOptimizer.mFreezerLock) { app.mOptRecord.setFreezeSticky(isSticky); mInternal.mOomAdjuster.mCachedAppOptimizer.unfreezeAppInternalLSP(app, 0, - false); + true); } } } diff --git a/services/core/java/com/android/server/am/AppPermissionTracker.java b/services/core/java/com/android/server/am/AppPermissionTracker.java index 18a91535a34c..947fcd38f5a0 100644 --- a/services/core/java/com/android/server/am/AppPermissionTracker.java +++ b/services/core/java/com/android/server/am/AppPermissionTracker.java @@ -37,6 +37,7 @@ import static com.android.server.am.BaseAppStateTracker.STATE_TYPE_PERMISSION; import android.annotation.NonNull; import android.annotation.Nullable; import android.app.AppOpsManager; +import android.content.AttributionSource; import android.content.Context; import android.content.pm.ApplicationInfo; import android.content.pm.PackageManager.OnPermissionsChangedListener; @@ -192,7 +193,11 @@ final class AppPermissionTracker extends BaseAppStateTracker<AppPermissionPolicy if (DEBUG_PERMISSION_TRACKER) { final IAppOpsService appOpsService = mInjector.getIAppOpsService(); try { - final int mode = appOpsService.checkOperation(op, uid, packageName); + final AttributionSource attributionSource = new AttributionSource.Builder(uid) + .setPackageName(packageName) + .build(); + final int mode = + appOpsService.checkOperationWithState(op, attributionSource.asState()); Slog.i(TAG, "onOpChanged: " + opToPublicName(op) + " " + UserHandle.formatUid(uid) + " " + packageName + " " + mode); @@ -307,7 +312,11 @@ final class AppPermissionTracker extends BaseAppStateTracker<AppPermissionPolicy final IAppOpsService appOpsService = mInjector.getIAppOpsService(); for (String pkg : packages) { try { - final int mode = appOpsService.checkOperation(mAppOp, mUid, pkg); + final AttributionSource attributionSource = + new AttributionSource.Builder(mUid).setPackageName(pkg).build(); + final int mode = + appOpsService.checkOperationWithState( + mAppOp, attributionSource.asState()); if (mode == AppOpsManager.MODE_ALLOWED) { mAppOpAllowed = true; return; diff --git a/services/core/java/com/android/server/appop/AppOpsService.java b/services/core/java/com/android/server/appop/AppOpsService.java index 052b0c2078d1..d6997daaa12b 100644 --- a/services/core/java/com/android/server/appop/AppOpsService.java +++ b/services/core/java/com/android/server/appop/AppOpsService.java @@ -1143,22 +1143,32 @@ public class AppOpsService extends IAppOpsService.Stub { } }, RARELY_USED_PACKAGES_INITIALIZATION_DELAY_MILLIS); - getPackageManagerInternal().setExternalSourcesPolicy( - new PackageManagerInternal.ExternalSourcesPolicy() { - @Override - public int getPackageTrustedToInstallApps(String packageName, int uid) { - int appOpMode = checkOperation(AppOpsManager.OP_REQUEST_INSTALL_PACKAGES, - uid, packageName); - switch (appOpMode) { - case AppOpsManager.MODE_ALLOWED: - return PackageManagerInternal.ExternalSourcesPolicy.USER_TRUSTED; - case AppOpsManager.MODE_ERRORED: - return PackageManagerInternal.ExternalSourcesPolicy.USER_BLOCKED; - default: - return PackageManagerInternal.ExternalSourcesPolicy.USER_DEFAULT; - } - } - }); + getPackageManagerInternal() + .setExternalSourcesPolicy( + new PackageManagerInternal.ExternalSourcesPolicy() { + @Override + public int getPackageTrustedToInstallApps(String packageName, int uid) { + final AttributionSource attributionSource = + new AttributionSource.Builder(uid) + .setPackageName(packageName) + .build(); + int appOpMode = + checkOperationWithState( + AppOpsManager.OP_REQUEST_INSTALL_PACKAGES, + attributionSource.asState()); + switch (appOpMode) { + case AppOpsManager.MODE_ALLOWED: + return PackageManagerInternal.ExternalSourcesPolicy + .USER_TRUSTED; + case AppOpsManager.MODE_ERRORED: + return PackageManagerInternal.ExternalSourcesPolicy + .USER_BLOCKED; + default: + return PackageManagerInternal.ExternalSourcesPolicy + .USER_DEFAULT; + } + } + }); } @VisibleForTesting @@ -2534,22 +2544,41 @@ public class AppOpsService extends IAppOpsService.Stub { } } + /** @deprecated Use {@link #checkOperationWithStateRaw} instead. */ @Override public int checkOperationRaw(int code, int uid, String packageName, - @Nullable String attributionTag) { - return mCheckOpsDelegateDispatcher.checkOperation(code, uid, packageName, attributionTag, - true /*raw*/); + @Nullable String attributionTag) { + final AttributionSource attributionSource = new AttributionSource.Builder(uid) + .setPackageName(packageName).setAttributionTag(attributionTag).build(); + return mCheckOpsDelegateDispatcher.checkOperation(code, attributionSource, true /*raw*/); + } + + @Override + public int checkOperationWithStateRaw(int code, AttributionSourceState attributionSourceState) { + final AttributionSource attributionSource = new AttributionSource(attributionSourceState); + return mCheckOpsDelegateDispatcher.checkOperation(code, attributionSource, true /*raw*/); } + /** @deprecated Use {@link #checkOperationWithState} instead. */ @Override public int checkOperation(int code, int uid, String packageName) { - return mCheckOpsDelegateDispatcher.checkOperation(code, uid, packageName, null, - false /*raw*/); + final AttributionSource attributionSource = new AttributionSource.Builder(uid) + .setPackageName(packageName) + .build(); + return mCheckOpsDelegateDispatcher.checkOperation(code, attributionSource, false /*raw*/); } - private int checkOperationImpl(int code, int uid, String packageName, - @Nullable String attributionTag, boolean raw) { + @Override + public int checkOperationWithState(int code, AttributionSourceState attributionSourceState) { + final AttributionSource attributionSource = new AttributionSource(attributionSourceState); + return mCheckOpsDelegateDispatcher.checkOperation(code, attributionSource, false /*raw*/); + } + + private int checkOperationImpl(int code, AttributionSource attributionSource, boolean raw) { verifyIncomingOp(code); + final String packageName = attributionSource.getPackageName(); + final int uid = attributionSource.getUid(); + final String attributionTag = attributionSource.getAttributionTag(); if (!isIncomingPackageValid(packageName, UserHandle.getUserId(uid))) { return AppOpsManager.opToDefaultMode(code); } @@ -2614,7 +2643,10 @@ public class AppOpsService extends IAppOpsService.Stub { if (mode != AppOpsManager.MODE_ALLOWED) { return mode; } - return checkOperation(code, uid, packageName); + final AttributionSource attributionSource = new AttributionSource.Builder(uid) + .setPackageName(packageName) + .build(); + return checkOperationWithState(code, attributionSource.asState()); } @Override @@ -2758,17 +2790,38 @@ public class AppOpsService extends IAppOpsService.Stub { proxiedFlags, shouldCollectAsyncNotedOp, message, shouldCollectMessage); } + /** @deprecated Use {@link #noteOperationWithState} instead. */ @Override public SyncNotedAppOp noteOperation(int code, int uid, String packageName, String attributionTag, boolean shouldCollectAsyncNotedOp, String message, boolean shouldCollectMessage) { - return mCheckOpsDelegateDispatcher.noteOperation(code, uid, packageName, - attributionTag, shouldCollectAsyncNotedOp, message, shouldCollectMessage); + final AttributionSource attributionSource = new AttributionSource.Builder(uid) + .setPackageName(packageName) + .setAttributionTag(attributionTag) + .build(); + return mCheckOpsDelegateDispatcher.noteOperation(code, attributionSource, + shouldCollectAsyncNotedOp, message, shouldCollectMessage); + } + + @Override + public SyncNotedAppOp noteOperationWithState( + int code, + AttributionSourceState attributionSourceState, + boolean shouldCollectAsyncNotedOp, + String message, + boolean shouldCollectMessage) { + final AttributionSource attributionSource = new AttributionSource(attributionSourceState); + return mCheckOpsDelegateDispatcher.noteOperation( + code, attributionSource, shouldCollectAsyncNotedOp, message, shouldCollectMessage); } - private SyncNotedAppOp noteOperationImpl(int code, int uid, @Nullable String packageName, - @Nullable String attributionTag, boolean shouldCollectAsyncNotedOp, + private SyncNotedAppOp noteOperationImpl(int code, AttributionSource attributionSource, + boolean shouldCollectAsyncNotedOp, @Nullable String message, boolean shouldCollectMessage) { + final int uid = attributionSource.getUid(); + final String packageName = attributionSource.getPackageName(); + final String attributionTag = attributionSource.getAttributionTag(); + verifyIncomingUid(uid); verifyIncomingOp(code); if (!isIncomingPackageValid(packageName, UserHandle.getUserId(uid))) { @@ -3163,22 +3216,42 @@ public class AppOpsService extends IAppOpsService.Stub { } } + /** @deprecated Use {@link #startOperationWithState} instead. */ @Override public SyncNotedAppOp startOperation(IBinder token, int code, int uid, - @Nullable String packageName, @Nullable String attributionTag, + @Nullable String packageName, @Nullable String attributionTag, + boolean startIfModeDefault, boolean shouldCollectAsyncNotedOp, + String message, boolean shouldCollectMessage, @AttributionFlags int attributionFlags, + int attributionChainId) { + final AttributionSource attributionSource = new AttributionSource.Builder(uid) + .setPackageName(packageName) + .setAttributionTag(attributionTag) + .build(); + return mCheckOpsDelegateDispatcher.startOperation(token, code, attributionSource, + startIfModeDefault, shouldCollectAsyncNotedOp, message, shouldCollectMessage, + attributionFlags, attributionChainId); + } + + @Override + public SyncNotedAppOp startOperationWithState(IBinder token, int code, + AttributionSourceState attributionSourceState, boolean startIfModeDefault, boolean shouldCollectAsyncNotedOp, String message, boolean shouldCollectMessage, @AttributionFlags int attributionFlags, int attributionChainId) { - return mCheckOpsDelegateDispatcher.startOperation(token, code, uid, packageName, - attributionTag, startIfModeDefault, shouldCollectAsyncNotedOp, message, + final AttributionSource attributionSource = new AttributionSource(attributionSourceState); + return mCheckOpsDelegateDispatcher.startOperation(token, code, attributionSource, + startIfModeDefault, shouldCollectAsyncNotedOp, message, shouldCollectMessage, attributionFlags, attributionChainId); } - private SyncNotedAppOp startOperationImpl(@NonNull IBinder clientId, int code, int uid, - @Nullable String packageName, @Nullable String attributionTag, - boolean startIfModeDefault, boolean shouldCollectAsyncNotedOp, @NonNull String message, + private SyncNotedAppOp startOperationImpl(@NonNull IBinder clientId, int code, + AttributionSource attributionSource, boolean startIfModeDefault, + boolean shouldCollectAsyncNotedOp, @NonNull String message, boolean shouldCollectMessage, @AttributionFlags int attributionFlags, int attributionChainId) { + final String packageName = attributionSource.getPackageName(); + final int uid = attributionSource.getUid(); + final String attributionTag = attributionSource.getAttributionTag(); verifyIncomingUid(uid); verifyIncomingOp(code); if (!isIncomingPackageValid(packageName, UserHandle.getUserId(uid))) { @@ -3200,7 +3273,7 @@ public class AppOpsService extends IAppOpsService.Stub { int result = MODE_DEFAULT; if (code == OP_RECORD_AUDIO_HOTWORD || code == OP_RECEIVE_AMBIENT_TRIGGER_AUDIO || code == OP_RECORD_AUDIO_SANDBOXED) { - result = checkOperation(OP_RECORD_AUDIO, uid, packageName); + result = checkOperationWithState(OP_RECORD_AUDIO, attributionSource.asState()); // Check result if (result != AppOpsManager.MODE_ALLOWED) { return new SyncNotedAppOp(result, code, attributionTag, packageName); @@ -3208,7 +3281,7 @@ public class AppOpsService extends IAppOpsService.Stub { } // As a special case for OP_CAMERA_SANDBOXED. if (code == OP_CAMERA_SANDBOXED) { - result = checkOperation(OP_CAMERA, uid, packageName); + result = checkOperationWithState(OP_CAMERA, attributionSource.asState()); // Check result if (result != AppOpsManager.MODE_ALLOWED) { return new SyncNotedAppOp(result, code, attributionTag, packageName); @@ -3512,15 +3585,29 @@ public class AppOpsService extends IAppOpsService.Stub { packageName); } + /** @deprecated Use {@link #finishOperationWithState} instead. */ @Override public void finishOperation(IBinder clientId, int code, int uid, String packageName, String attributionTag) { - mCheckOpsDelegateDispatcher.finishOperation(clientId, code, uid, packageName, - attributionTag); + final AttributionSource attributionSource = new AttributionSource.Builder(uid) + .setPackageName(packageName) + .setAttributionTag(attributionTag) + .build(); + mCheckOpsDelegateDispatcher.finishOperation(clientId, code, attributionSource); } - private void finishOperationImpl(IBinder clientId, int code, int uid, String packageName, - String attributionTag) { + @Override + public void finishOperationWithState(IBinder clientId, int code, + AttributionSourceState attributionSourceState) { + final AttributionSource attributionSource = new AttributionSource(attributionSourceState); + mCheckOpsDelegateDispatcher.finishOperation(clientId, code, attributionSource); + } + + private void finishOperationImpl(IBinder clientId, int code, + AttributionSource attributionSource) { + final String packageName = attributionSource.getPackageName(); + final int uid = attributionSource.getUid(); + final String attributionTag = attributionSource.getAttributionTag(); verifyIncomingUid(uid); verifyIncomingOp(code); if (!isIncomingPackageValid(packageName, UserHandle.getUserId(uid))) { @@ -5103,8 +5190,13 @@ public class AppOpsService extends IAppOpsService.Stub { } if (shell.packageName != null) { - shell.mInterface.startOperation(shell.mToken, shell.op, shell.packageUid, - shell.packageName, shell.attributionTag, true, true, + final AttributionSource shellAttributionSource = + new AttributionSource.Builder(shell.packageUid) + .setPackageName(shell.packageName) + .setAttributionTag(shell.attributionTag) + .build(); + shell.mInterface.startOperationWithState(shell.mToken, shell.op, + shellAttributionSource.asState(), true, true, "appops start shell command", true, AppOpsManager.ATTRIBUTION_FLAG_ACCESSOR, ATTRIBUTION_CHAIN_ID_NONE); } else { @@ -5119,8 +5211,13 @@ public class AppOpsService extends IAppOpsService.Stub { } if (shell.packageName != null) { - shell.mInterface.finishOperation(shell.mToken, shell.op, shell.packageUid, - shell.packageName, shell.attributionTag); + final AttributionSource shellAttributionSource = + new AttributionSource.Builder(shell.packageUid) + .setPackageName(shell.packageName) + .setAttributionTag(shell.attributionTag) + .build(); + shell.mInterface.finishOperationWithState(shell.mToken, shell.op, + shellAttributionSource.asState()); } else { return -1; } @@ -6666,25 +6763,24 @@ public class AppOpsService extends IAppOpsService.Stub { return mCheckOpsDelegate; } - public int checkOperation(int code, int uid, String packageName, - @Nullable String attributionTag, boolean raw) { + public int checkOperation(int code, AttributionSource attributionSource, boolean raw) { if (mPolicy != null) { if (mCheckOpsDelegate != null) { - return mPolicy.checkOperation(code, uid, packageName, attributionTag, raw, + return mPolicy.checkOperation(code, attributionSource, raw, this::checkDelegateOperationImpl); } else { - return mPolicy.checkOperation(code, uid, packageName, attributionTag, raw, + return mPolicy.checkOperation(code, attributionSource, raw, AppOpsService.this::checkOperationImpl); } } else if (mCheckOpsDelegate != null) { - return checkDelegateOperationImpl(code, uid, packageName, attributionTag, raw); + return checkDelegateOperationImpl(code, attributionSource, raw); } - return checkOperationImpl(code, uid, packageName, attributionTag, raw); + return checkOperationImpl(code, attributionSource, raw); } - private int checkDelegateOperationImpl(int code, int uid, String packageName, - @Nullable String attributionTag, boolean raw) { - return mCheckOpsDelegate.checkOperation(code, uid, packageName, attributionTag, raw, + private int checkDelegateOperationImpl(int code, AttributionSource attributionSource, + boolean raw) { + return mCheckOpsDelegate.checkOperation(code, attributionSource, raw, AppOpsService.this::checkOperationImpl); } @@ -6709,32 +6805,32 @@ public class AppOpsService extends IAppOpsService.Stub { AppOpsService.this::checkAudioOperationImpl); } - public SyncNotedAppOp noteOperation(int code, int uid, String packageName, - String attributionTag, boolean shouldCollectAsyncNotedOp, String message, + public SyncNotedAppOp noteOperation(int code, AttributionSource attributionSource, + boolean shouldCollectAsyncNotedOp, String message, boolean shouldCollectMessage) { if (mPolicy != null) { if (mCheckOpsDelegate != null) { - return mPolicy.noteOperation(code, uid, packageName, attributionTag, + return mPolicy.noteOperation(code, attributionSource, shouldCollectAsyncNotedOp, message, shouldCollectMessage, this::noteDelegateOperationImpl); } else { - return mPolicy.noteOperation(code, uid, packageName, attributionTag, + return mPolicy.noteOperation(code, attributionSource, shouldCollectAsyncNotedOp, message, shouldCollectMessage, AppOpsService.this::noteOperationImpl); } } else if (mCheckOpsDelegate != null) { - return noteDelegateOperationImpl(code, uid, packageName, - attributionTag, shouldCollectAsyncNotedOp, message, shouldCollectMessage); + return noteDelegateOperationImpl(code, attributionSource, shouldCollectAsyncNotedOp, + message, shouldCollectMessage); } - return noteOperationImpl(code, uid, packageName, attributionTag, + return noteOperationImpl(code, attributionSource, shouldCollectAsyncNotedOp, message, shouldCollectMessage); } - private SyncNotedAppOp noteDelegateOperationImpl(int code, int uid, - @Nullable String packageName, @Nullable String featureId, + private SyncNotedAppOp noteDelegateOperationImpl(int code, + AttributionSource attributionSource, boolean shouldCollectAsyncNotedOp, @Nullable String message, boolean shouldCollectMessage) { - return mCheckOpsDelegate.noteOperation(code, uid, packageName, featureId, + return mCheckOpsDelegate.noteOperation(code, attributionSource, shouldCollectAsyncNotedOp, message, shouldCollectMessage, AppOpsService.this::noteOperationImpl); } @@ -6770,39 +6866,38 @@ public class AppOpsService extends IAppOpsService.Stub { AppOpsService.this::noteProxyOperationImpl); } - public SyncNotedAppOp startOperation(IBinder token, int code, int uid, - @Nullable String packageName, @NonNull String attributionTag, - boolean startIfModeDefault, boolean shouldCollectAsyncNotedOp, - @Nullable String message, boolean shouldCollectMessage, - @AttributionFlags int attributionFlags, int attributionChainId) { + public SyncNotedAppOp startOperation(IBinder token, int code, + AttributionSource attributionSource, boolean startIfModeDefault, + boolean shouldCollectAsyncNotedOp, @Nullable String message, + boolean shouldCollectMessage, @AttributionFlags int attributionFlags, + int attributionChainId) { if (mPolicy != null) { if (mCheckOpsDelegate != null) { - return mPolicy.startOperation(token, code, uid, packageName, - attributionTag, startIfModeDefault, shouldCollectAsyncNotedOp, message, + return mPolicy.startOperation(token, code, attributionSource, + startIfModeDefault, shouldCollectAsyncNotedOp, message, shouldCollectMessage, attributionFlags, attributionChainId, this::startDelegateOperationImpl); } else { - return mPolicy.startOperation(token, code, uid, packageName, attributionTag, + return mPolicy.startOperation(token, code, attributionSource, startIfModeDefault, shouldCollectAsyncNotedOp, message, shouldCollectMessage, attributionFlags, attributionChainId, AppOpsService.this::startOperationImpl); } } else if (mCheckOpsDelegate != null) { - return startDelegateOperationImpl(token, code, uid, packageName, attributionTag, + return startDelegateOperationImpl(token, code, attributionSource, startIfModeDefault, shouldCollectAsyncNotedOp, message, shouldCollectMessage, attributionFlags, attributionChainId); } - return startOperationImpl(token, code, uid, packageName, attributionTag, + return startOperationImpl(token, code, attributionSource, startIfModeDefault, shouldCollectAsyncNotedOp, message, shouldCollectMessage, attributionFlags, attributionChainId); } - private SyncNotedAppOp startDelegateOperationImpl(IBinder token, int code, int uid, - @Nullable String packageName, @Nullable String attributionTag, - boolean startIfModeDefault, boolean shouldCollectAsyncNotedOp, String message, - boolean shouldCollectMessage, @AttributionFlags int attributionFlags, - int attributionChainId) { - return mCheckOpsDelegate.startOperation(token, code, uid, packageName, attributionTag, + private SyncNotedAppOp startDelegateOperationImpl(IBinder token, int code, + AttributionSource attributionSource, boolean startIfModeDefault, + boolean shouldCollectAsyncNotedOp, String message, boolean shouldCollectMessage, + @AttributionFlags int attributionFlags, int attributionChainId) { + return mCheckOpsDelegate.startOperation(token, code, attributionSource, startIfModeDefault, shouldCollectAsyncNotedOp, message, shouldCollectMessage, attributionFlags, attributionChainId, AppOpsService.this::startOperationImpl); } @@ -6848,26 +6943,26 @@ public class AppOpsService extends IAppOpsService.Stub { attributionChainId, AppOpsService.this::startProxyOperationImpl); } - public void finishOperation(IBinder clientId, int code, int uid, String packageName, - String attributionTag) { + public void finishOperation(IBinder clientId, int code, + AttributionSource attributionSource) { if (mPolicy != null) { if (mCheckOpsDelegate != null) { - mPolicy.finishOperation(clientId, code, uid, packageName, attributionTag, + mPolicy.finishOperation(clientId, code, attributionSource, this::finishDelegateOperationImpl); } else { - mPolicy.finishOperation(clientId, code, uid, packageName, attributionTag, + mPolicy.finishOperation(clientId, code, attributionSource, AppOpsService.this::finishOperationImpl); } } else if (mCheckOpsDelegate != null) { - finishDelegateOperationImpl(clientId, code, uid, packageName, attributionTag); + finishDelegateOperationImpl(clientId, code, attributionSource); } else { - finishOperationImpl(clientId, code, uid, packageName, attributionTag); + finishOperationImpl(clientId, code, attributionSource); } } - private void finishDelegateOperationImpl(IBinder clientId, int code, int uid, - String packageName, String attributionTag) { - mCheckOpsDelegate.finishOperation(clientId, code, uid, packageName, attributionTag, + private void finishDelegateOperationImpl(IBinder clientId, int code, + AttributionSource attributionSource) { + mCheckOpsDelegate.finishOperation(clientId, code, attributionSource, AppOpsService.this::finishOperationImpl); } diff --git a/services/core/java/com/android/server/display/feature/DisplayManagerFlags.java b/services/core/java/com/android/server/display/feature/DisplayManagerFlags.java index 7f3ea6a0a99e..0d3e0bc6b9cd 100644 --- a/services/core/java/com/android/server/display/feature/DisplayManagerFlags.java +++ b/services/core/java/com/android/server/display/feature/DisplayManagerFlags.java @@ -77,8 +77,8 @@ public class DisplayManagerFlags { Flags::enablePowerThrottlingClamper); private final FlagState mSmallAreaDetectionFlagState = new FlagState( - Flags.FLAG_ENABLE_SMALL_AREA_DETECTION, - Flags::enableSmallAreaDetection); + com.android.graphics.surfaceflinger.flags.Flags.FLAG_ENABLE_SMALL_AREA_DETECTION, + com.android.graphics.surfaceflinger.flags.Flags::enableSmallAreaDetection); /** Returns whether connected display management is enabled or not. */ public boolean isConnectedDisplayManagementEnabled() { diff --git a/services/core/java/com/android/server/display/feature/display_flags.aconfig b/services/core/java/com/android/server/display/feature/display_flags.aconfig index 9141814da6fc..9ab9c9def61b 100644 --- a/services/core/java/com/android/server/display/feature/display_flags.aconfig +++ b/services/core/java/com/android/server/display/feature/display_flags.aconfig @@ -104,12 +104,3 @@ flag { bug: "211737588" is_fixed_read_only: true } - -flag { - name: "enable_small_area_detection" - namespace: "display_manager" - description: "Feature flag for SmallAreaDetection" - bug: "298722189" - is_fixed_read_only: true -} - 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 9dec1dff4cf0..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) { @@ -837,15 +844,18 @@ class MediaRouter2ServiceImpl { private void unregisterRouter2Locked(@NonNull IMediaRouter2 router, boolean died) { RouterRecord routerRecord = mAllRouterRecords.remove(router.asBinder()); if (routerRecord == null) { - Slog.w(TAG, "Ignoring unregistering unknown router2"); + Slog.w( + TAG, + TextUtils.formatSimple( + "Ignoring unregistering unknown router: %s, died: %b", router, died)); return; } Slog.i( TAG, TextUtils.formatSimple( - "unregisterRouter2 | package: %s, router id: %d", - routerRecord.mPackageName, routerRecord.mRouterId)); + "unregisterRouter2 | package: %s, router id: %d, died: %b", + routerRecord.mPackageName, routerRecord.mRouterId, died)); UserRecord userRecord = routerRecord.mUserRecord; userRecord.mRouterRecords.remove(routerRecord); @@ -1161,6 +1171,7 @@ class MediaRouter2ServiceImpl { return sessionInfos; } + @RequiresPermission(Manifest.permission.MEDIA_CONTENT_CONTROL) @GuardedBy("mLock") private void registerManagerLocked( @NonNull IMediaRouter2Manager manager, @@ -1184,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( @@ -1230,15 +1240,22 @@ class MediaRouter2ServiceImpl { private void unregisterManagerLocked(@NonNull IMediaRouter2Manager manager, boolean died) { ManagerRecord managerRecord = mAllManagerRecords.remove(manager.asBinder()); if (managerRecord == null) { + Slog.w( + TAG, + TextUtils.formatSimple( + "Ignoring unregistering unknown manager: %s, died: %b", manager, died)); return; } UserRecord userRecord = managerRecord.mUserRecord; - Slog.i(TAG, TextUtils.formatSimple( - "unregisterManager | package: %s, user: %d, manager: %d", - managerRecord.mOwnerPackageName, - userRecord.mUserId, - managerRecord.mManagerId)); + Slog.i( + TAG, + TextUtils.formatSimple( + "unregisterManager | package: %s, user: %d, manager: %d, died: %b", + managerRecord.mOwnerPackageName, + userRecord.mUserId, + managerRecord.mManagerId, + died)); userRecord.mManagerRecords.remove(managerRecord); managerRecord.dispose(); 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/media/projection/FrameworkStatsLogWrapper.java b/services/core/java/com/android/server/media/projection/FrameworkStatsLogWrapper.java index 5bad06777328..6c74cba99bcb 100644 --- a/services/core/java/com/android/server/media/projection/FrameworkStatsLogWrapper.java +++ b/services/core/java/com/android/server/media/projection/FrameworkStatsLogWrapper.java @@ -21,8 +21,8 @@ import com.android.internal.util.FrameworkStatsLog; /** Wrapper around {@link FrameworkStatsLog} */ public class FrameworkStatsLogWrapper { - /** Wrapper around {@link FrameworkStatsLog#write}. */ - public void write( + /** Wrapper around {@link FrameworkStatsLog#write} for MediaProjectionStateChanged atom. */ + public void writeStateChanged( int code, int sessionId, int state, @@ -41,4 +41,21 @@ public class FrameworkStatsLogWrapper { timeSinceLastActive, creationSource); } + + /** Wrapper around {@link FrameworkStatsLog#write} for MediaProjectionTargetChanged atom. */ + public void writeTargetChanged( + int code, + int sessionId, + int targetType, + int hostUid, + int targetUid, + int windowingMode) { + FrameworkStatsLog.write( + code, + sessionId, + targetType, + hostUid, + targetUid, + windowingMode); + } } diff --git a/services/core/java/com/android/server/media/projection/MediaProjectionManagerService.java b/services/core/java/com/android/server/media/projection/MediaProjectionManagerService.java index 893ed6119f9f..6deda468f9a2 100644 --- a/services/core/java/com/android/server/media/projection/MediaProjectionManagerService.java +++ b/services/core/java/com/android/server/media/projection/MediaProjectionManagerService.java @@ -479,6 +479,18 @@ public final class MediaProjectionManagerService extends SystemService mMediaProjectionMetricsLogger.logAppSelectorDisplayed(hostUid); } + @VisibleForTesting + void notifyWindowingModeChanged(int contentToRecord, int targetUid, int windowingMode) { + synchronized (mLock) { + if (mProjectionGrant == null) { + Slog.i(TAG, "Cannot log MediaProjectionTargetChanged atom due to null projection"); + } else { + mMediaProjectionMetricsLogger.logChangedWindowingMode( + contentToRecord, mProjectionGrant.uid, targetUid, windowingMode); + } + } + } + /** * Handles result of dialog shown from * {@link BinderService#buildReviewGrantedConsentIntentLocked()}. @@ -905,6 +917,20 @@ public final class MediaProjectionManagerService extends SystemService } @Override // Binder call + @EnforcePermission(MANAGE_MEDIA_PROJECTION) + public void notifyWindowingModeChanged( + int contentToRecord, int targetUid, int windowingMode) { + notifyWindowingModeChanged_enforcePermission(); + final long token = Binder.clearCallingIdentity(); + try { + MediaProjectionManagerService.this.notifyWindowingModeChanged( + contentToRecord, targetUid, windowingMode); + } finally { + Binder.restoreCallingIdentity(token); + } + } + + @Override // Binder call public void dump(FileDescriptor fd, final PrintWriter pw, String[] args) { if (!DumpUtils.checkDumpPermission(mContext, TAG, pw)) return; final long token = Binder.clearCallingIdentity(); diff --git a/services/core/java/com/android/server/media/projection/MediaProjectionMetricsLogger.java b/services/core/java/com/android/server/media/projection/MediaProjectionMetricsLogger.java index d7fefeb0b1fe..be2a25a755a5 100644 --- a/services/core/java/com/android/server/media/projection/MediaProjectionMetricsLogger.java +++ b/services/core/java/com/android/server/media/projection/MediaProjectionMetricsLogger.java @@ -16,16 +16,32 @@ package com.android.server.media.projection; +import static android.app.WindowConfiguration.WINDOWING_MODE_FREEFORM; +import static android.app.WindowConfiguration.WINDOWING_MODE_FULLSCREEN; +import static android.app.WindowConfiguration.WINDOWING_MODE_MULTI_WINDOW; +import static android.view.ContentRecordingSession.RECORD_CONTENT_DISPLAY; +import static android.view.ContentRecordingSession.RECORD_CONTENT_TASK; + import static com.android.internal.util.FrameworkStatsLog.MEDIA_PROJECTION_STATE_CHANGED__CREATION_SOURCE__CREATION_SOURCE_UNKNOWN; import static com.android.internal.util.FrameworkStatsLog.MEDIA_PROJECTION_STATE_CHANGED__STATE__MEDIA_PROJECTION_STATE_APP_SELECTOR_DISPLAYED; import static com.android.internal.util.FrameworkStatsLog.MEDIA_PROJECTION_STATE_CHANGED__STATE__MEDIA_PROJECTION_STATE_CAPTURING_IN_PROGRESS; import static com.android.internal.util.FrameworkStatsLog.MEDIA_PROJECTION_STATE_CHANGED__STATE__MEDIA_PROJECTION_STATE_INITIATED; import static com.android.internal.util.FrameworkStatsLog.MEDIA_PROJECTION_STATE_CHANGED__STATE__MEDIA_PROJECTION_STATE_PERMISSION_REQUEST_DISPLAYED; import static com.android.internal.util.FrameworkStatsLog.MEDIA_PROJECTION_STATE_CHANGED__STATE__MEDIA_PROJECTION_STATE_STOPPED; +import static com.android.internal.util.FrameworkStatsLog.MEDIA_PROJECTION_TARGET_CHANGED__TARGET_TYPE__TARGET_TYPE_APP_TASK; +import static com.android.internal.util.FrameworkStatsLog.MEDIA_PROJECTION_TARGET_CHANGED__TARGET_TYPE__TARGET_TYPE_DISPLAY; +import static com.android.internal.util.FrameworkStatsLog.MEDIA_PROJECTION_TARGET_CHANGED__TARGET_TYPE__TARGET_TYPE_UNKNOWN; +import static com.android.internal.util.FrameworkStatsLog.MEDIA_PROJECTION_TARGET_CHANGED__TARGET_WINDOWING_MODE__WINDOWING_MODE_FREEFORM; +import static com.android.internal.util.FrameworkStatsLog.MEDIA_PROJECTION_TARGET_CHANGED__TARGET_WINDOWING_MODE__WINDOWING_MODE_FULLSCREEN; +import static com.android.internal.util.FrameworkStatsLog.MEDIA_PROJECTION_TARGET_CHANGED__TARGET_WINDOWING_MODE__WINDOWING_MODE_SPLIT_SCREEN; +import static com.android.internal.util.FrameworkStatsLog.MEDIA_PROJECTION_TARGET_CHANGED__TARGET_WINDOWING_MODE__WINDOWING_MODE_UNKNOWN; +import android.app.WindowConfiguration.WindowingMode; import android.content.Context; import android.util.Log; +import android.view.ContentRecordingSession.RecordContent; +import com.android.internal.annotations.VisibleForTesting; import com.android.internal.util.FrameworkStatsLog; import java.time.Duration; @@ -91,7 +107,7 @@ public class MediaProjectionMetricsLogger { durationSinceLastActiveSession == null ? TIME_SINCE_LAST_ACTIVE_UNKNOWN : (int) durationSinceLastActiveSession.toSeconds(); - write( + writeStateChanged( mSessionIdGenerator.createAndGetNewSessionId(), MEDIA_PROJECTION_STATE_CHANGED__STATE__MEDIA_PROJECTION_STATE_INITIATED, hostUid, @@ -102,13 +118,13 @@ public class MediaProjectionMetricsLogger { /** * Logs that the user entered the setup flow and permission dialog is displayed. This state is - * not sent when the permission is already granted and we skipped showing the permission dialog. + * not sent when the permission is already granted, and we skipped showing the permission dialog. * * @param hostUid UID of the package that initiates MediaProjection. */ public void logPermissionRequestDisplayed(int hostUid) { Log.d(TAG, "logPermissionRequestDisplayed"); - write( + writeStateChanged( mSessionIdGenerator.getCurrentSessionId(), MEDIA_PROJECTION_STATE_CHANGED__STATE__MEDIA_PROJECTION_STATE_PERMISSION_REQUEST_DISPLAYED, hostUid, @@ -123,7 +139,7 @@ public class MediaProjectionMetricsLogger { * @param hostUid UID of the package that initiates MediaProjection. */ public void logProjectionPermissionRequestCancelled(int hostUid) { - write( + writeStateChanged( mSessionIdGenerator.getCurrentSessionId(), FrameworkStatsLog .MEDIA_PROJECTION_STATE_CHANGED__STATE__MEDIA_PROJECTION_STATE_CANCELLED, @@ -141,7 +157,7 @@ public class MediaProjectionMetricsLogger { */ public void logAppSelectorDisplayed(int hostUid) { Log.d(TAG, "logAppSelectorDisplayed"); - write( + writeStateChanged( mSessionIdGenerator.getCurrentSessionId(), MEDIA_PROJECTION_STATE_CHANGED__STATE__MEDIA_PROJECTION_STATE_APP_SELECTOR_DISPLAYED, hostUid, @@ -158,7 +174,7 @@ public class MediaProjectionMetricsLogger { */ public void logInProgress(int hostUid, int targetUid) { Log.d(TAG, "logInProgress"); - write( + writeStateChanged( mSessionIdGenerator.getCurrentSessionId(), MEDIA_PROJECTION_STATE_CHANGED__STATE__MEDIA_PROJECTION_STATE_CAPTURING_IN_PROGRESS, hostUid, @@ -168,6 +184,54 @@ public class MediaProjectionMetricsLogger { } /** + * Logs that the windowing mode of a projection has changed. + * + * @param contentToRecord ContentRecordingSession.RecordContent indicating whether it is a + * task capture or display capture - gets converted to the corresponding + * TargetType before being logged. + * @param hostUid UID of the package that initiates MediaProjection. + * @param targetUid UID of the package that is captured if selected. + * @param windowingMode Updated WindowConfiguration.WindowingMode of the captured region - gets + * converted to the corresponding TargetWindowingMode before being logged. + */ + public void logChangedWindowingMode( + int contentToRecord, int hostUid, int targetUid, int windowingMode) { + Log.d(TAG, "logChangedWindowingMode"); + writeTargetChanged( + mSessionIdGenerator.getCurrentSessionId(), + contentToRecordToTargetType(contentToRecord), + hostUid, + targetUid, + windowingModeToTargetWindowingMode(windowingMode)); + + } + + @VisibleForTesting + public int contentToRecordToTargetType(@RecordContent int recordContentType) { + return switch (recordContentType) { + case RECORD_CONTENT_DISPLAY -> + MEDIA_PROJECTION_TARGET_CHANGED__TARGET_TYPE__TARGET_TYPE_DISPLAY; + case RECORD_CONTENT_TASK -> + MEDIA_PROJECTION_TARGET_CHANGED__TARGET_TYPE__TARGET_TYPE_APP_TASK; + default -> MEDIA_PROJECTION_TARGET_CHANGED__TARGET_TYPE__TARGET_TYPE_UNKNOWN; + }; + } + + @VisibleForTesting + public int windowingModeToTargetWindowingMode(@WindowingMode int windowingMode) { + return switch (windowingMode) { + case WINDOWING_MODE_FULLSCREEN -> + MEDIA_PROJECTION_TARGET_CHANGED__TARGET_WINDOWING_MODE__WINDOWING_MODE_FULLSCREEN; + case WINDOWING_MODE_FREEFORM -> + MEDIA_PROJECTION_TARGET_CHANGED__TARGET_WINDOWING_MODE__WINDOWING_MODE_FREEFORM; + case WINDOWING_MODE_MULTI_WINDOW -> + MEDIA_PROJECTION_TARGET_CHANGED__TARGET_WINDOWING_MODE__WINDOWING_MODE_SPLIT_SCREEN; + default -> + MEDIA_PROJECTION_TARGET_CHANGED__TARGET_WINDOWING_MODE__WINDOWING_MODE_UNKNOWN; + }; + } + + /** * Logs that the capturing stopped, either normally or because of error. * * @param hostUid UID of the package that initiates MediaProjection. @@ -178,7 +242,7 @@ public class MediaProjectionMetricsLogger { mPreviousState == MEDIA_PROJECTION_STATE_CHANGED__STATE__MEDIA_PROJECTION_STATE_CAPTURING_IN_PROGRESS; Log.d(TAG, "logStopped: wasCaptureInProgress=" + wasCaptureInProgress); - write( + writeStateChanged( mSessionIdGenerator.getCurrentSessionId(), MEDIA_PROJECTION_STATE_CHANGED__STATE__MEDIA_PROJECTION_STATE_STOPPED, hostUid, @@ -191,14 +255,31 @@ public class MediaProjectionMetricsLogger { } } - private void write( + public void notifyProjectionStateChange(int hostUid, int state, int sessionCreationSource) { + writeStateChanged(hostUid, state, sessionCreationSource); + } + + private void writeStateChanged(int hostUid, int state, int sessionCreationSource) { + mFrameworkStatsLogWrapper.writeStateChanged( + /* code */ FrameworkStatsLog.MEDIA_PROJECTION_STATE_CHANGED, + /* session_id */ 123, + /* state */ state, + /* previous_state */ FrameworkStatsLog + .MEDIA_PROJECTION_STATE_CHANGED__STATE__MEDIA_PROJECTION_STATE_UNKNOWN, + /* host_uid */ hostUid, + /* target_uid */ -1, + /* time_since_last_active */ 0, + /* creation_source */ sessionCreationSource); + } + + private void writeStateChanged( int sessionId, int state, int hostUid, int targetUid, int timeSinceLastActive, int creationSource) { - mFrameworkStatsLogWrapper.write( + mFrameworkStatsLogWrapper.writeStateChanged( /* code */ FrameworkStatsLog.MEDIA_PROJECTION_STATE_CHANGED, sessionId, state, @@ -209,4 +290,19 @@ public class MediaProjectionMetricsLogger { creationSource); mPreviousState = state; } + + private void writeTargetChanged( + int sessionId, + int targetType, + int hostUid, + int targetUid, + int targetWindowingMode) { + mFrameworkStatsLogWrapper.writeTargetChanged( + /* code */ FrameworkStatsLog.MEDIA_PROJECTION_TARGET_CHANGED, + sessionId, + targetType, + hostUid, + targetUid, + targetWindowingMode); + } } 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/notification/flags.aconfig b/services/core/java/com/android/server/notification/flags.aconfig index 66a76cc7fa70..25b7ca146ff1 100644 --- a/services/core/java/com/android/server/notification/flags.aconfig +++ b/services/core/java/com/android/server/notification/flags.aconfig @@ -7,12 +7,7 @@ flag { bug: "290381858" } -flag { - name: "modes_api" - namespace: "systemui" - description: "This flag controls new and updated DND apis" - bug: "300477976" -} + flag { name: "polite_notifications" diff --git a/services/core/java/com/android/server/pm/PackageArchiver.java b/services/core/java/com/android/server/pm/PackageArchiver.java index 42a97f7e05b4..5cd62872e07b 100644 --- a/services/core/java/com/android/server/pm/PackageArchiver.java +++ b/services/core/java/com/android/server/pm/PackageArchiver.java @@ -17,8 +17,8 @@ package com.android.server.pm; import static android.app.ComponentOptions.MODE_BACKGROUND_ACTIVITY_START_DENIED; -import static android.content.pm.ArchivedActivity.bytesFromBitmap; -import static android.content.pm.ArchivedActivity.drawableToBitmap; +import static android.content.pm.ArchivedActivityInfo.bytesFromBitmap; +import static android.content.pm.ArchivedActivityInfo.drawableToBitmap; import static android.content.pm.PackageManager.DELETE_ARCHIVE; import static android.content.pm.PackageManager.DELETE_KEEP_DATA; import static android.os.PowerExemptionManager.REASON_PACKAGE_UNARCHIVE; @@ -46,6 +46,12 @@ import android.content.pm.ResolveInfo; import android.content.pm.VersionedPackage; import android.graphics.Bitmap; import android.graphics.BitmapFactory; +import android.graphics.Color; +import android.graphics.PorterDuff; +import android.graphics.PorterDuffColorFilter; +import android.graphics.drawable.BitmapDrawable; +import android.graphics.drawable.Drawable; +import android.graphics.drawable.LayerDrawable; import android.os.Binder; import android.os.Bundle; import android.os.Environment; @@ -56,6 +62,7 @@ import android.os.UserHandle; import android.text.TextUtils; import android.util.Slog; +import com.android.internal.R; import com.android.internal.annotations.GuardedBy; import com.android.internal.annotations.VisibleForTesting; import com.android.server.pm.pkg.ArchiveState; @@ -367,7 +374,7 @@ public class PackageArchiver { // TODO(b/298452477) Handle monochrome icons. // In the rare case the archived app defined more than two launcher activities, we choose // the first one arbitrarily. - return decodeIcon(activityInfos.get(0)); + return includeCloudOverlay(decodeIcon(activityInfos.get(0))); } @VisibleForTesting @@ -375,6 +382,34 @@ public class PackageArchiver { return BitmapFactory.decodeFile(archiveActivityInfo.getIconBitmap().toString()); } + Bitmap includeCloudOverlay(Bitmap bitmap) { + Drawable cloudDrawable = + mContext.getResources() + .getDrawable(R.drawable.archived_app_cloud_overlay, mContext.getTheme()); + if (cloudDrawable == null) { + Slog.e(TAG, "Unable to locate cloud overlay for archived app!"); + return bitmap; + } + BitmapDrawable appIconDrawable = new BitmapDrawable(mContext.getResources(), bitmap); + PorterDuffColorFilter colorFilter = + new PorterDuffColorFilter( + Color.argb(0.32f /* alpha */, 0f /* red */, 0f /* green */, 0f /* blue */), + PorterDuff.Mode.SRC_ATOP); + appIconDrawable.setColorFilter(colorFilter); + appIconDrawable.setBounds( + 0 /* left */, + 0 /* top */, + cloudDrawable.getIntrinsicWidth(), + cloudDrawable.getIntrinsicHeight()); + LayerDrawable layerDrawable = + new LayerDrawable(new Drawable[] {appIconDrawable, cloudDrawable}); + final int iconSize = mContext.getSystemService( + ActivityManager.class).getLauncherLargeIconSize(); + Bitmap appIconWithCloudOverlay = drawableToBitmap(layerDrawable, iconSize); + bitmap.recycle(); + return appIconWithCloudOverlay; + } + private void verifyArchived(PackageStateInternal ps, int userId) throws PackageManager.NameNotFoundException { PackageUserStateInternal userState = ps.getUserStateOrDefault(userId); diff --git a/services/core/java/com/android/server/policy/AppOpsPolicy.java b/services/core/java/com/android/server/policy/AppOpsPolicy.java index b83421fe78d7..c2821aef2142 100644 --- a/services/core/java/com/android/server/policy/AppOpsPolicy.java +++ b/services/core/java/com/android/server/policy/AppOpsPolicy.java @@ -50,11 +50,12 @@ import android.util.Log; import android.util.SparseArray; import com.android.internal.annotations.GuardedBy; -import com.android.internal.util.function.HeptFunction; import com.android.internal.util.function.HexFunction; +import com.android.internal.util.function.NonaFunction; import com.android.internal.util.function.QuadFunction; -import com.android.internal.util.function.QuintConsumer; import com.android.internal.util.function.QuintFunction; +import com.android.internal.util.function.TriConsumer; +import com.android.internal.util.function.TriFunction; import com.android.internal.util.function.UndecFunction; import com.android.server.LocalServices; @@ -229,10 +230,12 @@ public final class AppOpsPolicy implements AppOpsManagerInternal.CheckOpsDelegat } @Override - public int checkOperation(int code, int uid, String packageName, - @Nullable String attributionTag, boolean raw, - QuintFunction<Integer, Integer, String, String, Boolean, Integer> superImpl) { - return superImpl.apply(code, resolveUid(code, uid), packageName, attributionTag, raw); + public int checkOperation(int code, AttributionSource attributionSource, boolean raw, + TriFunction<Integer, AttributionSource, Boolean, Integer> superImpl) { + final int uid = attributionSource.getUid(); + final AttributionSource resolvedAttributionSource = + attributionSource.withUid(resolveUid(code, uid)); + return superImpl.apply(code, resolvedAttributionSource, raw); } @Override @@ -242,21 +245,25 @@ public final class AppOpsPolicy implements AppOpsManagerInternal.CheckOpsDelegat } @Override - public SyncNotedAppOp noteOperation(int code, int uid, @Nullable String packageName, - @Nullable String attributionTag, boolean shouldCollectAsyncNotedOp, @Nullable - String message, boolean shouldCollectMessage, @NonNull HeptFunction<Integer, Integer, - String, String, Boolean, String, Boolean, SyncNotedAppOp> superImpl) { - return superImpl.apply(resolveDatasourceOp(code, uid, packageName, attributionTag), - resolveUid(code, uid), packageName, attributionTag, shouldCollectAsyncNotedOp, - message, shouldCollectMessage); + public SyncNotedAppOp noteOperation(int code, AttributionSource attributionSource, + boolean shouldCollectAsyncNotedOp, @Nullable + String message, boolean shouldCollectMessage, + @NonNull QuintFunction<Integer, AttributionSource, Boolean, String, Boolean, + SyncNotedAppOp> superImpl) { + final int uid = attributionSource.getUid(); + final AttributionSource resolvedAttributionSource = + attributionSource.withUid(resolveUid(code, uid)); + return superImpl.apply(resolveDatasourceOp(code, uid, attributionSource.getPackageName(), + attributionSource.getAttributionTag()), resolvedAttributionSource, + shouldCollectAsyncNotedOp, message, shouldCollectMessage); } @Override public SyncNotedAppOp noteProxyOperation(int code, @NonNull AttributionSource attributionSource, boolean shouldCollectAsyncNotedOp, @Nullable String message, boolean shouldCollectMessage, boolean skipProxyOperation, @NonNull HexFunction<Integer, - AttributionSource, Boolean, String, Boolean, Boolean, - SyncNotedAppOp> superImpl) { + AttributionSource, Boolean, String, Boolean, Boolean, + SyncNotedAppOp> superImpl) { return superImpl.apply(resolveDatasourceOp(code, attributionSource.getUid(), attributionSource.getPackageName(), attributionSource.getAttributionTag()), attributionSource, shouldCollectAsyncNotedOp, message, shouldCollectMessage, @@ -264,17 +271,21 @@ public final class AppOpsPolicy implements AppOpsManagerInternal.CheckOpsDelegat } @Override - public SyncNotedAppOp startOperation(IBinder token, int code, int uid, - @Nullable String packageName, @Nullable String attributionTag, + public SyncNotedAppOp startOperation(IBinder token, int code, + AttributionSource attributionSource, boolean startIfModeDefault, boolean shouldCollectAsyncNotedOp, String message, boolean shouldCollectMessage, @AttributionFlags int attributionFlags, - int attributionChainId, @NonNull UndecFunction<IBinder, Integer, Integer, String, - String, Boolean, Boolean, String, Boolean, Integer, Integer, - SyncNotedAppOp> superImpl) { - return superImpl.apply(token, resolveDatasourceOp(code, uid, packageName, attributionTag), - resolveUid(code, uid), packageName, attributionTag, startIfModeDefault, - shouldCollectAsyncNotedOp, message, shouldCollectMessage, attributionFlags, - attributionChainId); + int attributionChainId, + @NonNull NonaFunction<IBinder, Integer, AttributionSource, Boolean, Boolean, String, + Boolean, Integer, Integer, + SyncNotedAppOp> superImpl) { + final int uid = attributionSource.getUid(); + final AttributionSource resolvedAttributionSource = + attributionSource.withUid(resolveUid(code, uid)); + return superImpl.apply(token, resolveDatasourceOp(code, uid, + attributionSource.getPackageName(), attributionSource.getAttributionTag()), + resolvedAttributionSource, startIfModeDefault, shouldCollectAsyncNotedOp, message, + shouldCollectMessage, attributionFlags, attributionChainId); } @Override @@ -293,11 +304,14 @@ public final class AppOpsPolicy implements AppOpsManagerInternal.CheckOpsDelegat } @Override - public void finishOperation(IBinder clientId, int code, int uid, String packageName, - String attributionTag, - @NonNull QuintConsumer<IBinder, Integer, Integer, String, String> superImpl) { - superImpl.accept(clientId, resolveDatasourceOp(code, uid, packageName, attributionTag), - resolveUid(code, uid), packageName, attributionTag); + public void finishOperation(IBinder clientId, int code, AttributionSource attributionSource, + @NonNull TriConsumer<IBinder, Integer, AttributionSource> superImpl) { + final int uid = attributionSource.getUid(); + final AttributionSource resolvedAttributionSource = + attributionSource.withUid(resolveUid(code, uid)); + superImpl.accept(clientId, resolveDatasourceOp(code, uid, + attributionSource.getPackageName(), attributionSource.getAttributionTag()), + resolvedAttributionSource); } @Override 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/tv/TvInputManagerService.java b/services/core/java/com/android/server/tv/TvInputManagerService.java index b12ecc333d1f..e4c7fc1f3797 100644 --- a/services/core/java/com/android/server/tv/TvInputManagerService.java +++ b/services/core/java/com/android/server/tv/TvInputManagerService.java @@ -1166,7 +1166,11 @@ public final class TvInputManagerService extends SystemService { .EXTERNAL_TV_INPUT_EVENT__EVENT_TYPE__CONNECTION_STATE_CHANGED, mOnScreenInputId, mOnScreenSessionState); } else if (mOnScreenInputId != null) { - TvInputInfo currentInputInfo = userState.inputMap.get(mOnScreenInputId).info; + TvInputState currentInputState = userState.inputMap.get(mOnScreenInputId); + TvInputInfo currentInputInfo = null; + if (currentInputState != null) { + currentInputInfo = currentInputState.info; + } if (currentInputInfo != null && currentInputInfo.getHdmiDeviceInfo() != null && inputId.equals(currentInputInfo.getParentId())) { logExternalInputEvent( diff --git a/services/core/java/com/android/server/wm/ContentRecorder.java b/services/core/java/com/android/server/wm/ContentRecorder.java index 022ef6152929..8717098ff8e8 100644 --- a/services/core/java/com/android/server/wm/ContentRecorder.java +++ b/services/core/java/com/android/server/wm/ContentRecorder.java @@ -16,6 +16,7 @@ package com.android.server.wm; +import static android.app.WindowConfiguration.WINDOWING_MODE_UNDEFINED; import static android.content.Context.MEDIA_PROJECTION_SERVICE; import static android.content.res.Configuration.ORIENTATION_UNDEFINED; import static android.view.ContentRecordingSession.RECORD_CONTENT_DISPLAY; @@ -100,6 +101,8 @@ final class ContentRecorder implements WindowContainerListener { @Configuration.Orientation private int mLastOrientation = ORIENTATION_UNDEFINED; + private int mLastWindowingMode = WINDOWING_MODE_UNDEFINED; + private final boolean mCorrectForAnisotropicPixels; ContentRecorder(@NonNull DisplayContent displayContent) { @@ -156,7 +159,8 @@ final class ContentRecorder implements WindowContainerListener { * Handle a configuration change on the display content, and resize recording if needed. * @param lastOrientation the prior orientation of the configuration */ - void onConfigurationChanged(@Configuration.Orientation int lastOrientation) { + void onConfigurationChanged( + @Configuration.Orientation int lastOrientation, int lastWindowingMode) { // Update surface for MediaProjection, if this DisplayContent is being used for recording. if (!isCurrentlyRecording() || mLastRecordedBounds == null) { return; @@ -185,6 +189,16 @@ final class ContentRecorder implements WindowContainerListener { } } + // Record updated windowing mode, if necessary. + int recordedContentWindowingMode = mRecordedWindowContainer.getWindowingMode(); + if (lastWindowingMode != recordedContentWindowingMode) { + mMediaProjectionManager.notifyWindowingModeChanged( + mContentRecordingSession.getContentToRecord(), + mContentRecordingSession.getTargetUid(), + recordedContentWindowingMode + ); + } + ProtoLog.v(WM_DEBUG_CONTENT_RECORDING, "Content Recording: Display %d was already recording, so apply " + "transformations if necessary", @@ -327,8 +341,10 @@ final class ContentRecorder implements WindowContainerListener { return; } + final int contentToRecord = mContentRecordingSession.getContentToRecord(); + // TODO(b/297514518) Do not start capture if the app is in PIP, the bounds are inaccurate. - if (mContentRecordingSession.getContentToRecord() == RECORD_CONTENT_TASK) { + if (contentToRecord == RECORD_CONTENT_TASK) { if (mRecordedWindowContainer.asTask().inPinnedWindowingMode()) { ProtoLog.v(WM_DEBUG_CONTENT_RECORDING, "Content Recording: Display %d should start recording, but " @@ -375,7 +391,7 @@ final class ContentRecorder implements WindowContainerListener { // Notify the client about the visibility of the mirrored region, now that we have begun // capture. - if (mContentRecordingSession.getContentToRecord() == RECORD_CONTENT_TASK) { + if (contentToRecord == RECORD_CONTENT_TASK) { mMediaProjectionManager.notifyActiveProjectionCapturedContentVisibilityChanged( mRecordedWindowContainer.asTask().isVisibleRequested()); } else { @@ -385,6 +401,11 @@ final class ContentRecorder implements WindowContainerListener { currentDisplayState != DISPLAY_STATE_OFF); } + // Record initial windowing mode after recording starts. + mMediaProjectionManager.notifyWindowingModeChanged( + contentToRecord, mContentRecordingSession.getTargetUid(), + mRecordedWindowContainer.getWindowConfiguration().getWindowingMode()); + // No need to clean up. In SurfaceFlinger, parents hold references to their children. The // mirrored SurfaceControl is alive since the parent DisplayContent SurfaceControl is // holding a reference to it. Therefore, the mirrored SurfaceControl will be cleaned up @@ -617,8 +638,9 @@ final class ContentRecorder implements WindowContainerListener { Configuration mergedOverrideConfiguration) { WindowContainerListener.super.onMergedOverrideConfigurationChanged( mergedOverrideConfiguration); - onConfigurationChanged(mLastOrientation); + onConfigurationChanged(mLastOrientation, mLastWindowingMode); mLastOrientation = mergedOverrideConfiguration.orientation; + mLastWindowingMode = mergedOverrideConfiguration.windowConfiguration.getWindowingMode(); } // WindowContainerListener @@ -635,6 +657,7 @@ final class ContentRecorder implements WindowContainerListener { void stopActiveProjection(); void notifyActiveProjectionCapturedContentResized(int width, int height); void notifyActiveProjectionCapturedContentVisibilityChanged(boolean isVisible); + void notifyWindowingModeChanged(int contentToRecord, int targetUid, int windowingMode); } private static final class RemoteMediaProjectionManagerWrapper implements @@ -700,6 +723,22 @@ final class ContentRecorder implements WindowContainerListener { } } + @Override + public void notifyWindowingModeChanged(int contentToRecord, int targetUid, + int windowingMode) { + fetchMediaProjectionManager(); + if (mIMediaProjectionManager == null) { + return; + } + try { + mIMediaProjectionManager.notifyWindowingModeChanged( + contentToRecord, targetUid, windowingMode); + } catch (RemoteException e) { + ProtoLog.e(WM_DEBUG_CONTENT_RECORDING, + "Content Recording: Unable to tell log windowing mode change: %s", e); + } + } + private void fetchMediaProjectionManager() { if (mIMediaProjectionManager != null) { return; diff --git a/services/core/java/com/android/server/wm/DisplayContent.java b/services/core/java/com/android/server/wm/DisplayContent.java index 576e8a48ab31..c716879a5097 100644 --- a/services/core/java/com/android/server/wm/DisplayContent.java +++ b/services/core/java/com/android/server/wm/DisplayContent.java @@ -2757,6 +2757,7 @@ class DisplayContent extends RootDisplayArea implements WindowManagerPolicy.Disp @Override public void onConfigurationChanged(Configuration newParentConfig) { final int lastOrientation = getConfiguration().orientation; + final int lastWindowingMode = getWindowingMode(); super.onConfigurationChanged(newParentConfig); if (mDisplayPolicy != null) { mDisplayPolicy.onConfigurationChanged(); @@ -2768,7 +2769,7 @@ class DisplayContent extends RootDisplayArea implements WindowManagerPolicy.Disp // Update surface for MediaProjection, if this DisplayContent is being used for recording. if (mContentRecorder != null) { - mContentRecorder.onConfigurationChanged(lastOrientation); + mContentRecorder.onConfigurationChanged(lastOrientation, lastWindowingMode); } if (lastOrientation != getConfiguration().orientation) { diff --git a/services/core/java/com/android/server/wm/OWNERS b/services/core/java/com/android/server/wm/OWNERS index f8c39d0906a0..cd704478aa83 100644 --- a/services/core/java/com/android/server/wm/OWNERS +++ b/services/core/java/com/android/server/wm/OWNERS @@ -18,5 +18,8 @@ rgl@google.com yunfanc@google.com wilsonshih@google.com -per-file BackgroundActivityStartController.java = set noparent -per-file BackgroundActivityStartController.java = brufino@google.com, topjohnwu@google.com, achim@google.com, ogunwale@google.com, louischang@google.com, lus@google.com +# Files related to background activity launches +per-file Background*Start* = set noparent +per-file Background*Start* = file:/BAL_OWNERS +per-file Background*Start* = ogunwale@google.com, louischang@google.com + 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/SynchedDeviceConfig.java b/services/core/java/com/android/server/wm/SynchedDeviceConfig.java index c2e819e4c60b..4d4f99f5b68e 100644 --- a/services/core/java/com/android/server/wm/SynchedDeviceConfig.java +++ b/services/core/java/com/android/server/wm/SynchedDeviceConfig.java @@ -20,7 +20,6 @@ import android.annotation.NonNull; import android.provider.DeviceConfig; import java.util.Map; -import java.util.Optional; import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.Executor; @@ -98,27 +97,28 @@ final class SynchedDeviceConfig implements DeviceConfig.OnPropertiesChangedListe * @throws IllegalArgumentException {@code key} isn't recognised. */ boolean getFlagValue(@NonNull String key) { - return findEntry(key).map(SynchedDeviceConfigEntry::getValue) - .orElseThrow(() -> new IllegalArgumentException("Unexpected flag name: " + key)); + final SynchedDeviceConfigEntry entry = mDeviceConfigEntries.get(key); + if (entry == null) { + throw new IllegalArgumentException("Unexpected flag name: " + key); + } + return entry.getValue(); } /** * @return {@code true} if the flag for the given {@code key} was enabled at build time. */ boolean isBuildTimeFlagEnabled(@NonNull String key) { - return findEntry(key).map(SynchedDeviceConfigEntry::isBuildTimeFlagEnabled) - .orElseThrow(() -> new IllegalArgumentException("Unexpected flag name: " + key)); + final SynchedDeviceConfigEntry entry = mDeviceConfigEntries.get(key); + if (entry == null) { + throw new IllegalArgumentException("Unexpected flag name: " + key); + } + return entry.isBuildTimeFlagEnabled(); } private boolean isDeviceConfigFlagEnabled(@NonNull String key, boolean defaultValue) { return DeviceConfig.getBoolean(mNamespace, key, defaultValue); } - @NonNull - private Optional<SynchedDeviceConfigEntry> findEntry(@NonNull String key) { - return Optional.ofNullable(mDeviceConfigEntries.get(key)); - } - static class SynchedDeviceConfigBuilder { private final String mNamespace; diff --git a/services/core/java/com/android/server/wm/Task.java b/services/core/java/com/android/server/wm/Task.java index 6cad16c7db40..5c5a1e1d23dc 100644 --- a/services/core/java/com/android/server/wm/Task.java +++ b/services/core/java/com/android/server/wm/Task.java @@ -6541,11 +6541,11 @@ class Task extends TaskFragment { mActivityType = ACTIVITY_TYPE_STANDARD; } - if (mActivityType != ACTIVITY_TYPE_STANDARD + if (!DisplayContent.alwaysCreateRootTask(tda.getWindowingMode(), mActivityType) && mActivityType != ACTIVITY_TYPE_UNDEFINED) { - // For now there can be only one root task of a particular non-standard activity - // type on a display. So, get that ignoring whatever windowing mode it is - // currently in. + // Only Recents or Standard activity types are allowed to have more than one + // root task on a display, this is independent of whatever windowing mode it + // is currently in. Task rootTask = tda.getRootTask(WINDOWING_MODE_UNDEFINED, mActivityType); if (rootTask != null) { throw new IllegalArgumentException("Root task=" + rootTask + " of activityType=" 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/WindowOrganizerController.java b/services/core/java/com/android/server/wm/WindowOrganizerController.java index a8b9417edb9b..3497353a9849 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); 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/AppStateTrackerTest.java b/services/tests/mockingservicestests/src/com/android/server/AppStateTrackerTest.java index 47ae97fc5d27..7ceccc57c0f1 100644 --- a/services/tests/mockingservicestests/src/com/android/server/AppStateTrackerTest.java +++ b/services/tests/mockingservicestests/src/com/android/server/AppStateTrackerTest.java @@ -44,6 +44,7 @@ import android.app.AppOpsManager.PackageOps; import android.app.IActivityManager; import android.app.IUidObserver; import android.app.usage.UsageStatsManager; +import android.content.AttributionSourceState; import android.content.BroadcastReceiver; import android.content.Context; import android.content.Intent; @@ -229,12 +230,20 @@ public class AppStateTrackerTest { private AppStateTrackerTestable newInstance() throws Exception { MockitoAnnotations.initMocks(this); - when(mMockIAppOpsService.checkOperation(eq(TARGET_OP), anyInt(), anyString())) - .thenAnswer(inv -> { - return mRestrictedPackages.indexOf( - Pair.create(inv.getArgument(1), inv.getArgument(2))) >= 0 ? - AppOpsManager.MODE_IGNORED : AppOpsManager.MODE_ALLOWED; - }); + when(mMockIAppOpsService.checkOperationWithState(eq(TARGET_OP), any())) + .thenAnswer( + (Answer<Integer>) + invocation -> { + AttributionSourceState attribution = + (AttributionSourceState) invocation.getArguments()[1]; + return mRestrictedPackages.indexOf( + Pair.create( + attribution.uid, + attribution.packageName)) + >= 0 + ? AppOpsManager.MODE_IGNORED + : AppOpsManager.MODE_ALLOWED; + }); final AppStateTrackerTestable instance = new AppStateTrackerTestable(); 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 40b5458b06b9..3ee8050cda3e 100644 --- a/services/tests/mockingservicestests/src/com/android/server/am/ActivityManagerServiceTest.java +++ b/services/tests/mockingservicestests/src/com/android/server/am/ActivityManagerServiceTest.java @@ -69,6 +69,7 @@ import android.app.BroadcastOptions; import android.app.IApplicationThread; import android.app.IUidObserver; import android.app.SyncNotedAppOp; +import android.content.AttributionSourceState; import android.content.ComponentName; import android.content.Context; import android.content.Intent; @@ -223,12 +224,16 @@ public class ActivityManagerServiceTest { assertThat(sProcessListSettingsListener).isNotNull(); } - private void mockNoteOperation() { + private void mockNoteOp() { SyncNotedAppOp allowed = new SyncNotedAppOp(AppOpsManager.MODE_ALLOWED, AppOpsManager.OP_GET_USAGE_STATS, null, mContext.getPackageName()); - when(mAppOpsService.noteOperation(eq(AppOpsManager.OP_GET_USAGE_STATS), eq(Process.myUid()), - nullable(String.class), nullable(String.class), any(Boolean.class), - nullable(String.class), any(Boolean.class))).thenReturn(allowed); + when(mAppOpsService.noteOperationWithState( + eq(AppOpsManager.OP_GET_USAGE_STATS), + any(AttributionSourceState.class), + any(Boolean.class), + nullable(String.class), + any(Boolean.class))) + .thenReturn(allowed); } @After @@ -609,7 +614,7 @@ public class ActivityManagerServiceTest { */ @Test public void testDispatchUids_dispatchNeededChanges() throws RemoteException { - mockNoteOperation(); + mockNoteOp(); final int[] changesToObserve = { ActivityManager.UID_OBSERVER_PROCSTATE, @@ -818,7 +823,7 @@ public class ActivityManagerServiceTest { */ @Test public void testDispatchUidChanges_procStateCutpoint() throws RemoteException { - mockNoteOperation(); + mockNoteOp(); final IUidObserver observer = mock(IUidObserver.Stub.class); @@ -888,7 +893,7 @@ public class ActivityManagerServiceTest { */ @Test public void testDispatchUidChanges_validateUidsUpdated() { - mockNoteOperation(); + mockNoteOp(); final int[] changesForPendingItems = UID_RECORD_CHANGES; diff --git a/services/tests/mockingservicestests/src/com/android/server/am/BackgroundRestrictionTest.java b/services/tests/mockingservicestests/src/com/android/server/am/BackgroundRestrictionTest.java index bb91939c430e..dcbee83b839b 100644 --- a/services/tests/mockingservicestests/src/com/android/server/am/BackgroundRestrictionTest.java +++ b/services/tests/mockingservicestests/src/com/android/server/am/BackgroundRestrictionTest.java @@ -113,6 +113,8 @@ import android.app.Notification; import android.app.NotificationManager; import android.app.role.RoleManager; import android.app.usage.AppStandbyInfo; +import android.content.AttributionSource; +import android.content.AttributionSourceState; import android.content.Context; import android.content.Intent; import android.content.pm.PackageManager; @@ -2454,9 +2456,12 @@ public final class BackgroundRestrictionTest { doReturn(granted ? MODE_ALLOWED : MODE_IGNORED) .when(mAppOpsManager) .checkOpNoThrow(op, uid, packageName); + AttributionSource attributionSource = + new AttributionSource.Builder(uid).setPackageName(packageName).build(); + AttributionSourceState attributionSourceState = attributionSource.asState(); doReturn(granted ? MODE_ALLOWED : MODE_IGNORED) .when(mIAppOpsService) - .checkOperation(op, uid, packageName); + .checkOperationWithState(eq(op), eq(attributionSourceState)); } catch (RemoteException e) { // Ignore. } diff --git a/services/tests/mockingservicestests/src/com/android/server/appop/AppOpsServiceTest.java b/services/tests/mockingservicestests/src/com/android/server/appop/AppOpsServiceTest.java index 646f4862d75d..daed5df4edd7 100644 --- a/services/tests/mockingservicestests/src/com/android/server/appop/AppOpsServiceTest.java +++ b/services/tests/mockingservicestests/src/com/android/server/appop/AppOpsServiceTest.java @@ -49,6 +49,7 @@ import static org.mockito.ArgumentMatchers.nullable; import android.app.AppOpsManager; import android.app.AppOpsManager.OpEntry; import android.app.AppOpsManager.PackageOps; +import android.content.AttributionSource; import android.content.ContentResolver; import android.content.Context; import android.content.pm.PackageManagerInternal; @@ -216,18 +217,21 @@ public class AppOpsServiceTest { } @Test - public void testNoteOperationAndGetOpsForPackage() { + public void testNoteOpAndGetOpsForPackage() { mAppOpsService.setMode(OP_READ_SMS, mMyUid, sMyPackageName, MODE_ALLOWED); mAppOpsService.setMode(OP_WRITE_SMS, mMyUid, sMyPackageName, MODE_ERRORED); + AttributionSource attributionSource = + new AttributionSource.Builder(mMyUid).setPackageName(sMyPackageName).build(); // Note an op that's allowed. - mAppOpsService.noteOperation(OP_READ_SMS, mMyUid, sMyPackageName, null, false, null, false); + mAppOpsService.noteOperationWithState(OP_READ_SMS, attributionSource.asState(), false, + null, false); List<PackageOps> loggedOps = getLoggedOps(); assertContainsOp(loggedOps, OP_READ_SMS, mTestStartMillis, -1, MODE_ALLOWED); // Note another op that's not allowed. - mAppOpsService.noteOperation(OP_WRITE_SMS, mMyUid, sMyPackageName, null, false, null, - false); + mAppOpsService.noteOperationWithState(OP_WRITE_SMS, attributionSource.asState(), false, + null, false); loggedOps = getLoggedOps(); assertContainsOp(loggedOps, OP_READ_SMS, mTestStartMillis, -1, MODE_ALLOWED); assertContainsOp(loggedOps, OP_WRITE_SMS, -1, mTestStartMillis, MODE_ERRORED); @@ -239,20 +243,24 @@ public class AppOpsServiceTest { * ACCESS_COARSE_LOCATION op is used to check whether WIFI_SCAN is allowed. */ @Test - public void testNoteOperationAndGetOpsForPackage_controlledByDifferentOp() { + public void testNoteOpAndGetOpsForPackage_controlledByDifferentOp() { // This op controls WIFI_SCAN mAppOpsService.setMode(OP_COARSE_LOCATION, mMyUid, sMyPackageName, MODE_ALLOWED); - assertThat(mAppOpsService.noteOperation(OP_WIFI_SCAN, mMyUid, sMyPackageName, null, false, - null, false).getOpMode()).isEqualTo(MODE_ALLOWED); + assertThat(mAppOpsService.noteOperationWithState(OP_WIFI_SCAN, + new AttributionSource.Builder(mMyUid).setPackageName(sMyPackageName) + .build().asState(), false, null, false).getOpMode()) + .isEqualTo(MODE_ALLOWED); assertContainsOp(getLoggedOps(), OP_WIFI_SCAN, mTestStartMillis, -1, MODE_ALLOWED /* default for WIFI_SCAN; this is not changed or used in this test */); // Now set COARSE_LOCATION to ERRORED -> this will make WIFI_SCAN disabled as well. mAppOpsService.setMode(OP_COARSE_LOCATION, mMyUid, sMyPackageName, MODE_ERRORED); - assertThat(mAppOpsService.noteOperation(OP_WIFI_SCAN, mMyUid, sMyPackageName, null, false, - null, false).getOpMode()).isEqualTo(MODE_ERRORED); + assertThat(mAppOpsService.noteOperationWithState(OP_WIFI_SCAN, + new AttributionSource.Builder(mMyUid).setPackageName(sMyPackageName) + .build().asState(), false, null, false) + .getOpMode()).isEqualTo(MODE_ERRORED); assertContainsOp(getLoggedOps(), OP_WIFI_SCAN, mTestStartMillis, mTestStartMillis, MODE_ALLOWED /* default for WIFI_SCAN; this is not changed or used in this test */); @@ -263,9 +271,12 @@ public class AppOpsServiceTest { public void testStatePersistence() { mAppOpsService.setMode(OP_READ_SMS, mMyUid, sMyPackageName, MODE_ALLOWED); mAppOpsService.setMode(OP_WRITE_SMS, mMyUid, sMyPackageName, MODE_ERRORED); - mAppOpsService.noteOperation(OP_READ_SMS, mMyUid, sMyPackageName, null, false, null, false); - mAppOpsService.noteOperation(OP_WRITE_SMS, mMyUid, sMyPackageName, null, false, null, - false); + AttributionSource attributionSource = + new AttributionSource.Builder(mMyUid).setPackageName(sMyPackageName).build(); + mAppOpsService.noteOperationWithState(OP_READ_SMS, attributionSource.asState(), false, + null, false); + mAppOpsService.noteOperationWithState(OP_WRITE_SMS, attributionSource.asState(), false, + null, false); mAppOpsService.shutdown(); @@ -283,7 +294,10 @@ public class AppOpsServiceTest { @Test public void testShutdown() { mAppOpsService.setMode(OP_READ_SMS, mMyUid, sMyPackageName, MODE_ALLOWED); - mAppOpsService.noteOperation(OP_READ_SMS, mMyUid, sMyPackageName, null, false, null, false); + AttributionSource attributionSource = + new AttributionSource.Builder(mMyUid).setPackageName(sMyPackageName).build(); + mAppOpsService.noteOperationWithState(OP_READ_SMS, attributionSource.asState(), false, + null, false); mAppOpsService.shutdown(); // Create a new app ops service which will initialize its state from XML. @@ -297,7 +311,10 @@ public class AppOpsServiceTest { @Test public void testGetOpsForPackage() { mAppOpsService.setMode(OP_READ_SMS, mMyUid, sMyPackageName, MODE_ALLOWED); - mAppOpsService.noteOperation(OP_READ_SMS, mMyUid, sMyPackageName, null, false, null, false); + AttributionSource attributionSource = + new AttributionSource.Builder(mMyUid).setPackageName(sMyPackageName).build(); + mAppOpsService.noteOperationWithState(OP_READ_SMS, attributionSource.asState(), false, + null, false); // Query all ops List<PackageOps> loggedOps = mAppOpsService.getOpsForPackage( @@ -326,7 +343,10 @@ public class AppOpsServiceTest { @Test public void testPackageRemoved() { mAppOpsService.setMode(OP_READ_SMS, mMyUid, sMyPackageName, MODE_ALLOWED); - mAppOpsService.noteOperation(OP_READ_SMS, mMyUid, sMyPackageName, null, false, null, false); + AttributionSource attributionSource = + new AttributionSource.Builder(mMyUid).setPackageName(sMyPackageName).build(); + mAppOpsService.noteOperationWithState(OP_READ_SMS, attributionSource.asState(), false, + null, false); List<PackageOps> loggedOps = getLoggedOps(); assertContainsOp(loggedOps, OP_READ_SMS, mTestStartMillis, -1, MODE_ALLOWED); @@ -341,7 +361,8 @@ public class AppOpsServiceTest { @Test public void testPackageRemovedHistoricalOps() throws InterruptedException { mAppOpsService.setMode(OP_READ_SMS, mMyUid, sMyPackageName, MODE_ALLOWED); - mAppOpsService.noteOperation(OP_READ_SMS, mMyUid, sMyPackageName, null, false, null, false); + mAppOpsService.noteOperationWithState(OP_READ_SMS, mMyUid, sMyPackageName, null, false, + null, false); AppOpsManager.HistoricalOps historicalOps = new AppOpsManager.HistoricalOps(0, 15000); historicalOps.increaseAccessCount(OP_READ_SMS, mMyUid, sMyPackageName, null, @@ -381,7 +402,10 @@ public class AppOpsServiceTest { @Test public void testUidRemoved() { mAppOpsService.setMode(OP_READ_SMS, mMyUid, sMyPackageName, MODE_ALLOWED); - mAppOpsService.noteOperation(OP_READ_SMS, mMyUid, sMyPackageName, null, false, null, false); + AttributionSource attributionSource = + new AttributionSource.Builder(mMyUid).setPackageName(sMyPackageName).build(); + mAppOpsService.noteOperationWithState(OP_READ_SMS, attributionSource.asState(), + false, null, false); List<PackageOps> loggedOps = getLoggedOps(); assertContainsOp(loggedOps, OP_READ_SMS, mTestStartMillis, -1, MODE_ALLOWED); @@ -393,7 +417,10 @@ public class AppOpsServiceTest { @Test public void testUidStateInitializationDoesntClearState() throws InterruptedException { mAppOpsService.setMode(OP_READ_SMS, mMyUid, sMyPackageName, MODE_ALLOWED); - mAppOpsService.noteOperation(OP_READ_SMS, mMyUid, sMyPackageName, null, false, null, false); + AttributionSource attributionSource = + new AttributionSource.Builder(mMyUid).setPackageName(sMyPackageName).build(); + mAppOpsService.noteOperationWithState(OP_READ_SMS, attributionSource.asState(), false, + null, false); mAppOpsService.initializeUidStates(); List<PackageOps> ops = mAppOpsService.getOpsForPackage(mMyUid, sMyPackageName, new int[]{OP_READ_SMS}); 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 e7f1d16e1dfd..5c8a19c76887 100644 --- a/services/tests/mockingservicestests/src/com/android/server/pm/PackageArchiverTest.java +++ b/services/tests/mockingservicestests/src/com/android/server/pm/PackageArchiverTest.java @@ -182,6 +182,10 @@ public class PackageArchiverTest { any(LauncherActivityInfo.class), eq(mUserId), anyInt(), anyInt()); doReturn(mIcon).when(mArchiveManager).decodeIcon( any(ArchiveState.ArchiveActivityInfo.class)); + Resources mockResources = mock(Resources.class); + doReturn(mockResources) + .when(mContext) + .getResources(); } @Test diff --git a/services/tests/servicestests/src/com/android/server/media/projection/MediaProjectionManagerServiceTest.java b/services/tests/servicestests/src/com/android/server/media/projection/MediaProjectionManagerServiceTest.java index ece3dfeabafa..097cc5177a83 100644 --- a/services/tests/servicestests/src/com/android/server/media/projection/MediaProjectionManagerServiceTest.java +++ b/services/tests/servicestests/src/com/android/server/media/projection/MediaProjectionManagerServiceTest.java @@ -17,12 +17,17 @@ package com.android.server.media.projection; +import static android.app.WindowConfiguration.WINDOWING_MODE_MULTI_WINDOW; import static android.content.pm.ApplicationInfo.PRIVATE_FLAG_PRIVILEGED; import static android.media.projection.MediaProjectionManager.TYPE_MIRRORING; import static android.media.projection.ReviewGrantedConsentResult.RECORD_CANCEL; import static android.media.projection.ReviewGrantedConsentResult.RECORD_CONTENT_DISPLAY; import static android.media.projection.ReviewGrantedConsentResult.RECORD_CONTENT_TASK; import static android.media.projection.ReviewGrantedConsentResult.UNKNOWN; +import static android.view.ContentRecordingSession.TARGET_UID_FULL_SCREEN; +import static android.view.ContentRecordingSession.TARGET_UID_UNKNOWN; +import static android.view.ContentRecordingSession.createDisplaySession; +import static android.view.ContentRecordingSession.createTaskSession; import static android.view.Display.DEFAULT_DISPLAY; import static android.view.Display.INVALID_DISPLAY; @@ -62,6 +67,7 @@ import android.os.UserHandle; import android.os.test.TestLooper; import android.platform.test.annotations.Presubmit; import android.view.ContentRecordingSession; +import android.view.ContentRecordingSession.RecordContent; import androidx.test.ext.junit.runners.AndroidJUnit4; import androidx.test.filters.FlakyTest; @@ -99,7 +105,7 @@ public class MediaProjectionManagerServiceTest { private final ApplicationInfo mAppInfo = new ApplicationInfo(); private final TestLooper mTestLooper = new TestLooper(); private static final ContentRecordingSession DISPLAY_SESSION = - ContentRecordingSession.createDisplaySession(DEFAULT_DISPLAY); + createDisplaySession(DEFAULT_DISPLAY); // Callback registered by an app on a MediaProjection instance. private final FakeIMediaProjectionCallback mIMediaProjectionCallback = new FakeIMediaProjectionCallback(); @@ -142,7 +148,7 @@ public class MediaProjectionManagerServiceTest { private MediaProjectionManagerService mService; private OffsettableClock mClock; private ContentRecordingSession mWaitingDisplaySession = - ContentRecordingSession.createDisplaySession(DEFAULT_DISPLAY); + createDisplaySession(DEFAULT_DISPLAY); @Mock private ActivityManagerInternal mAmInternal; @@ -333,7 +339,7 @@ public class MediaProjectionManagerServiceTest { projection.stop(); verify(mMediaProjectionMetricsLogger) - .logStopped(UID, ContentRecordingSession.TARGET_UID_UNKNOWN); + .logStopped(UID, TARGET_UID_UNKNOWN); } @Test @@ -351,7 +357,7 @@ public class MediaProjectionManagerServiceTest { projection.stop(); verify(mMediaProjectionMetricsLogger) - .logStopped(UID, ContentRecordingSession.TARGET_UID_FULL_SCREEN); + .logStopped(UID, TARGET_UID_FULL_SCREEN); } @Test @@ -366,7 +372,7 @@ public class MediaProjectionManagerServiceTest { .when(mWindowManagerInternal) .setContentRecordingSession(any(ContentRecordingSession.class)); ContentRecordingSession taskSession = - ContentRecordingSession.createTaskSession(mock(IBinder.class), targetUid); + createTaskSession(mock(IBinder.class), targetUid); service.setContentRecordingSession(taskSession); projection.stop(); @@ -695,6 +701,26 @@ public class MediaProjectionManagerServiceTest { verify(mMediaProjectionMetricsLogger).logAppSelectorDisplayed(hostUid); } + @Test + public void notifyWindowingModeChanged_forwardsToLogger() throws Exception { + int targetUid = 123; + mService = + new MediaProjectionManagerService(mContext, mMediaProjectionMetricsLoggerInjector); + + ContentRecordingSession taskSession = + createTaskSession(mock(IBinder.class), targetUid); + mService.setContentRecordingSession(taskSession); + + MediaProjectionManagerService.MediaProjection projection = startProjectionPreconditions(); + projection.start(mIMediaProjectionCallback); + + mService.notifyWindowingModeChanged( + RECORD_CONTENT_TASK, targetUid, WINDOWING_MODE_MULTI_WINDOW); + + verify(mMediaProjectionMetricsLogger).logChangedWindowingMode(RECORD_CONTENT_TASK, + projection.uid, targetUid, WINDOWING_MODE_MULTI_WINDOW); + } + /** * Executes and validates scenario where the consent result indicates the projection ends. */ @@ -755,7 +781,7 @@ public class MediaProjectionManagerServiceTest { */ private void testSetUserReviewGrantedConsentResult_startedSession( @ReviewGrantedConsentResult int consentResult, - @ContentRecordingSession.RecordContent int recordedContent) + @RecordContent int recordedContent) throws NameNotFoundException { MediaProjectionManagerService.MediaProjection projection = startProjectionPreconditions(); projection.setLaunchCookie(mock(IBinder.class)); @@ -777,7 +803,7 @@ public class MediaProjectionManagerServiceTest { */ private void testSetUserReviewGrantedConsentResult_failedToStartSession( @ReviewGrantedConsentResult int consentResult, - @ContentRecordingSession.RecordContent int recordedContent) + @RecordContent int recordedContent) throws NameNotFoundException { MediaProjectionManagerService.MediaProjection projection = startProjectionPreconditions(); projection.start(mIMediaProjectionCallback); @@ -889,7 +915,7 @@ public class MediaProjectionManagerServiceTest { int targetUid = 123455; ContentRecordingSession taskSession = - ContentRecordingSession.createTaskSession(mock(IBinder.class), targetUid); + createTaskSession(mock(IBinder.class), targetUid); service.setContentRecordingSession(taskSession); verify(mMediaProjectionMetricsLogger).logInProgress(projection.uid, targetUid); @@ -970,7 +996,7 @@ public class MediaProjectionManagerServiceTest { verify(mWatcherCallback, never()).onRecordingSessionSet(any(), any()); } - private void verifySetSessionWithContent(@ContentRecordingSession.RecordContent int content) { + private void verifySetSessionWithContent(@RecordContent int content) { verify(mWindowManagerInternal, atLeastOnce()).setContentRecordingSession( mSessionCaptor.capture()); assertThat(mSessionCaptor.getValue()).isNotNull(); diff --git a/services/tests/servicestests/src/com/android/server/media/projection/MediaProjectionMetricsLoggerTest.java b/services/tests/servicestests/src/com/android/server/media/projection/MediaProjectionMetricsLoggerTest.java index ad1cd6eca5ac..72ce9fe9a23f 100644 --- a/services/tests/servicestests/src/com/android/server/media/projection/MediaProjectionMetricsLoggerTest.java +++ b/services/tests/servicestests/src/com/android/server/media/projection/MediaProjectionMetricsLoggerTest.java @@ -16,6 +16,14 @@ package com.android.server.media.projection; +import static android.app.WindowConfiguration.WINDOWING_MODE_FREEFORM; +import static android.app.WindowConfiguration.WINDOWING_MODE_FULLSCREEN; +import static android.app.WindowConfiguration.WINDOWING_MODE_MULTI_WINDOW; +import static android.app.WindowConfiguration.WINDOWING_MODE_PINNED; +import static android.app.WindowConfiguration.WINDOWING_MODE_UNDEFINED; +import static android.view.ContentRecordingSession.RECORD_CONTENT_DISPLAY; +import static android.view.ContentRecordingSession.RECORD_CONTENT_TASK; + import static com.android.internal.util.FrameworkStatsLog.MEDIA_PROJECTION_STATE_CHANGED__CREATION_SOURCE__CREATION_SOURCE_UNKNOWN; import static com.android.internal.util.FrameworkStatsLog.MEDIA_PROJECTION_STATE_CHANGED__STATE__MEDIA_PROJECTION_STATE_APP_SELECTOR_DISPLAYED; import static com.android.internal.util.FrameworkStatsLog.MEDIA_PROJECTION_STATE_CHANGED__STATE__MEDIA_PROJECTION_STATE_CANCELLED; @@ -24,6 +32,13 @@ import static com.android.internal.util.FrameworkStatsLog.MEDIA_PROJECTION_STATE import static com.android.internal.util.FrameworkStatsLog.MEDIA_PROJECTION_STATE_CHANGED__STATE__MEDIA_PROJECTION_STATE_PERMISSION_REQUEST_DISPLAYED; import static com.android.internal.util.FrameworkStatsLog.MEDIA_PROJECTION_STATE_CHANGED__STATE__MEDIA_PROJECTION_STATE_STOPPED; import static com.android.internal.util.FrameworkStatsLog.MEDIA_PROJECTION_STATE_CHANGED__STATE__MEDIA_PROJECTION_STATE_UNKNOWN; +import static com.android.internal.util.FrameworkStatsLog.MEDIA_PROJECTION_TARGET_CHANGED__TARGET_TYPE__TARGET_TYPE_APP_TASK; +import static com.android.internal.util.FrameworkStatsLog.MEDIA_PROJECTION_TARGET_CHANGED__TARGET_TYPE__TARGET_TYPE_DISPLAY; +import static com.android.internal.util.FrameworkStatsLog.MEDIA_PROJECTION_TARGET_CHANGED__TARGET_TYPE__TARGET_TYPE_UNKNOWN; +import static com.android.internal.util.FrameworkStatsLog.MEDIA_PROJECTION_TARGET_CHANGED__TARGET_WINDOWING_MODE__WINDOWING_MODE_FREEFORM; +import static com.android.internal.util.FrameworkStatsLog.MEDIA_PROJECTION_TARGET_CHANGED__TARGET_WINDOWING_MODE__WINDOWING_MODE_FULLSCREEN; +import static com.android.internal.util.FrameworkStatsLog.MEDIA_PROJECTION_TARGET_CHANGED__TARGET_WINDOWING_MODE__WINDOWING_MODE_SPLIT_SCREEN; +import static com.android.internal.util.FrameworkStatsLog.MEDIA_PROJECTION_TARGET_CHANGED__TARGET_WINDOWING_MODE__WINDOWING_MODE_UNKNOWN; import static org.mockito.ArgumentMatchers.anyInt; import static org.mockito.ArgumentMatchers.eq; @@ -38,10 +53,14 @@ import androidx.test.filters.SmallTest; import com.android.internal.util.FrameworkStatsLog; +import com.google.common.truth.Expect; + import org.junit.Before; +import org.junit.Rule; import org.junit.Test; import org.junit.runner.RunWith; import org.mockito.Mock; +import org.mockito.Mockito; import org.mockito.MockitoAnnotations; import java.time.Duration; @@ -60,12 +79,18 @@ public class MediaProjectionMetricsLoggerTest { private static final int TEST_TARGET_UID = 456; private static final int TEST_CREATION_SOURCE = 789; + private static final int TEST_WINDOWING_MODE = 987; + private static final int TEST_CONTENT_TO_RECORD = 654; + @Mock private FrameworkStatsLogWrapper mFrameworkStatsLogWrapper; @Mock private MediaProjectionSessionIdGenerator mSessionIdGenerator; @Mock private MediaProjectionTimestampStore mTimestampStore; private MediaProjectionMetricsLogger mLogger; + @Rule + public Expect mExpect = Expect.create(); + @Before public void setUp() { MockitoAnnotations.initMocks(this); @@ -93,7 +118,7 @@ public class MediaProjectionMetricsLoggerTest { public void logInitiated_logsHostUid() { mLogger.logInitiated(TEST_HOST_UID, TEST_CREATION_SOURCE); - verifyHostUidLogged(TEST_HOST_UID); + verifyStateChangedHostUidLogged(TEST_HOST_UID); } @Test @@ -107,7 +132,7 @@ public class MediaProjectionMetricsLoggerTest { public void logInitiated_logsUnknownTargetUid() { mLogger.logInitiated(TEST_HOST_UID, TEST_CREATION_SOURCE); - verifyTargetUidLogged(-2); + verifyStageChangedTargetUidLogged(-2); } @Test @@ -178,14 +203,14 @@ public class MediaProjectionMetricsLoggerTest { public void logStopped_logsHostUid() { mLogger.logStopped(TEST_HOST_UID, TEST_TARGET_UID); - verifyHostUidLogged(TEST_HOST_UID); + verifyStateChangedHostUidLogged(TEST_HOST_UID); } @Test public void logStopped_logsTargetUid() { mLogger.logStopped(TEST_HOST_UID, TEST_TARGET_UID); - verifyTargetUidLogged(TEST_TARGET_UID); + verifyStageChangedTargetUidLogged(TEST_TARGET_UID); } @Test @@ -263,14 +288,14 @@ public class MediaProjectionMetricsLoggerTest { public void logInProgress_logsHostUid() { mLogger.logInProgress(TEST_HOST_UID, TEST_TARGET_UID); - verifyHostUidLogged(TEST_HOST_UID); + verifyStateChangedHostUidLogged(TEST_HOST_UID); } @Test public void logInProgress_logsTargetUid() { mLogger.logInProgress(TEST_HOST_UID, TEST_TARGET_UID); - verifyTargetUidLogged(TEST_TARGET_UID); + verifyStageChangedTargetUidLogged(TEST_TARGET_UID); } @Test @@ -336,14 +361,14 @@ public class MediaProjectionMetricsLoggerTest { public void logPermissionRequestDisplayed_logsHostUid() { mLogger.logPermissionRequestDisplayed(TEST_HOST_UID); - verifyHostUidLogged(TEST_HOST_UID); + verifyStateChangedHostUidLogged(TEST_HOST_UID); } @Test public void logPermissionRequestDisplayed_logsUnknownTargetUid() { mLogger.logPermissionRequestDisplayed(TEST_HOST_UID); - verifyTargetUidLogged(-2); + verifyStageChangedTargetUidLogged(-2); } @Test @@ -409,14 +434,14 @@ public class MediaProjectionMetricsLoggerTest { public void logAppSelectorDisplayed_logsHostUid() { mLogger.logAppSelectorDisplayed(TEST_HOST_UID); - verifyHostUidLogged(TEST_HOST_UID); + verifyStateChangedHostUidLogged(TEST_HOST_UID); } @Test public void logAppSelectorDisplayed_logsUnknownTargetUid() { mLogger.logAppSelectorDisplayed(TEST_HOST_UID); - verifyTargetUidLogged(-2); + verifyStageChangedTargetUidLogged(-2); } @Test @@ -492,14 +517,14 @@ public class MediaProjectionMetricsLoggerTest { public void logProjectionPermissionRequestCancelled_logsHostUid() { mLogger.logProjectionPermissionRequestCancelled(TEST_HOST_UID); - verifyHostUidLogged(TEST_HOST_UID); + verifyStateChangedHostUidLogged(TEST_HOST_UID); } @Test public void logProjectionPermissionRequestCancelled_logsUnknownTargetUid() { mLogger.logProjectionPermissionRequestCancelled(TEST_HOST_UID); - verifyTargetUidLogged(-2); + verifyStageChangedTargetUidLogged(-2); } @Test @@ -510,9 +535,88 @@ public class MediaProjectionMetricsLoggerTest { MEDIA_PROJECTION_STATE_CHANGED__CREATION_SOURCE__CREATION_SOURCE_UNKNOWN); } + @Test + public void logWindowingModeChanged_logsTargetChangedAtomId() { + mLogger.logChangedWindowingMode( + TEST_CONTENT_TO_RECORD, TEST_HOST_UID, TEST_TARGET_UID, TEST_WINDOWING_MODE); + + verifyTargetChangedAtomIdLogged(); + } + + @Test + public void logWindowingModeChanged_logsTargetType() { + MediaProjectionMetricsLogger logger = Mockito.spy(mLogger); + final int testTargetType = 111; + when(logger.contentToRecordToTargetType(TEST_CONTENT_TO_RECORD)).thenReturn(testTargetType); + logger.logChangedWindowingMode( + TEST_CONTENT_TO_RECORD, TEST_HOST_UID, TEST_TARGET_UID, TEST_WINDOWING_MODE); + verifyTargetTypeLogged(testTargetType); + } + + @Test + public void logWindowingModeChanged_logsHostUid() { + mLogger.logChangedWindowingMode( + TEST_CONTENT_TO_RECORD, TEST_HOST_UID, TEST_TARGET_UID, TEST_WINDOWING_MODE); + verifyTargetChangedHostUidLogged(TEST_HOST_UID); + } + + @Test + public void logWindowingModeChanged_logsTargetUid() { + mLogger.logChangedWindowingMode( + TEST_CONTENT_TO_RECORD, TEST_HOST_UID, TEST_TARGET_UID, TEST_WINDOWING_MODE); + verifyTargetChangedTargetUidLogged(TEST_TARGET_UID); + } + + @Test + public void logWindowingModeChanged_logsTargetWindowingMode() { + MediaProjectionMetricsLogger logger = Mockito.spy(mLogger); + final int testTargetWindowingMode = 222; + when(logger.windowingModeToTargetWindowingMode(TEST_WINDOWING_MODE)) + .thenReturn(testTargetWindowingMode); + logger.logChangedWindowingMode( + TEST_CONTENT_TO_RECORD, TEST_HOST_UID, TEST_TARGET_UID, TEST_WINDOWING_MODE); + verifyWindowingModeLogged(testTargetWindowingMode); + } + + @Test + public void testContentToRecordToTargetType() { + mExpect.that(mLogger.contentToRecordToTargetType(RECORD_CONTENT_DISPLAY)) + .isEqualTo(MEDIA_PROJECTION_TARGET_CHANGED__TARGET_TYPE__TARGET_TYPE_DISPLAY); + + mExpect.that(mLogger.contentToRecordToTargetType(RECORD_CONTENT_TASK)) + .isEqualTo(MEDIA_PROJECTION_TARGET_CHANGED__TARGET_TYPE__TARGET_TYPE_APP_TASK); + + mExpect.that(mLogger.contentToRecordToTargetType(2)) + .isEqualTo(MEDIA_PROJECTION_TARGET_CHANGED__TARGET_TYPE__TARGET_TYPE_UNKNOWN); + + mExpect.that(mLogger.contentToRecordToTargetType(-1)) + .isEqualTo(MEDIA_PROJECTION_TARGET_CHANGED__TARGET_TYPE__TARGET_TYPE_UNKNOWN); + + mExpect.that(mLogger.contentToRecordToTargetType(100)) + .isEqualTo(MEDIA_PROJECTION_TARGET_CHANGED__TARGET_TYPE__TARGET_TYPE_UNKNOWN); + } + + @Test + public void testWindowingModeToTargetWindowingMode() { + mExpect.that(mLogger.windowingModeToTargetWindowingMode(WINDOWING_MODE_FULLSCREEN)) + .isEqualTo(MEDIA_PROJECTION_TARGET_CHANGED__TARGET_WINDOWING_MODE__WINDOWING_MODE_FULLSCREEN); + + mExpect.that(mLogger.windowingModeToTargetWindowingMode(WINDOWING_MODE_MULTI_WINDOW)) + .isEqualTo(MEDIA_PROJECTION_TARGET_CHANGED__TARGET_WINDOWING_MODE__WINDOWING_MODE_SPLIT_SCREEN); + + mExpect.that(mLogger.windowingModeToTargetWindowingMode(WINDOWING_MODE_FREEFORM)) + .isEqualTo(MEDIA_PROJECTION_TARGET_CHANGED__TARGET_WINDOWING_MODE__WINDOWING_MODE_FREEFORM); + + mExpect.that(mLogger.windowingModeToTargetWindowingMode(WINDOWING_MODE_PINNED)) + .isEqualTo(MEDIA_PROJECTION_TARGET_CHANGED__TARGET_WINDOWING_MODE__WINDOWING_MODE_UNKNOWN); + + mExpect.that(mLogger.windowingModeToTargetWindowingMode(WINDOWING_MODE_UNDEFINED)) + .isEqualTo(MEDIA_PROJECTION_TARGET_CHANGED__TARGET_WINDOWING_MODE__WINDOWING_MODE_UNKNOWN); + } + private void verifyStateChangedAtomIdLogged() { verify(mFrameworkStatsLogWrapper) - .write( + .writeStateChanged( /* code= */ eq(FrameworkStatsLog.MEDIA_PROJECTION_STATE_CHANGED), /* sessionId= */ anyInt(), /* state= */ anyInt(), @@ -525,7 +629,7 @@ public class MediaProjectionMetricsLoggerTest { private void verifyStateLogged(int state) { verify(mFrameworkStatsLogWrapper) - .write( + .writeStateChanged( /* code= */ anyInt(), /* sessionId= */ anyInt(), eq(state), @@ -536,9 +640,9 @@ public class MediaProjectionMetricsLoggerTest { /* creationSource= */ anyInt()); } - private void verifyHostUidLogged(int hostUid) { + private void verifyStateChangedHostUidLogged(int hostUid) { verify(mFrameworkStatsLogWrapper) - .write( + .writeStateChanged( /* code= */ anyInt(), /* sessionId= */ anyInt(), /* state= */ anyInt(), @@ -551,7 +655,7 @@ public class MediaProjectionMetricsLoggerTest { private void verifyCreationSourceLogged(int creationSource) { verify(mFrameworkStatsLogWrapper) - .write( + .writeStateChanged( /* code= */ anyInt(), /* sessionId= */ anyInt(), /* state= */ anyInt(), @@ -562,9 +666,9 @@ public class MediaProjectionMetricsLoggerTest { eq(creationSource)); } - private void verifyTargetUidLogged(int targetUid) { + private void verifyStageChangedTargetUidLogged(int targetUid) { verify(mFrameworkStatsLogWrapper) - .write( + .writeStateChanged( /* code= */ anyInt(), /* sessionId= */ anyInt(), /* state= */ anyInt(), @@ -577,7 +681,7 @@ public class MediaProjectionMetricsLoggerTest { private void verifyTimeSinceLastActiveSessionLogged(int timeSinceLastActiveSession) { verify(mFrameworkStatsLogWrapper) - .write( + .writeStateChanged( /* code= */ anyInt(), /* sessionId= */ anyInt(), /* state= */ anyInt(), @@ -590,7 +694,7 @@ public class MediaProjectionMetricsLoggerTest { private void verifySessionIdLogged(int newSessionId) { verify(mFrameworkStatsLogWrapper) - .write( + .writeStateChanged( /* code= */ anyInt(), /* sessionId= */ eq(newSessionId), /* state= */ anyInt(), @@ -603,7 +707,7 @@ public class MediaProjectionMetricsLoggerTest { private void verifyPreviousStateLogged(int previousState) { verify(mFrameworkStatsLogWrapper) - .write( + .writeStateChanged( /* code= */ anyInt(), /* sessionId= */ anyInt(), /* state= */ anyInt(), @@ -613,4 +717,59 @@ public class MediaProjectionMetricsLoggerTest { /* timeSinceLastActive= */ anyInt(), /* creationSource= */ anyInt()); } + + private void verifyTargetChangedAtomIdLogged() { + verify(mFrameworkStatsLogWrapper) + .writeTargetChanged( + eq(FrameworkStatsLog.MEDIA_PROJECTION_TARGET_CHANGED), + /* sessionId= */ anyInt(), + /* targetType= */ anyInt(), + /* hostUid= */ anyInt(), + /* targetUid= */ anyInt(), + /* targetWindowingMode= */ anyInt()); + } + + private void verifyTargetTypeLogged(int targetType) { + verify(mFrameworkStatsLogWrapper) + .writeTargetChanged( + /* code= */ anyInt(), + /* sessionId= */ anyInt(), + eq(targetType), + /* hostUid= */ anyInt(), + /* targetUid= */ anyInt(), + /* targetWindowingMode= */ anyInt()); + } + + private void verifyTargetChangedHostUidLogged(int hostUid) { + verify(mFrameworkStatsLogWrapper) + .writeTargetChanged( + /* code= */ anyInt(), + /* sessionId= */ anyInt(), + /* targetType= */ anyInt(), + eq(hostUid), + /* targetUid= */ anyInt(), + /* targetWindowingMode= */ anyInt()); + } + + private void verifyTargetChangedTargetUidLogged(int targetUid) { + verify(mFrameworkStatsLogWrapper) + .writeTargetChanged( + /* code= */ anyInt(), + /* sessionId= */ anyInt(), + /* targetType= */ anyInt(), + /* hostUid= */ anyInt(), + eq(targetUid), + /* targetWindowingMode= */ anyInt()); + } + + private void verifyWindowingModeLogged(int targetWindowingMode) { + verify(mFrameworkStatsLogWrapper) + .writeTargetChanged( + /* code= */ anyInt(), + /* sessionId= */ anyInt(), + /* targetType= */ anyInt(), + /* hostUid= */ anyInt(), + /* targetUid= */ anyInt(), + eq(targetWindowingMode)); + } } diff --git a/services/tests/servicestests/src/com/android/server/pm/SuspendPackagesTest.java b/services/tests/servicestests/src/com/android/server/pm/SuspendPackagesTest.java index 398148ff4d3b..01a91c1db1e6 100644 --- a/services/tests/servicestests/src/com/android/server/pm/SuspendPackagesTest.java +++ b/services/tests/servicestests/src/com/android/server/pm/SuspendPackagesTest.java @@ -30,6 +30,7 @@ import static org.junit.Assert.assertTrue; import static org.junit.Assert.fail; import android.app.AppGlobals; +import android.content.AttributionSource; import android.content.Context; import android.content.pm.IPackageManager; import android.content.pm.LauncherApps; @@ -281,12 +282,16 @@ public class SuspendPackagesTest { }; iAppOps.startWatchingMode(code, TEST_APP_PACKAGE_NAME, watcher); final int testPackageUid = mPackageManager.getPackageUid(TEST_APP_PACKAGE_NAME, 0); - int opMode = iAppOps.checkOperation(code, testPackageUid, TEST_APP_PACKAGE_NAME); + AttributionSource attributionSource = + new AttributionSource.Builder(testPackageUid) + .setPackageName(TEST_APP_PACKAGE_NAME) + .build(); + int opMode = iAppOps.checkOperationWithState(code, attributionSource.asState()); assertEquals("Op " + opToName(code) + " disallowed for unsuspended package", MODE_ALLOWED, opMode); suspendTestPackage(null, null, null); assertTrue("AppOpsWatcher did not callback", latch.await(5, TimeUnit.SECONDS)); - opMode = iAppOps.checkOperation(code, testPackageUid, TEST_APP_PACKAGE_NAME); + opMode = iAppOps.checkOperationWithState(code, attributionSource.asState()); assertEquals("Op " + opToName(code) + " allowed for suspended package", MODE_IGNORED, opMode); iAppOps.stopWatchingMode(watcher); diff --git a/services/tests/wmtests/src/com/android/server/wm/ContentRecorderTests.java b/services/tests/wmtests/src/com/android/server/wm/ContentRecorderTests.java index 78566fb06179..887e5ee0c58a 100644 --- a/services/tests/wmtests/src/com/android/server/wm/ContentRecorderTests.java +++ b/services/tests/wmtests/src/com/android/server/wm/ContentRecorderTests.java @@ -42,6 +42,7 @@ import static org.mockito.Mockito.atLeast; import static org.mockito.Mockito.atLeastOnce; import static org.mockito.Mockito.clearInvocations; import static org.mockito.Mockito.never; +import static org.mockito.Mockito.times; import android.app.WindowConfiguration; import android.content.pm.ActivityInfo; @@ -232,7 +233,7 @@ public class ContentRecorderTests extends WindowTestsBase { @Test public void testOnConfigurationChanged_neverRecording() { defaultInit(); - mContentRecorder.onConfigurationChanged(ORIENTATION_PORTRAIT); + mContentRecorder.onConfigurationChanged(ORIENTATION_PORTRAIT, WINDOWING_MODE_FULLSCREEN); verify(mTransaction, never()).setPosition(eq(mRecordedSurface), anyFloat(), anyFloat()); verify(mTransaction, never()).setMatrix(eq(mRecordedSurface), anyFloat(), anyFloat(), @@ -248,7 +249,7 @@ public class ContentRecorderTests extends WindowTestsBase { @Configuration.Orientation final int lastOrientation = mDisplayContent.getConfiguration().orientation == ORIENTATION_PORTRAIT ? ORIENTATION_LANDSCAPE : ORIENTATION_PORTRAIT; - mContentRecorder.onConfigurationChanged(lastOrientation); + mContentRecorder.onConfigurationChanged(lastOrientation, WINDOWING_MODE_FULLSCREEN); verify(mTransaction, atLeast(2)).setPosition(eq(mRecordedSurface), anyFloat(), anyFloat()); @@ -266,7 +267,8 @@ public class ContentRecorderTests extends WindowTestsBase { // The user rotates the device, so the host app resizes the virtual display for the capture. resizeDisplay(mDisplayContent, newWidth, mSurfaceSize.y); resizeDisplay(mVirtualDisplayContent, newWidth, mSurfaceSize.y); - mContentRecorder.onConfigurationChanged(mDisplayContent.getConfiguration().orientation); + mContentRecorder.onConfigurationChanged( + mDisplayContent.getConfiguration().orientation, WINDOWING_MODE_FULLSCREEN); verify(mTransaction, atLeast(2)).setPosition(eq(mRecordedSurface), anyFloat(), anyFloat()); @@ -283,7 +285,7 @@ public class ContentRecorderTests extends WindowTestsBase { // Change a value that we shouldn't rely upon; it has the wrong type. mVirtualDisplayContent.setOverrideOrientation(SCREEN_ORIENTATION_FULL_SENSOR); mContentRecorder.onConfigurationChanged( - mVirtualDisplayContent.getConfiguration().orientation); + mVirtualDisplayContent.getConfiguration().orientation, WINDOWING_MODE_FULLSCREEN); // No resize is issued, only the initial transformations when we started recording. verify(mTransaction).setPosition(eq(mRecordedSurface), anyFloat(), @@ -307,7 +309,7 @@ public class ContentRecorderTests extends WindowTestsBase { doReturn(newSurfaceSize).when(mWm.mDisplayManagerInternal).getDisplaySurfaceDefaultSize( anyInt()); mContentRecorder.onConfigurationChanged( - mVirtualDisplayContent.getConfiguration().orientation); + mVirtualDisplayContent.getConfiguration().orientation, WINDOWING_MODE_FULLSCREEN); // No resize is issued, only the initial transformations when we started recording. verify(mTransaction, atLeast(2)).setPosition(eq(mRecordedSurface), anyFloat(), @@ -379,6 +381,55 @@ public class ContentRecorderTests extends WindowTestsBase { } @Test + public void testTaskWindowingModeChanged_changeWindowMode_notifyWindowModeChanged() { + defaultInit(); + // WHEN a recording is ongoing. + mTask.setWindowingMode(WINDOWING_MODE_FULLSCREEN); + mContentRecorder.setContentRecordingSession(mTaskSession); + mContentRecorder.updateRecording(); + assertThat(mContentRecorder.isCurrentlyRecording()).isTrue(); + + // THEN the windowing mode change callback is notified. + verify(mMediaProjectionManagerWrapper) + .notifyWindowingModeChanged(mTaskSession.getContentToRecord(), + mTaskSession.getTargetUid(), WINDOWING_MODE_FULLSCREEN); + + // WHEN a configuration change arrives, and the task is now multi-window mode. + mTask.setWindowingMode(WINDOWING_MODE_MULTI_WINDOW); + Configuration configuration = mTask.getConfiguration(); + mTask.onConfigurationChanged(configuration); + + // THEN windowing mode change callback is notified again. + verify(mMediaProjectionManagerWrapper) + .notifyWindowingModeChanged(mTaskSession.getContentToRecord(), + mTaskSession.getTargetUid(), WINDOWING_MODE_MULTI_WINDOW); + } + + @Test + public void testTaskWindowingModeChanged_sameWindowMode_notifyWindowModeChanged() { + defaultInit(); + // WHEN a recording is ongoing. + mTask.setWindowingMode(WINDOWING_MODE_FULLSCREEN); + mContentRecorder.setContentRecordingSession(mTaskSession); + mContentRecorder.updateRecording(); + assertThat(mContentRecorder.isCurrentlyRecording()).isTrue(); + + // THEN the windowing mode change callback is notified. + verify(mMediaProjectionManagerWrapper) + .notifyWindowingModeChanged(mTaskSession.getContentToRecord(), + mTaskSession.getTargetUid(), WINDOWING_MODE_FULLSCREEN); + + // WHEN a configuration change arrives, and the task is STILL fullscreen. + mTask.setWindowingMode(WINDOWING_MODE_FULLSCREEN); + Configuration configuration = mTask.getConfiguration(); + mTask.onConfigurationChanged(configuration); + + // THEN the windowing mode change callback is NOT called notified again. + verify(mMediaProjectionManagerWrapper, times(1)) + .notifyWindowingModeChanged(anyInt(), anyInt(), anyInt()); + } + + @Test public void testTaskWindowingModeChanged_pip_stopsRecording() { defaultInit(); // WHEN a recording is ongoing. @@ -421,9 +472,12 @@ public class ContentRecorderTests extends WindowTestsBase { mContentRecorder.updateRecording(); assertThat(mContentRecorder.isCurrentlyRecording()).isTrue(); - // THEN the visibility change callback is notified. + // THEN the visibility change & windowing mode change callbacks are notified. verify(mMediaProjectionManagerWrapper) .notifyActiveProjectionCapturedContentVisibilityChanged(true); + verify(mMediaProjectionManagerWrapper) + .notifyWindowingModeChanged(mTaskSession.getContentToRecord(), + mTaskSession.getTargetUid(), mRootWindowContainer.getWindowingMode()); } @Test @@ -434,9 +488,12 @@ public class ContentRecorderTests extends WindowTestsBase { mContentRecorder.updateRecording(); assertThat(mContentRecorder.isCurrentlyRecording()).isTrue(); - // THEN the visibility change callback is notified. + // THEN the visibility change & windowing mode change callbacks are notified. verify(mMediaProjectionManagerWrapper) .notifyActiveProjectionCapturedContentVisibilityChanged(true); + verify(mMediaProjectionManagerWrapper) + .notifyWindowingModeChanged(mDisplaySession.getContentToRecord(), + mDisplaySession.getTargetUid(), mRootWindowContainer.getWindowingMode()); } @Test diff --git a/services/tests/wmtests/src/com/android/server/wm/InputMethodDialogWindowContextTest.java b/services/tests/wmtests/src/com/android/server/wm/InputMethodDialogWindowContextTest.java index 41659113b1b2..da3a02ac525a 100644 --- a/services/tests/wmtests/src/com/android/server/wm/InputMethodDialogWindowContextTest.java +++ b/services/tests/wmtests/src/com/android/server/wm/InputMethodDialogWindowContextTest.java @@ -160,6 +160,9 @@ public class InputMethodDialogWindowContextTest extends WindowTestsBase { final DisplayAreaGroup firstDaGroup = mSecondaryDisplay.mFirstRoot; maxBoundsVerifier.setMaxBounds(firstDaGroup.getMaxBounds()); + // Clear the previous invocation histories in case we may count the previous + // onConfigurationChanged invocation into the next verification. + clearInvocations(tokenClient, imeContainer); firstDaGroup.placeImeContainer(imeContainer); verify(imeContainer, timeout(WAIT_TIMEOUT_MS)).onConfigurationChanged( 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/IBooleanConsumer.aidl b/telephony/java/android/telephony/IBooleanConsumer.aidl new file mode 100644 index 000000000000..69f7c9e6e065 --- /dev/null +++ b/telephony/java/android/telephony/IBooleanConsumer.aidl @@ -0,0 +1,25 @@ +/* + * Copyright (C) 2023 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package android.telephony; + +/** + * Consumer pattern for an operation that requires a boolean result from another process to finish. + * @hide + */ +oneway interface IBooleanConsumer { + void accept(boolean result); +}
\ No newline at end of file diff --git a/telephony/java/android/telephony/IIntegerConsumer.aidl b/telephony/java/android/telephony/IIntegerConsumer.aidl new file mode 100644 index 000000000000..3e84c327734f --- /dev/null +++ b/telephony/java/android/telephony/IIntegerConsumer.aidl @@ -0,0 +1,25 @@ +/* + * Copyright (C) 2023 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package android.telephony; + +/** + * Consumer pattern for an operation that requires an integer result from another process to finish. + * @hide + */ +oneway interface IIntegerConsumer { + void accept(int result); +}
\ No newline at end of file diff --git a/telephony/java/android/telephony/SubscriptionManager.java b/telephony/java/android/telephony/SubscriptionManager.java index 8e90fe7ea975..f8608b8fead2 100644 --- a/telephony/java/android/telephony/SubscriptionManager.java +++ b/telephony/java/android/telephony/SubscriptionManager.java @@ -265,8 +265,8 @@ public class SubscriptionManager { } } - private static VoidPropertyInvalidatedCache<Integer> sGetDefaultSubIdCache = - new VoidPropertyInvalidatedCache<>(ISub::getDefaultSubId, + private static IntegerPropertyInvalidatedCache<Integer> sGetDefaultSubIdCacheAsUser = + new IntegerPropertyInvalidatedCache<>(ISub::getDefaultSubIdAsUser, CACHE_KEY_SUBSCRIPTION_MANAGER_SERVICE_PROPERTY, INVALID_SUBSCRIPTION_ID); @@ -275,8 +275,8 @@ public class SubscriptionManager { CACHE_KEY_SUBSCRIPTION_MANAGER_SERVICE_PROPERTY, INVALID_SUBSCRIPTION_ID); - private static VoidPropertyInvalidatedCache<Integer> sGetDefaultSmsSubIdCache = - new VoidPropertyInvalidatedCache<>(ISub::getDefaultSmsSubId, + private static IntegerPropertyInvalidatedCache<Integer> sGetDefaultSmsSubIdCacheAsUser = + new IntegerPropertyInvalidatedCache<>(ISub::getDefaultSmsSubIdAsUser, CACHE_KEY_SUBSCRIPTION_MANAGER_SERVICE_PROPERTY, INVALID_SUBSCRIPTION_ID); @@ -2309,7 +2309,7 @@ public class SubscriptionManager { * @return the "system" default subscription id. */ public static int getDefaultSubscriptionId() { - return sGetDefaultSubIdCache.query(null); + return sGetDefaultSubIdCacheAsUser.query(Process.myUserHandle().getIdentifier()); } /** @@ -2325,7 +2325,7 @@ public class SubscriptionManager { try { ISub iSub = TelephonyManager.getSubscriptionService(); if (iSub != null) { - subId = iSub.getDefaultVoiceSubId(); + subId = iSub.getDefaultVoiceSubIdAsUser(Process.myUserHandle().getIdentifier()); } } catch (RemoteException ex) { // ignore it @@ -2397,7 +2397,7 @@ public class SubscriptionManager { * @return the default SMS subscription Id. */ public static int getDefaultSmsSubscriptionId() { - return sGetDefaultSmsSubIdCache.query(null); + return sGetDefaultSmsSubIdCacheAsUser.query(Process.myUserHandle().getIdentifier()); } /** @@ -3927,10 +3927,10 @@ public class SubscriptionManager { * @hide */ public static void disableCaching() { - sGetDefaultSubIdCache.disableLocal(); + sGetDefaultSubIdCacheAsUser.disableLocal(); sGetDefaultDataSubIdCache.disableLocal(); sGetActiveDataSubscriptionIdCache.disableLocal(); - sGetDefaultSmsSubIdCache.disableLocal(); + sGetDefaultSmsSubIdCacheAsUser.disableLocal(); sGetSlotIndexCache.disableLocal(); sGetSubIdCache.disableLocal(); sGetPhoneIdCache.disableLocal(); @@ -3941,10 +3941,10 @@ public class SubscriptionManager { * * @hide */ public static void clearCaches() { - sGetDefaultSubIdCache.clear(); + sGetDefaultSubIdCacheAsUser.clear(); sGetDefaultDataSubIdCache.clear(); sGetActiveDataSubscriptionIdCache.clear(); - sGetDefaultSmsSubIdCache.clear(); + sGetDefaultSmsSubIdCacheAsUser.clear(); sGetSlotIndexCache.clear(); sGetSubIdCache.clear(); sGetPhoneIdCache.clear(); 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/satellite/stub/ISatellite.aidl b/telephony/java/android/telephony/satellite/stub/ISatellite.aidl index e2cd4f8da2c4..711be02761fe 100644 --- a/telephony/java/android/telephony/satellite/stub/ISatellite.aidl +++ b/telephony/java/android/telephony/satellite/stub/ISatellite.aidl @@ -16,14 +16,14 @@ package android.telephony.satellite.stub; +import android.telephony.IBooleanConsumer; +import android.telephony.IIntegerConsumer; + import android.telephony.satellite.stub.INtnSignalStrengthConsumer; import android.telephony.satellite.stub.ISatelliteCapabilitiesConsumer; import android.telephony.satellite.stub.ISatelliteListener; import android.telephony.satellite.stub.SatelliteDatagram; -import com.android.internal.telephony.IBooleanConsumer; -import com.android.internal.telephony.IIntegerConsumer; - /** * {@hide} */ diff --git a/telephony/java/android/telephony/satellite/stub/SatelliteImplBase.java b/telephony/java/android/telephony/satellite/stub/SatelliteImplBase.java index a636a6128e61..c0d0830e6105 100644 --- a/telephony/java/android/telephony/satellite/stub/SatelliteImplBase.java +++ b/telephony/java/android/telephony/satellite/stub/SatelliteImplBase.java @@ -19,10 +19,10 @@ package android.telephony.satellite.stub; import android.annotation.NonNull; import android.os.IBinder; import android.os.RemoteException; +import android.telephony.IBooleanConsumer; +import android.telephony.IIntegerConsumer; import android.util.Log; -import com.android.internal.telephony.IBooleanConsumer; -import com.android.internal.telephony.IIntegerConsumer; import com.android.internal.telephony.util.TelephonyUtils; import java.util.List; diff --git a/telephony/java/com/android/internal/telephony/ISub.aidl b/telephony/java/com/android/internal/telephony/ISub.aidl index a5a23e8659d8..d2dbeb7aff74 100644 --- a/telephony/java/com/android/internal/telephony/ISub.aidl +++ b/telephony/java/com/android/internal/telephony/ISub.aidl @@ -239,6 +239,7 @@ interface ISub { int getSubId(int slotIndex); int getDefaultSubId(); + int getDefaultSubIdAsUser(int userId); int getPhoneId(int subId); @@ -251,10 +252,12 @@ interface ISub { void setDefaultDataSubId(int subId); int getDefaultVoiceSubId(); + int getDefaultVoiceSubIdAsUser(int userId); void setDefaultVoiceSubId(int subId); int getDefaultSmsSubId(); + int getDefaultSmsSubIdAsUser(int userId); void setDefaultSmsSubId(int subId); 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/activityembedding/open/OpenActivityEmbeddingPlaceholderSplitTest.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/activityembedding/open/OpenActivityEmbeddingPlaceholderSplitTest.kt index 48edf6ddeba6..59ff0c65c4fc 100644 --- a/tests/FlickerTests/src/com/android/server/wm/flicker/activityembedding/open/OpenActivityEmbeddingPlaceholderSplitTest.kt +++ b/tests/FlickerTests/src/com/android/server/wm/flicker/activityembedding/open/OpenActivityEmbeddingPlaceholderSplitTest.kt @@ -88,14 +88,20 @@ class OpenActivityEmbeddingPlaceholderSplitTest(flicker: LegacyFlickerTest) : flicker.assertWm { notContains(ActivityEmbeddingAppHelper.PLACEHOLDER_PRIMARY_COMPONENT) .then() - .isAppWindowInvisible(ActivityEmbeddingAppHelper.PLACEHOLDER_PRIMARY_COMPONENT) + .isAppWindowInvisible( + ActivityEmbeddingAppHelper.PLACEHOLDER_PRIMARY_COMPONENT, + isOptional = true + ) .then() .isAppWindowVisible(ActivityEmbeddingAppHelper.PLACEHOLDER_PRIMARY_COMPONENT) } flicker.assertWm { notContains(ActivityEmbeddingAppHelper.PLACEHOLDER_SECONDARY_COMPONENT) .then() - .isAppWindowInvisible(ActivityEmbeddingAppHelper.PLACEHOLDER_SECONDARY_COMPONENT) + .isAppWindowInvisible( + ActivityEmbeddingAppHelper.PLACEHOLDER_SECONDARY_COMPONENT, + isOptional = true + ) .then() .isAppWindowVisible(ActivityEmbeddingAppHelper.PLACEHOLDER_SECONDARY_COMPONENT) } 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) |