diff options
92 files changed, 1306 insertions, 621 deletions
diff --git a/core/api/current.txt b/core/api/current.txt index 3335375238c9..832a68fd1e8f 100644 --- a/core/api/current.txt +++ b/core/api/current.txt @@ -39990,8 +39990,10 @@ package android.security.keystore { method @NonNull public java.util.List<java.security.cert.X509Certificate> getGrantedCertificateChainFromId(long) throws android.security.keystore.KeyPermanentlyInvalidatedException, java.security.UnrecoverableKeyException; method @NonNull public java.security.Key getGrantedKeyFromId(long) throws android.security.keystore.KeyPermanentlyInvalidatedException, java.security.UnrecoverableKeyException; method @NonNull public java.security.KeyPair getGrantedKeyPairFromId(long) throws android.security.keystore.KeyPermanentlyInvalidatedException, java.security.UnrecoverableKeyException; + method @FlaggedApi("android.security.keystore2.attest_modules") @NonNull public byte[] getSupplementaryAttestationInfo(int) throws android.security.KeyStoreException; method public long grantKeyAccess(@NonNull String, int) throws android.security.KeyStoreException, java.security.UnrecoverableKeyException; method public void revokeKeyAccess(@NonNull String, int) throws android.security.KeyStoreException, java.security.UnrecoverableKeyException; + field public static final int MODULE_HASH = -1879047468; // 0x900002d4 } public class SecureKeyImportUnavailableException extends java.security.ProviderException { diff --git a/core/api/module-lib-current.txt b/core/api/module-lib-current.txt index 340d9cba1eac..6446f07937d4 100644 --- a/core/api/module-lib-current.txt +++ b/core/api/module-lib-current.txt @@ -483,6 +483,10 @@ package android.os { field public static final long TRACE_TAG_NETWORK = 2097152L; // 0x200000L } + public class UpdateEngine { + method @FlaggedApi("android.os.update_engine_api") public void triggerPostinstall(@NonNull String); + } + } package android.os.storage { diff --git a/core/java/android/app/SystemServiceRegistry.java b/core/java/android/app/SystemServiceRegistry.java index 8f84ee879b1a..79dd22fb3df5 100644 --- a/core/java/android/app/SystemServiceRegistry.java +++ b/core/java/android/app/SystemServiceRegistry.java @@ -78,8 +78,6 @@ import android.content.ContentCaptureOptions; import android.content.Context; import android.content.IRestrictionsManager; import android.content.RestrictionsManager; -import android.content.integrity.AppIntegrityManager; -import android.content.integrity.IAppIntegrityManager; import android.content.om.IOverlayManager; import android.content.om.OverlayManager; import android.content.pm.ApplicationInfo; @@ -1536,16 +1534,6 @@ public final class SystemServiceRegistry { return new AttestationVerificationManager(ctx.getOuterContext(), IAttestationVerificationManagerService.Stub.asInterface(b)); }}); - - //CHECKSTYLE:ON IndentationCheck - registerService(Context.APP_INTEGRITY_SERVICE, AppIntegrityManager.class, - new CachedServiceFetcher<AppIntegrityManager>() { - @Override - public AppIntegrityManager createService(ContextImpl ctx) - throws ServiceNotFoundException { - IBinder b = ServiceManager.getServiceOrThrow(Context.APP_INTEGRITY_SERVICE); - return new AppIntegrityManager(IAppIntegrityManager.Stub.asInterface(b)); - }}); registerService(Context.APP_HIBERNATION_SERVICE, AppHibernationManager.class, new CachedServiceFetcher<AppHibernationManager>() { @Override diff --git a/core/java/android/hardware/display/DisplayManager.java b/core/java/android/hardware/display/DisplayManager.java index 97f6899ff141..b0ea92d140a5 100644 --- a/core/java/android/hardware/display/DisplayManager.java +++ b/core/java/android/hardware/display/DisplayManager.java @@ -18,6 +18,7 @@ package android.hardware.display; import static android.view.Display.DEFAULT_DISPLAY; import static android.view.Display.HdrCapabilities.HdrType; +import static android.view.Display.INVALID_DISPLAY; import android.Manifest; import android.annotation.FlaggedApi; @@ -47,6 +48,7 @@ import android.os.Looper; import android.os.Process; import android.os.RemoteException; import android.os.ServiceManager; +import android.os.UserManager; import android.util.Log; import android.util.Pair; import android.util.Slog; @@ -96,6 +98,8 @@ public final class DisplayManager { @GuardedBy("mLock") private final WeakDisplayCache mDisplayCache = new WeakDisplayCache(); + private int mDisplayIdToMirror = INVALID_DISPLAY; + /** * Broadcast receiver that indicates when the Wifi display status changes. * <p> @@ -1086,6 +1090,7 @@ public final class DisplayManager { if (surface != null) { builder.setSurface(surface); } + builder.setDisplayIdToMirror(getDisplayIdToMirror()); return createVirtualDisplay(builder.build(), handler, callback); } @@ -1163,6 +1168,7 @@ public final class DisplayManager { if (surface != null) { builder.setSurface(surface); } + builder.setDisplayIdToMirror(getDisplayIdToMirror()); return createVirtualDisplay(projection, builder.build(), callback, handler); } @@ -1708,6 +1714,16 @@ public final class DisplayManager { return mGlobal.getDefaultDozeBrightness(displayId); } + private int getDisplayIdToMirror() { + if (mDisplayIdToMirror == INVALID_DISPLAY) { + final UserManager userManager = mContext.getSystemService(UserManager.class); + mDisplayIdToMirror = userManager.isVisibleBackgroundUsersSupported() + ? userManager.getMainDisplayIdAssignedToUser() + : DEFAULT_DISPLAY; + } + return mDisplayIdToMirror; + } + /** * Listens for changes in available display devices. */ diff --git a/core/java/android/net/metrics/DnsEvent.java b/core/java/android/net/metrics/DnsEvent.java index bf351ce07fe8..f53d1c4d191d 100644 --- a/core/java/android/net/metrics/DnsEvent.java +++ b/core/java/android/net/metrics/DnsEvent.java @@ -62,7 +62,11 @@ final public class DnsEvent { return isSuccess; } if (eventCount == eventTypes.length) { - resize((int) (1.4 * eventCount)); + int resizeLength = (int) (1.4 * eventCount); + if (eventCount == resizeLength) { + resizeLength++; + } + resize(resizeLength); } eventTypes[eventCount] = eventType; returnCodes[eventCount] = returnCode; diff --git a/core/java/android/os/OWNERS b/core/java/android/os/OWNERS index bfcc5cc6f18e..8d353384f1e2 100644 --- a/core/java/android/os/OWNERS +++ b/core/java/android/os/OWNERS @@ -118,9 +118,10 @@ per-file IpcDataCache.java = file:/PERFORMANCE_OWNERS # Memory per-file OomKillRecord.java = file:/MEMORY_OWNERS -# MessageQueue +# MessageQueue and related classes per-file MessageQueue.java = mfasheh@google.com, shayba@google.com per-file Message.java = mfasheh@google.com, shayba@google.com +per-file TestLooperManager.java = mfasheh@google.com, shayba@google.com # Stats per-file IStatsBootstrapAtomService.aidl = file:/services/core/java/com/android/server/stats/OWNERS diff --git a/core/java/android/os/SELinux.java b/core/java/android/os/SELinux.java index f64a81177ce2..11c54ef802fe 100644 --- a/core/java/android/os/SELinux.java +++ b/core/java/android/os/SELinux.java @@ -193,4 +193,31 @@ public class SELinux { return false; } } + + /** + * Gets the genfs labels version of the vendor. The genfs labels version is + * specified in {@code /vendor/etc/selinux/genfs_labels_version.txt}. The + * version follows the VINTF version format "YYYYMM" and affects how {@code + * genfs_contexts} entries are applied. + * + * <p>The genfs labels version indicates changes in the SELinux labeling + * scheme over time. For example: + * <ul> + * <li>For version 202504 and later, {@code /sys/class/udc} is labeled as + * {@code sysfs_udc}. + * <li>For version 202404 and earlier, {@code /sys/class/udc} is labeled + * as {@code sysfs}. + * </ul> + * Check {@code /system/etc/selinux/plat_sepolicy_genfs_{version}.cil} to + * see which labels are new in {version}. + * + * <p>Older vendors may override {@code genfs_contexts} with vendor-specific + * extensions. The framework must not break such labellings to maintain + * compatibility with such vendors, by checking the genfs labels version and + * implementing a fallback mechanism. + * + * @return an integer representing the genfs labels version of /vendor, in + * the format YYYYMM. + */ + public static final native int getGenfsLabelsVersion(); } diff --git a/core/java/android/os/ServiceManager.java b/core/java/android/os/ServiceManager.java index 8aec7eb59e91..9085fe09bdaa 100644 --- a/core/java/android/os/ServiceManager.java +++ b/core/java/android/os/ServiceManager.java @@ -277,7 +277,8 @@ public final class ServiceManager { if (service != null) { return service; } else { - return Binder.allowBlocking(getIServiceManager().checkService(name).getBinder()); + return Binder.allowBlocking( + getIServiceManager().checkService(name).getServiceWithMetadata().service); } } catch (RemoteException e) { Log.e(TAG, "error in checkService", e); @@ -425,7 +426,8 @@ public final class ServiceManager { private static IBinder rawGetService(String name) throws RemoteException { final long start = sStatLogger.getTime(); - final IBinder binder = getIServiceManager().getService2(name).getBinder(); + final IBinder binder = + getIServiceManager().getService2(name).getServiceWithMetadata().service; final int time = (int) sStatLogger.logDurationStat(Stats.GET_SERVICE, start); diff --git a/core/java/android/os/ServiceManagerNative.java b/core/java/android/os/ServiceManagerNative.java index 5a9c8787ee3b..49b696d95723 100644 --- a/core/java/android/os/ServiceManagerNative.java +++ b/core/java/android/os/ServiceManagerNative.java @@ -61,7 +61,7 @@ class ServiceManagerProxy implements IServiceManager { @UnsupportedAppUsage public IBinder getService(String name) throws RemoteException { // Same as checkService (old versions of servicemanager had both methods). - return checkService(name).getBinder(); + return checkService(name).getServiceWithMetadata().service; } public Service getService2(String name) throws RemoteException { diff --git a/core/java/android/os/UpdateEngine.java b/core/java/android/os/UpdateEngine.java index 0a8f62fd56d8..81e4549c78d1 100644 --- a/core/java/android/os/UpdateEngine.java +++ b/core/java/android/os/UpdateEngine.java @@ -16,6 +16,7 @@ package android.os; +import android.annotation.FlaggedApi; import android.annotation.IntDef; import android.annotation.NonNull; import android.annotation.SystemApi; @@ -667,4 +668,23 @@ public class UpdateEngine { throw e.rethrowFromSystemServer(); } } + + /** + * Run postinstall script for specified partition |partition| + * + * @param partition The partition to trigger postinstall runs + * + * @throws ServiceSpecificException error code of this exception would be one of + * https://cs.android.com/android/platform/superproject/main/+/main:system/update_engine/common/error_code.h + * @hide + */ + @FlaggedApi(Flags.FLAG_UPDATE_ENGINE_API) + @SystemApi(client = SystemApi.Client.MODULE_LIBRARIES) + public void triggerPostinstall(@NonNull String partition) { + try { + mUpdateEngine.triggerPostinstall(partition); + } catch (RemoteException e) { + throw e.rethrowFromSystemServer(); + } + } } diff --git a/core/java/android/provider/Settings.java b/core/java/android/provider/Settings.java index b8a8be159d12..ef8b3d738154 100644 --- a/core/java/android/provider/Settings.java +++ b/core/java/android/provider/Settings.java @@ -19338,14 +19338,14 @@ public final class Settings { * If hotword detection should be enabled. * @hide */ - @Readable(maxTargetSdk = Build.VERSION_CODES.UPSIDE_DOWN_CAKE) + @Readable public static final String HOTWORD_DETECTION_ENABLED = "hotword_detection_enabled"; /** * Whether Smart Replies are enabled within Wear. * @hide */ - @Readable(maxTargetSdk = Build.VERSION_CODES.UPSIDE_DOWN_CAKE) + @Readable public static final String SMART_REPLIES_ENABLED = "smart_replies_enabled"; /** @@ -19359,7 +19359,7 @@ public final class Settings { * If FLP should obtain location data from the paired device. * @hide */ - @Readable(maxTargetSdk = Build.VERSION_CODES.UPSIDE_DOWN_CAKE) + @Readable public static final String OBTAIN_PAIRED_DEVICE_LOCATION = "obtain_paired_device_location"; @@ -19367,7 +19367,7 @@ public final class Settings { * The play store availability on companion phone. * @hide */ - @Readable(maxTargetSdk = Build.VERSION_CODES.UPSIDE_DOWN_CAKE) + @Readable public static final String PHONE_PLAY_STORE_AVAILABILITY = "phone_play_store_availability"; @@ -19383,7 +19383,7 @@ public final class Settings { * Whether the bug report is enabled. * @hide */ - @Readable(maxTargetSdk = Build.VERSION_CODES.UPSIDE_DOWN_CAKE) + @Readable public static final String BUG_REPORT = "bug_report"; // Possible bug report states @@ -19396,14 +19396,14 @@ public final class Settings { * The enabled/disabled state of the SmartIlluminate. * @hide */ - @Readable(maxTargetSdk = Build.VERSION_CODES.UPSIDE_DOWN_CAKE) + @Readable public static final String SMART_ILLUMINATE_ENABLED = "smart_illuminate_enabled"; /** * Whether automatic time is enabled on the watch. * @hide */ - @Readable(maxTargetSdk = Build.VERSION_CODES.UPSIDE_DOWN_CAKE) + @Readable public static final String CLOCKWORK_AUTO_TIME = "clockwork_auto_time"; // Possible clockwork auto time states @@ -19421,7 +19421,7 @@ public final class Settings { * Whether automatic time zone is enabled on the watch. * @hide */ - @Readable(maxTargetSdk = Build.VERSION_CODES.UPSIDE_DOWN_CAKE) + @Readable public static final String CLOCKWORK_AUTO_TIME_ZONE = "clockwork_auto_time_zone"; // Possible clockwork auto time zone states @@ -19438,14 +19438,14 @@ public final class Settings { * Whether 24 hour time format is enabled on the watch. * @hide */ - @Readable(maxTargetSdk = Build.VERSION_CODES.UPSIDE_DOWN_CAKE) + @Readable public static final String CLOCKWORK_24HR_TIME = "clockwork_24hr_time"; /** * Whether the auto wifi toggle setting is enabled. * @hide */ - @Readable(maxTargetSdk = Build.VERSION_CODES.UPSIDE_DOWN_CAKE) + @Readable public static final String AUTO_WIFI = "auto_wifi"; // Possible force wifi on states @@ -19465,7 +19465,7 @@ public final class Settings { * wifi requirement until this time). The time is in millis since epoch. * @hide */ - @Readable(maxTargetSdk = Build.VERSION_CODES.UPSIDE_DOWN_CAKE) + @Readable public static final String ALT_BYPASS_WIFI_REQUIREMENT_TIME_MILLIS = "alt_bypass_wifi_requirement_time_millis"; @@ -19473,7 +19473,7 @@ public final class Settings { * Whether the setup was skipped. * @hide */ - @Readable(maxTargetSdk = Build.VERSION_CODES.UPSIDE_DOWN_CAKE) + @Readable public static final String SETUP_SKIPPED = "setup_skipped"; // Possible setup_skipped states @@ -19488,7 +19488,7 @@ public final class Settings { * The last requested call forwarding action. * @hide */ - @Readable(maxTargetSdk = Build.VERSION_CODES.UPSIDE_DOWN_CAKE) + @Readable public static final String LAST_CALL_FORWARD_ACTION = "last_call_forward_action"; // Possible call forwarding actions @@ -19501,31 +19501,31 @@ public final class Settings { // Stem button settings. /** @hide */ - @Readable(maxTargetSdk = Build.VERSION_CODES.UPSIDE_DOWN_CAKE) + @Readable public static final String STEM_1_TYPE = "STEM_1_TYPE"; /** @hide */ - @Readable(maxTargetSdk = Build.VERSION_CODES.UPSIDE_DOWN_CAKE) + @Readable public static final String STEM_1_DATA = "STEM_1_DATA"; /** @hide */ - @Readable(maxTargetSdk = Build.VERSION_CODES.UPSIDE_DOWN_CAKE) + @Readable public static final String STEM_1_DEFAULT_DATA = "STEM_1_DEFAULT_DATA"; /** @hide */ - @Readable(maxTargetSdk = Build.VERSION_CODES.UPSIDE_DOWN_CAKE) + @Readable public static final String STEM_2_TYPE = "STEM_2_TYPE"; /** @hide */ - @Readable(maxTargetSdk = Build.VERSION_CODES.UPSIDE_DOWN_CAKE) + @Readable public static final String STEM_2_DATA = "STEM_2_DATA"; /** @hide */ - @Readable(maxTargetSdk = Build.VERSION_CODES.UPSIDE_DOWN_CAKE) + @Readable public static final String STEM_2_DEFAULT_DATA = "STEM_2_DEFAULT_DATA"; /** @hide */ - @Readable(maxTargetSdk = Build.VERSION_CODES.UPSIDE_DOWN_CAKE) + @Readable public static final String STEM_3_TYPE = "STEM_3_TYPE"; /** @hide */ - @Readable(maxTargetSdk = Build.VERSION_CODES.UPSIDE_DOWN_CAKE) + @Readable public static final String STEM_3_DATA = "STEM_3_DATA"; /** @hide */ - @Readable(maxTargetSdk = Build.VERSION_CODES.UPSIDE_DOWN_CAKE) + @Readable public static final String STEM_3_DEFAULT_DATA = "STEM_3_DEFAULT_DATA"; // Stem types @@ -19540,14 +19540,14 @@ public final class Settings { * If the device should be muted when off body. * @hide */ - @Readable(maxTargetSdk = Build.VERSION_CODES.UPSIDE_DOWN_CAKE) + @Readable public static final String MUTE_WHEN_OFF_BODY_ENABLED = "obtain_mute_when_off_body"; /** * Wear OS version string. * @hide */ - @Readable(maxTargetSdk = Build.VERSION_CODES.UPSIDE_DOWN_CAKE) + @Readable public static final String WEAR_OS_VERSION_STRING = "wear_os_version_string"; /** @@ -19560,28 +19560,28 @@ public final class Settings { * The android wear system version. * @hide */ - @Readable(maxTargetSdk = Build.VERSION_CODES.UPSIDE_DOWN_CAKE) + @Readable public static final String ANDROID_WEAR_VERSION = "android_wear_version"; /** * The wear system capabiltiies. * @hide */ - @Readable(maxTargetSdk = Build.VERSION_CODES.UPSIDE_DOWN_CAKE) + @Readable public static final String SYSTEM_CAPABILITIES = "system_capabilities"; /** * The android wear system edition. * @hide */ - @Readable(maxTargetSdk = Build.VERSION_CODES.UPSIDE_DOWN_CAKE) + @Readable public static final String SYSTEM_EDITION = "android_wear_system_edition"; /** * The Wear platform MR number. * @hide */ - @Readable(maxTargetSdk = Build.VERSION_CODES.UPSIDE_DOWN_CAKE) + @Readable public static final String WEAR_PLATFORM_MR_NUMBER = "wear_platform_mr_number"; /** @@ -19595,42 +19595,42 @@ public final class Settings { * Whether ambient is currently enabled. * @hide */ - @Readable(maxTargetSdk = Build.VERSION_CODES.UPSIDE_DOWN_CAKE) + @Readable public static final String AMBIENT_ENABLED = "ambient_enabled"; /** * Whether ambient tilt to wake is enabled. * @hide */ - @Readable(maxTargetSdk = Build.VERSION_CODES.UPSIDE_DOWN_CAKE) + @Readable public static final String AMBIENT_TILT_TO_WAKE = "ambient_tilt_to_wake"; /** * Whether ambient low bit mode is enabled by developer options. * @hide */ - @Readable(maxTargetSdk = Build.VERSION_CODES.UPSIDE_DOWN_CAKE) + @Readable public static final String AMBIENT_LOW_BIT_ENABLED_DEV = "ambient_low_bit_enabled_dev"; /** * Whether ambient touch to wake is enabled. * @hide */ - @Readable(maxTargetSdk = Build.VERSION_CODES.UPSIDE_DOWN_CAKE) + @Readable public static final String AMBIENT_TOUCH_TO_WAKE = "ambient_touch_to_wake"; /** * Whether ambient tilt to bright is enabled. * @hide */ - @Readable(maxTargetSdk = Build.VERSION_CODES.UPSIDE_DOWN_CAKE) + @Readable public static final String AMBIENT_TILT_TO_BRIGHT = "ambient_tilt_to_bright"; /** * Whether touch and hold to edit WF is enabled * @hide */ - @Readable(maxTargetSdk = Build.VERSION_CODES.UPSIDE_DOWN_CAKE) + @Readable public static final String GESTURE_TOUCH_AND_HOLD_WATCH_FACE_ENABLED = "gesture_touch_and_hold_watchface_enabled"; @@ -19644,7 +19644,7 @@ public final class Settings { * Whether bedtime mode is enabled. * @hide */ - @Readable(maxTargetSdk = Build.VERSION_CODES.UPSIDE_DOWN_CAKE) + @Readable public static final String BEDTIME_MODE = "bedtime_mode"; /** @@ -19656,35 +19656,35 @@ public final class Settings { * Whether the current watchface is decomposable. * @hide */ - @Readable(maxTargetSdk = Build.VERSION_CODES.UPSIDE_DOWN_CAKE) + @Readable public static final String DECOMPOSABLE_WATCHFACE = "current_watchface_decomposable"; /** * Whether to force ambient when docked. * @hide */ - @Readable(maxTargetSdk = Build.VERSION_CODES.UPSIDE_DOWN_CAKE) + @Readable public static final String AMBIENT_FORCE_WHEN_DOCKED = "ambient_force_when_docked"; /** * Whether the ambient low bit mode is enabled. * @hide */ - @Readable(maxTargetSdk = Build.VERSION_CODES.UPSIDE_DOWN_CAKE) + @Readable public static final String AMBIENT_LOW_BIT_ENABLED = "ambient_low_bit_enabled"; /** * The timeout duration in minutes of ambient mode when plugged in. * @hide */ - @Readable(maxTargetSdk = Build.VERSION_CODES.UPSIDE_DOWN_CAKE) + @Readable public static final String AMBIENT_PLUGGED_TIMEOUT_MIN = "ambient_plugged_timeout_min"; /** * What OS does paired device has. * @hide */ - @Readable(maxTargetSdk = Build.VERSION_CODES.UPSIDE_DOWN_CAKE) + @Readable public static final String PAIRED_DEVICE_OS_TYPE = "paired_device_os_type"; // Possible values of PAIRED_DEVICE_OS_TYPE @@ -19719,7 +19719,7 @@ public final class Settings { * The user's last setting for hfp client. * @hide */ - @Readable(maxTargetSdk = Build.VERSION_CODES.UPSIDE_DOWN_CAKE) + @Readable public static final String USER_HFP_CLIENT_SETTING = "user_hfp_client_setting"; // Possible hfp client user setting values @@ -19744,7 +19744,7 @@ public final class Settings { * The companion App name. * @hide */ - @Readable(maxTargetSdk = Build.VERSION_CODES.UPSIDE_DOWN_CAKE) + @Readable public static final String COMPANION_APP_NAME = "wear_companion_app_name"; /** @@ -19752,21 +19752,21 @@ public final class Settings { * wear. 1 for supporting, 0 for not supporting. * @hide */ - @Readable(maxTargetSdk = Build.VERSION_CODES.UPSIDE_DOWN_CAKE) + @Readable public static final String ENABLE_ALL_LANGUAGES = "enable_all_languages"; /** * The Locale (as language tag) the user chose at startup. * @hide */ - @Readable(maxTargetSdk = Build.VERSION_CODES.UPSIDE_DOWN_CAKE) + @Readable public static final String SETUP_LOCALE = "setup_locale"; /** * The version of oem setup present. * @hide */ - @Readable(maxTargetSdk = Build.VERSION_CODES.UPSIDE_DOWN_CAKE) + @Readable public static final String OEM_SETUP_VERSION = "oem_setup_version"; /** @@ -19812,7 +19812,7 @@ public final class Settings { * -{@link BATTERY_SAVER_MODE_CUSTOM} * @hide */ - @Readable(maxTargetSdk = Build.VERSION_CODES.UPSIDE_DOWN_CAKE) + @Readable public static final String BATTERY_SAVER_MODE = "battery_saver_mode"; /** @@ -19869,7 +19869,7 @@ public final class Settings { * If burn in protection is enabled. * @hide */ - @Readable(maxTargetSdk = Build.VERSION_CODES.UPSIDE_DOWN_CAKE) + @Readable public static final String BURN_IN_PROTECTION_ENABLED = "burn_in_protection"; /** @@ -19888,7 +19888,7 @@ public final class Settings { * RIGHT_WRIST_ROTATION_0 = "2", RIGHT_WRIST_ROTATION_180 = "3" * @hide */ - @Readable(maxTargetSdk = Build.VERSION_CODES.UPSIDE_DOWN_CAKE) + @Readable public static final String WRIST_ORIENTATION_MODE = "wear_wrist_orientation_mode"; /** @@ -19927,7 +19927,7 @@ public final class Settings { * * @hide */ - @Readable(maxTargetSdk = Build.VERSION_CODES.UPSIDE_DOWN_CAKE) + @Readable public static final String CLOCKWORK_SYSUI_PACKAGE = "clockwork_sysui_package"; /** @@ -19957,7 +19957,7 @@ public final class Settings { * Whether the device has Wet Mode/ Touch Lock Mode enabled. * @hide */ - @Readable(maxTargetSdk = Build.VERSION_CODES.UPSIDE_DOWN_CAKE) + @Readable public static final String WET_MODE_ON = "wet_mode_on"; /** @@ -19976,7 +19976,7 @@ public final class Settings { * Whether charging sounds are enabled. * @hide */ - @Readable(maxTargetSdk = Build.VERSION_CODES.UPSIDE_DOWN_CAKE) + @Readable public static final String CHARGING_SOUNDS_ENABLED = "wear_charging_sounds_enabled"; /** @@ -19985,7 +19985,7 @@ public final class Settings { * * @hide */ - @Readable(maxTargetSdk = Build.VERSION_CODES.UPSIDE_DOWN_CAKE) + @Readable public static final String DYNAMIC_COLOR_THEME_ENABLED = "dynamic_color_theme_enabled"; /** @@ -20077,7 +20077,7 @@ public final class Settings { * The key to indicate the data migration status on device upgrade in Wear Services. * @hide */ - @Readable(maxTargetSdk = Build.VERSION_CODES.UPSIDE_DOWN_CAKE) + @Readable public static final String UPGRADE_DATA_MIGRATION_STATUS = "upgrade_data_migration_status"; @@ -20134,20 +20134,20 @@ public final class Settings { * The custom foreground color. * @hide */ - @Readable(maxTargetSdk = Build.VERSION_CODES.UPSIDE_DOWN_CAKE) + @Readable public static final String CUSTOM_COLOR_FOREGROUND = "custom_foreground_color"; /** * The custom background color. * @hide */ - @Readable(maxTargetSdk = Build.VERSION_CODES.UPSIDE_DOWN_CAKE) + @Readable public static final String CUSTOM_COLOR_BACKGROUND = "custom_background_color"; /** The status of the phone switching process. * @hide */ - @Readable(maxTargetSdk = Build.VERSION_CODES.UPSIDE_DOWN_CAKE) + @Readable public static final String PHONE_SWITCHING_STATUS = "phone_switching_status"; /** @@ -20318,7 +20318,7 @@ public final class Settings { * Controls the launcher ui mode on wearable devices. * @hide */ - @Readable(maxTargetSdk = Build.VERSION_CODES.UPSIDE_DOWN_CAKE) + @Readable public static final String WEAR_LAUNCHER_UI_MODE = "wear_launcher_ui_mode"; /** Whether Wear Power Anomaly Service is enabled. diff --git a/core/java/android/security/net/config/CertificatesEntryRef.java b/core/java/android/security/net/config/CertificatesEntryRef.java index 45cd0f011299..a46049fb2f6d 100644 --- a/core/java/android/security/net/config/CertificatesEntryRef.java +++ b/core/java/android/security/net/config/CertificatesEntryRef.java @@ -17,6 +17,7 @@ package android.security.net.config; import android.util.ArraySet; + import java.security.cert.X509Certificate; import java.util.Set; @@ -24,16 +25,23 @@ import java.util.Set; public final class CertificatesEntryRef { private final CertificateSource mSource; private final boolean mOverridesPins; + private final boolean mDisableCT; - public CertificatesEntryRef(CertificateSource source, boolean overridesPins) { + public CertificatesEntryRef(CertificateSource source, boolean overridesPins, + boolean disableCT) { mSource = source; mOverridesPins = overridesPins; + mDisableCT = disableCT; } boolean overridesPins() { return mOverridesPins; } + boolean disableCT() { + return mDisableCT; + } + public Set<TrustAnchor> getTrustAnchors() { // TODO: cache this [but handle mutable sources] Set<TrustAnchor> anchors = new ArraySet<TrustAnchor>(); diff --git a/core/java/android/security/net/config/KeyStoreConfigSource.java b/core/java/android/security/net/config/KeyStoreConfigSource.java index 8d4f098bcb37..a54d8d0499cb 100644 --- a/core/java/android/security/net/config/KeyStoreConfigSource.java +++ b/core/java/android/security/net/config/KeyStoreConfigSource.java @@ -17,8 +17,8 @@ package android.security.net.config; import android.util.Pair; + import java.security.KeyStore; -import java.security.KeyStoreException; import java.util.Set; /** @@ -32,7 +32,7 @@ class KeyStoreConfigSource implements ConfigSource { mConfig = new NetworkSecurityConfig.Builder() .addCertificatesEntryRef( // Use the KeyStore and do not override pins (of which there are none). - new CertificatesEntryRef(new KeyStoreCertificateSource(ks), false)) + new CertificatesEntryRef(new KeyStoreCertificateSource(ks), false, false)) .build(); } diff --git a/core/java/android/security/net/config/NetworkSecurityConfig.java b/core/java/android/security/net/config/NetworkSecurityConfig.java index 129ae63ec9c0..410c68b8d04d 100644 --- a/core/java/android/security/net/config/NetworkSecurityConfig.java +++ b/core/java/android/security/net/config/NetworkSecurityConfig.java @@ -112,7 +112,6 @@ public final class NetworkSecurityConfig { return mHstsEnforced; } - // TODO(b/28746284): add exceptions for user-added certificates and enterprise overrides. public boolean isCertificateTransparencyVerificationRequired() { return mCertificateTransparencyVerificationRequired; } @@ -192,20 +191,21 @@ public final class NetworkSecurityConfig { * @hide */ public static Builder getDefaultBuilder(ApplicationInfo info) { + // System certificate store, does not bypass static pins, does not disable CT. + CertificatesEntryRef systemRef = new CertificatesEntryRef( + SystemCertificateSource.getInstance(), false, false); Builder builder = new Builder() .setHstsEnforced(DEFAULT_HSTS_ENFORCED) - // System certificate store, does not bypass static pins. - .addCertificatesEntryRef( - new CertificatesEntryRef(SystemCertificateSource.getInstance(), false)); + .addCertificatesEntryRef(systemRef); final boolean cleartextTrafficPermitted = info.targetSdkVersion < Build.VERSION_CODES.P && !info.isInstantApp(); builder.setCleartextTrafficPermitted(cleartextTrafficPermitted); // Applications targeting N and above must opt in into trusting the user added certificate // store. if (info.targetSdkVersion <= Build.VERSION_CODES.M && !info.isPrivilegedApp()) { - // User certificate store, does not bypass static pins. + // User certificate store, does not bypass static pins. CT is disabled. builder.addCertificatesEntryRef( - new CertificatesEntryRef(UserCertificateSource.getInstance(), false)); + new CertificatesEntryRef(UserCertificateSource.getInstance(), false, true)); } return builder; } @@ -339,6 +339,16 @@ public final class NetworkSecurityConfig { if (mCertificateTransparencyVerificationRequiredSet) { return mCertificateTransparencyVerificationRequired; } + // CT verification has not been set explicitly. Before deferring to + // the parent, check if any of the CertificatesEntryRef requires it + // to be disabled (i.e., user store or inline certificate). + if (hasCertificatesEntryRefs()) { + for (CertificatesEntryRef ref : getCertificatesEntryRefs()) { + if (ref.disableCT()) { + return false; + } + } + } if (mParentBuilder != null) { return mParentBuilder.getCertificateTransparencyVerificationRequired(); } diff --git a/core/java/android/security/net/config/XmlConfigSource.java b/core/java/android/security/net/config/XmlConfigSource.java index b1c14793bbbd..95e579fc538b 100644 --- a/core/java/android/security/net/config/XmlConfigSource.java +++ b/core/java/android/security/net/config/XmlConfigSource.java @@ -182,6 +182,7 @@ public class XmlConfigSource implements ConfigSource { boolean overridePins = parser.getAttributeBooleanValue(null, "overridePins", defaultOverridePins); int sourceId = parser.getAttributeResourceValue(null, "src", -1); + boolean disableCT = false; String sourceString = parser.getAttributeValue(null, "src"); CertificateSource source = null; if (sourceString == null) { @@ -190,10 +191,12 @@ public class XmlConfigSource implements ConfigSource { if (sourceId != -1) { // TODO: Cache ResourceCertificateSources by sourceId source = new ResourceCertificateSource(sourceId, mContext); + disableCT = true; } else if ("system".equals(sourceString)) { source = SystemCertificateSource.getInstance(); } else if ("user".equals(sourceString)) { source = UserCertificateSource.getInstance(); + disableCT = true; } else if ("wfa".equals(sourceString)) { source = WfaCertificateSource.getInstance(); } else { @@ -201,7 +204,7 @@ public class XmlConfigSource implements ConfigSource { + "Should be one of system|user|@resourceVal"); } XmlUtils.skipCurrentTag(parser); - return new CertificatesEntryRef(source, overridePins); + return new CertificatesEntryRef(source, overridePins, disableCT); } private Collection<CertificatesEntryRef> parseTrustAnchors(XmlResourceParser parser, diff --git a/core/java/com/android/internal/os/TEST_MAPPING b/core/java/com/android/internal/os/TEST_MAPPING index 4400ed117721..1923c5fb9186 100644 --- a/core/java/com/android/internal/os/TEST_MAPPING +++ b/core/java/com/android/internal/os/TEST_MAPPING @@ -20,7 +20,7 @@ "file_patterns": [ "BinderDeathDispatcher\\.java" ], - "name": "FrameworksCoreTests_internal_os_binder" + "name": "FrameworksCoreTests_all_binder" }, { "file_patterns": [ diff --git a/core/java/com/android/internal/pm/pkg/component/AconfigFlags.java b/core/java/com/android/internal/pm/pkg/component/AconfigFlags.java index 39aadfb24b0c..f0c8f0ac2bad 100644 --- a/core/java/com/android/internal/pm/pkg/component/AconfigFlags.java +++ b/core/java/com/android/internal/pm/pkg/component/AconfigFlags.java @@ -239,16 +239,12 @@ public class AconfigFlags { negated = true; featureFlag = featureFlag.substring(1).strip(); } - final Boolean flagValue = getFlagValue(featureFlag); + Boolean flagValue = getFlagValue(featureFlag); if (flagValue == null) { - Slog.w(LOG_TAG, "Skipping element " + parser.getName() - + " due to unknown feature flag " + featureFlag); - return true; + flagValue = false; } // Skip if flag==false && attr=="flag" OR flag==true && attr=="!flag" (negated) if (flagValue == negated) { - Slog.v(LOG_TAG, "Skipping element " + parser.getName() - + " behind feature flag " + featureFlag + " = " + flagValue); return true; } return false; diff --git a/core/jni/Android.bp b/core/jni/Android.bp index 9a4ff8fc264f..37c84ce76e61 100644 --- a/core/jni/Android.bp +++ b/core/jni/Android.bp @@ -290,6 +290,7 @@ cc_library_shared_for_libandroid_runtime { "libasync_safe", "libbinderthreadstateutils", "libdmabufinfo", + "libgenfslabelsversion.ffi", "libgui_window_info_static", "libkernelconfigs", "libnativehelper_lazy", diff --git a/core/jni/android_os_SELinux.cpp b/core/jni/android_os_SELinux.cpp index 7a4670f4e49d..805d5ad41e83 100644 --- a/core/jni/android_os_SELinux.cpp +++ b/core/jni/android_os_SELinux.cpp @@ -18,18 +18,19 @@ #include <errno.h> #include <fcntl.h> - +#include <genfslabelsversion.h> +#include <nativehelper/JNIPlatformHelp.h> +#include <nativehelper/ScopedLocalRef.h> +#include <nativehelper/ScopedUtfChars.h> #include <utils/Log.h> -#include <nativehelper/JNIPlatformHelp.h> -#include "jni.h" +#include <atomic> +#include <memory> + #include "core_jni_helpers.h" -#include "selinux/selinux.h" +#include "jni.h" #include "selinux/android.h" -#include <memory> -#include <atomic> -#include <nativehelper/ScopedLocalRef.h> -#include <nativehelper/ScopedUtfChars.h> +#include "selinux/selinux.h" namespace android { namespace { @@ -404,8 +405,19 @@ static jboolean native_restorecon(JNIEnv *env, jobject, jstring pathnameStr, jin } /* + * Function: getGenfsLabelsVersion + * Purpose: get which genfs labels version /vendor uses + * Returns: int: genfs labels version of /vendor + * Exceptions: none + */ +static jint getGenfsLabelsVersion(JNIEnv *, jclass) { + return get_genfs_labels_version(); +} + +/* * JNI registration. */ +// clang-format off static const JNINativeMethod method_table[] = { /* name, signature, funcPtr */ { "checkSELinuxAccess" , "(Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;)Z" , (void*)checkSELinuxAccess }, @@ -420,7 +432,9 @@ static const JNINativeMethod method_table[] = { { "setFileContext" , "(Ljava/lang/String;Ljava/lang/String;)Z" , (void*)setFileCon }, { "setFSCreateContext" , "(Ljava/lang/String;)Z" , (void*)setFSCreateCon }, { "fileSelabelLookup" , "(Ljava/lang/String;)Ljava/lang/String;" , (void*)fileSelabelLookup}, + { "getGenfsLabelsVersion" , "()I" , (void *)getGenfsLabelsVersion}, }; +// clang-format on static int log_callback(int type, const char *fmt, ...) { va_list ap; diff --git a/core/tests/coretests/Android.bp b/core/tests/coretests/Android.bp index 6a191c601846..0a33a80830e3 100644 --- a/core/tests/coretests/Android.bp +++ b/core/tests/coretests/Android.bp @@ -523,14 +523,25 @@ test_module_config { } test_module_config { - name: "FrameworksCoreTests_internal_os_binder", + name: "FrameworksCoreTests_all_binder", base: "FrameworksCoreTests", test_suites: [ "automotive-tests", "device-tests", "device-platinum-tests", ], - include_filters: ["com.android.internal.os.BinderDeathDispatcherTest"], + include_filters: [ + "android.os.BinderProxyTest", + "android.os.BinderDeathRecipientTest", + "android.os.BinderFrozenStateChangeNotificationTest", + "android.os.BinderProxyCountingTest", + "android.os.BinderUncaughtExceptionHandlerTest", + "android.os.BinderThreadPriorityTest", + "android.os.BinderWorkSourceTest", + "android.os.ParcelNullabilityTest", + "android.os.ParcelTest", + "com.android.internal.os.BinderDeathDispatcherTest", + ], exclude_annotations: ["com.android.internal.os.SkipPresubmit"], } diff --git a/core/tests/coretests/src/android/content/res/FontScaleConverterFactoryTest.kt b/core/tests/coretests/src/android/content/res/FontScaleConverterFactoryTest.kt index c0a9bc2cdd24..f9d449cd3b10 100644 --- a/core/tests/coretests/src/android/content/res/FontScaleConverterFactoryTest.kt +++ b/core/tests/coretests/src/android/content/res/FontScaleConverterFactoryTest.kt @@ -18,10 +18,7 @@ package android.content.res 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.RavenwoodFlagsValueProvider -import android.platform.test.ravenwood.RavenwoodRule import android.util.SparseArray import androidx.core.util.forEach import androidx.test.ext.junit.runners.AndroidJUnit4 @@ -47,15 +44,7 @@ import org.junit.runner.RunWith class FontScaleConverterFactoryTest { @get:Rule - val ravenwoodRule: RavenwoodRule = RavenwoodRule.Builder().build() - - @get:Rule - val checkFlagsRule: CheckFlagsRule = - if (RavenwoodRule.isOnRavenwood()) { - RavenwoodFlagsValueProvider.createAllOnCheckFlagsRule() - } else { - DeviceFlagsValueProvider.createCheckFlagsRule() - } + val checkFlagsRule = DeviceFlagsValueProvider.createCheckFlagsRule() private var defaultLookupTables: SparseArray<FontScaleConverter>? = null diff --git a/core/tests/coretests/src/android/content/res/ResourcesManagerTest.java b/core/tests/coretests/src/android/content/res/ResourcesManagerTest.java index 3eefe044de90..9dc4ca19f60c 100644 --- a/core/tests/coretests/src/android/content/res/ResourcesManagerTest.java +++ b/core/tests/coretests/src/android/content/res/ResourcesManagerTest.java @@ -33,8 +33,6 @@ import android.platform.test.annotations.Postsubmit; 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.RavenwoodFlagsValueProvider; -import android.platform.test.ravenwood.RavenwoodRule; import android.util.ArraySet; import android.util.DisplayMetrics; import android.util.TypedValue; @@ -65,13 +63,7 @@ public class ResourcesManagerTest { private static final String TEST_LIB = "com.android.frameworks.coretests.bdr_helper_app1"; @Rule - public final RavenwoodRule mRavenwood = new RavenwoodRule.Builder().build(); - - @Rule - public final CheckFlagsRule mCheckFlagsRule = - RavenwoodRule.isOnRavenwood() - ? RavenwoodFlagsValueProvider.createAllOnCheckFlagsRule() - : DeviceFlagsValueProvider.createCheckFlagsRule(); + public final CheckFlagsRule mCheckFlagsRule = DeviceFlagsValueProvider.createCheckFlagsRule(); private ResourcesManager mResourcesManager; private Map<Integer, DisplayMetrics> mDisplayMetricsMap; diff --git a/core/tests/coretests/src/android/os/BinderThreadPriorityTest.java b/core/tests/coretests/src/android/os/BinderThreadPriorityTest.java index 4172bffe100c..9a679d8e8a96 100644 --- a/core/tests/coretests/src/android/os/BinderThreadPriorityTest.java +++ b/core/tests/coretests/src/android/os/BinderThreadPriorityTest.java @@ -31,6 +31,8 @@ import android.util.Log; import androidx.test.InstrumentationRegistry; import androidx.test.ext.junit.runners.AndroidJUnit4; +import com.android.internal.os.SkipPresubmit; + import org.junit.After; import org.junit.Before; import org.junit.Rule; @@ -131,6 +133,7 @@ public class BinderThreadPriorityTest { } @Test + @SkipPresubmit("b/381950874: bitrot and failed") public void testPassPriorityToService() throws Exception { for (int prio = 19; prio >= -20; prio--) { Process.setThreadPriority(prio); @@ -146,6 +149,7 @@ public class BinderThreadPriorityTest { } @Test + @SkipPresubmit("b/381950874: bitrot and failed") public void testCallBackFromServiceWithPriority() throws Exception { for (int prio = -20; prio <= 19; prio++) { final int expected = prio; diff --git a/keystore/java/Android.bp b/keystore/java/Android.bp index 21edff1e1c96..264ac5ff1d92 100644 --- a/keystore/java/Android.bp +++ b/keystore/java/Android.bp @@ -13,5 +13,13 @@ filegroup { "**/*.java", "**/*.aidl", ], + exclude_srcs: select(release_flag("RELEASE_ATTEST_MODULES"), { + true: [ + "android/security/KeyStore2HalCurrent.java", + ], + default: [ + "android/security/KeyStore2HalLatest.java", + ], + }), visibility: ["//frameworks/base"], } diff --git a/keystore/java/android/security/KeyStore2.java b/keystore/java/android/security/KeyStore2.java index dd703f5eefb9..f5cf571ad955 100644 --- a/keystore/java/android/security/KeyStore2.java +++ b/keystore/java/android/security/KeyStore2.java @@ -101,7 +101,7 @@ public class KeyStore2 { R execute(IKeystoreService service) throws RemoteException; } - private <R> R handleRemoteExceptionWithRetry(@NonNull CheckedRemoteRequest<R> request) + <R> R handleRemoteExceptionWithRetry(@NonNull CheckedRemoteRequest<R> request) throws KeyStoreException { IKeystoreService service = getService(false /* retryLookup */); boolean firstTry = true; @@ -369,6 +369,18 @@ public class KeyStore2 { } } + /** + * Returns tag-specific info required to interpret a tag's attested value. + * @see IKeystoreService#getSupplementaryAttestationInfo(Tag) for more details. + * @param tag + * @return + * @throws KeyStoreException + * @hide + */ + public byte[] getSupplementaryAttestationInfo(int tag) throws KeyStoreException { + return KeyStore2HalVersion.getSupplementaryAttestationInfoHelper(tag, this); + } + static KeyStoreException getKeyStoreException(int errorCode, String serviceErrorMessage) { if (errorCode > 0) { // KeyStore layer error diff --git a/keystore/java/android/security/KeyStore2HalCurrent.java b/keystore/java/android/security/KeyStore2HalCurrent.java new file mode 100644 index 000000000000..f4d8fe65c995 --- /dev/null +++ b/keystore/java/android/security/KeyStore2HalCurrent.java @@ -0,0 +1,30 @@ +/* + * Copyright (C) 2024 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package android.security; + +/** + * @hide This class is necessary to allow the version of the AIDL interface for Keystore and +* KeyMint used in KeyStore2.java to differ by BUILD flag `RELEASE_ATTEST_MODULES`. When +* `RELEASE_ATTEST_MODULES` is not set, this file is included, and the current HALs for Keystore +* (V4) and KeyMint (V3) are used. +*/ +class KeyStore2HalVersion { + public static byte[] getSupplementaryAttestationInfoHelper(int tag, KeyStore2 ks) + throws KeyStoreException { + return new byte[0]; + } +} diff --git a/keystore/java/android/security/KeyStore2HalLatest.java b/keystore/java/android/security/KeyStore2HalLatest.java new file mode 100644 index 000000000000..123f1c0b8f39 --- /dev/null +++ b/keystore/java/android/security/KeyStore2HalLatest.java @@ -0,0 +1,31 @@ +/* + * Copyright (C) 2024 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package android.security; + +/** + * @hide This class is necessary to allow the version of the AIDL interface for Keystore and +* KeyMint used in KeyStore2.java to differ by BUILD flag `RELEASE_ATTEST_MODULES`. When +* `RELEASE_ATTEST_MODULES` is set, this file is included, and the latest HALs for Keystore (V5) +* and KeyMint (V4) are used. +*/ +class KeyStore2HalVersion { + public static byte[] getSupplementaryAttestationInfoHelper(int tag, KeyStore2 ks) + throws KeyStoreException { + return ks.handleRemoteExceptionWithRetry( + (service) -> service.getSupplementaryAttestationInfo(tag)); + } +} diff --git a/keystore/java/android/security/keystore/KeyStoreManager.java b/keystore/java/android/security/keystore/KeyStoreManager.java index e6091c1da8a5..740ccb53a691 100644 --- a/keystore/java/android/security/keystore/KeyStoreManager.java +++ b/keystore/java/android/security/keystore/KeyStoreManager.java @@ -17,9 +17,11 @@ package android.security.keystore; import android.annotation.FlaggedApi; +import android.annotation.IntDef; import android.annotation.NonNull; import android.annotation.SystemService; import android.content.Context; +import android.hardware.security.keymint.TagType; import android.security.KeyStore2; import android.security.KeyStoreException; import android.security.keystore2.AndroidKeyStoreProvider; @@ -32,6 +34,8 @@ import android.util.Log; import com.android.internal.annotations.GuardedBy; import java.io.ByteArrayInputStream; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; import java.security.Key; import java.security.KeyPair; import java.security.PublicKey; @@ -299,6 +303,37 @@ public final class KeyStoreManager { return Collections.emptyList(); } + /** @hide */ + @Retention(RetentionPolicy.SOURCE) + @IntDef(value = {MODULE_HASH}) + public @interface SupplementaryAttestationInfoTagEnum {} + + /** + * When passed into getSupplementaryAttestationInfo, getSupplementaryAttestationInfo returns the + * DER-encoded structure corresponding to the `Modules` schema described in the KeyMint HAL's + * KeyCreationResult.aidl. The SHA-256 hash of this encoded structure is what's included with + * the tag in attestations. + */ + // TODO(b/369375199): Replace with Tag.MODULE_HASH when flagging is removed. + public static final int MODULE_HASH = TagType.BYTES | 724; + + /** + * Returns tag-specific data required to interpret a tag's attested value. + * + * When performing key attestation, the obtained attestation certificate contains a list of tags + * and their corresponding attested values. For some tags, additional information about the + * attested value can be queried via this API. See individual tags for specifics. + * + * @param tag tag for which info is being requested + * @return tag-specific info + * @throws KeyStoreException if the requested info is not available + */ + @FlaggedApi(android.security.keystore2.Flags.FLAG_ATTEST_MODULES) + public @NonNull byte[] getSupplementaryAttestationInfo( + @SupplementaryAttestationInfoTagEnum int tag) throws KeyStoreException { + return mKeyStore2.getSupplementaryAttestationInfo(tag); + } + /** * Returns a new {@link KeyDescriptor} instance in the app domain / namespace with the {@code * alias} set to the provided value. diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/back/BackAnimationController.java b/libs/WindowManager/Shell/src/com/android/wm/shell/back/BackAnimationController.java index 3e5adf395cdd..5836085e0ddc 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/back/BackAnimationController.java +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/back/BackAnimationController.java @@ -1501,10 +1501,6 @@ public class BackAnimationController implements RemoteCallable<BackAnimationCont int rootIdx = -1; for (int i = info.getChanges().size() - 1; i >= 0; --i) { final TransitionInfo.Change c = info.getChanges().get(i); - if (c.hasFlags(FLAG_IS_WALLPAPER)) { - st.setAlpha(c.getLeash(), 1.0f); - continue; - } if (TransitionUtil.isOpeningMode(c.getMode())) { final Point offset = c.getEndRelOffset(); st.setPosition(c.getLeash(), offset.x, offset.y); diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/transition/MixedTransitionHelper.java b/libs/WindowManager/Shell/src/com/android/wm/shell/transition/MixedTransitionHelper.java index 30d7245436be..e61929fef312 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/transition/MixedTransitionHelper.java +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/transition/MixedTransitionHelper.java @@ -141,10 +141,13 @@ public class MixedTransitionHelper { pipHandler.setEnterAnimationType(ANIM_TYPE_ALPHA); pipHandler.startEnterAnimation(pipChange, startTransaction, finishTransaction, finishCB); + // make a new finishTransaction because pip's startEnterAnimation "consumes" it so + // we need a separate one to send over to launcher. + SurfaceControl.Transaction otherFinishT = new SurfaceControl.Transaction(); // Dispatch the rest of the transition normally. This will most-likely be taken by // recents or default handler. mixed.mLeftoversHandler = player.dispatchTransition(mixed.mTransition, everythingElse, - otherStartT, finishTransaction, finishCB, mixedHandler); + otherStartT, otherFinishT, finishCB, mixedHandler); } else { ProtoLog.v(ShellProtoLogGroup.WM_SHELL_TRANSITIONS, " Not leaving split, so just " + "forward animation to Pip-Handler."); diff --git a/libs/WindowManager/Shell/tests/flicker/pip/src/com/android/wm/shell/flicker/pip/FromSplitScreenEnterPipOnUserLeaveHintTest.kt b/libs/WindowManager/Shell/tests/flicker/pip/src/com/android/wm/shell/flicker/pip/FromSplitScreenEnterPipOnUserLeaveHintTest.kt index d03d7799d675..d1bf6acf785d 100644 --- a/libs/WindowManager/Shell/tests/flicker/pip/src/com/android/wm/shell/flicker/pip/FromSplitScreenEnterPipOnUserLeaveHintTest.kt +++ b/libs/WindowManager/Shell/tests/flicker/pip/src/com/android/wm/shell/flicker/pip/FromSplitScreenEnterPipOnUserLeaveHintTest.kt @@ -183,12 +183,6 @@ class FromSplitScreenEnterPipOnUserLeaveHintTest(flicker: LegacyFlickerTest) : } /** {@inheritDoc} */ - @FlakyTest(bugId = 312446524) - @Test - override fun visibleLayersShownMoreThanOneConsecutiveEntry() = - super.visibleLayersShownMoreThanOneConsecutiveEntry() - - /** {@inheritDoc} */ @Test @FlakyTest(bugId = 336510055) override fun entireScreenCovered() { diff --git a/packages/SettingsProvider/src/com/android/providers/settings/SettingsProvider.java b/packages/SettingsProvider/src/com/android/providers/settings/SettingsProvider.java index 749ad0a993b3..6f8947c9bea1 100644 --- a/packages/SettingsProvider/src/com/android/providers/settings/SettingsProvider.java +++ b/packages/SettingsProvider/src/com/android/providers/settings/SettingsProvider.java @@ -2479,10 +2479,10 @@ public class SettingsProvider extends ContentProvider { final long identity = Binder.clearCallingIdentity(); try { int currentUser = ActivityManager.getCurrentUser(); - if (callingUser == currentUser) { - // enforce the deny list only if the caller is not current user. Currently only auto - // uses background visible user, and auto doesn't support profiles so profiles of - // current users is not checked here. + if (callingUser == currentUser || callingUser == UserHandle.USER_SYSTEM) { + // enforce the deny list only if the caller is not current user or not a system + // user. Currently only auto uses background visible user, and auto doesn't + // support profiles so profiles of current users is not checked here. return; } } finally { diff --git a/packages/SystemUI/aconfig/systemui.aconfig b/packages/SystemUI/aconfig/systemui.aconfig index f8383d94b1ab..554ad8ba64e6 100644 --- a/packages/SystemUI/aconfig/systemui.aconfig +++ b/packages/SystemUI/aconfig/systemui.aconfig @@ -1431,4 +1431,14 @@ flag { metadata { purpose: PURPOSE_BUGFIX } +} + +flag { + name: "ignore_touches_next_to_notification_shelf" + namespace: "systemui" + description: "The shelf can vertically overlap the unlock icon. Ignore touches if so." + bug: "358424256" + metadata { + purpose: PURPOSE_BUGFIX + } }
\ No newline at end of file diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/dreams/DreamOverlayCallbackControllerTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/dreams/DreamOverlayCallbackControllerTest.kt index d9dcfdc7becb..9c6fd4bf71b4 100644 --- a/packages/SystemUI/multivalentTests/src/com/android/systemui/dreams/DreamOverlayCallbackControllerTest.kt +++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/dreams/DreamOverlayCallbackControllerTest.kt @@ -56,6 +56,7 @@ class DreamOverlayCallbackControllerTest : SysuiTestCase() { // Adding twice should not invoke twice reset(callback) + underTest.onStartDream() underTest.addCallback(callback) underTest.onWakeUp() verify(callback, times(1)).onWakeUp() @@ -68,6 +69,19 @@ class DreamOverlayCallbackControllerTest : SysuiTestCase() { } @Test + fun onWakeUp_multipleCalls() { + underTest.onStartDream() + assertThat(underTest.isDreaming).isEqualTo(true) + + underTest.addCallback(callback) + underTest.onWakeUp() + underTest.onWakeUp() + underTest.onWakeUp() + verify(callback, times(1)).onWakeUp() + assertThat(underTest.isDreaming).isEqualTo(false) + } + + @Test fun onStartDreamInvokesCallback() { underTest.addCallback(callback) diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/dreams/DreamOverlayServiceTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/dreams/DreamOverlayServiceTest.kt index 7dd717470153..30b0aef90489 100644 --- a/packages/SystemUI/multivalentTests/src/com/android/systemui/dreams/DreamOverlayServiceTest.kt +++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/dreams/DreamOverlayServiceTest.kt @@ -712,6 +712,9 @@ class DreamOverlayServiceTest : SysuiTestCase() { // Verify DreamOverlayContainerViewController is destroyed. verify(mDreamOverlayContainerViewController).destroy() + + // DreamOverlay callback receives onWakeUp. + verify(mDreamOverlayCallbackController).onWakeUp() } @Test diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/ui/viewmodel/DeviceEntryBackgroundViewModelTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/ui/viewmodel/DeviceEntryBackgroundViewModelTest.kt new file mode 100644 index 000000000000..22677b2f8e3e --- /dev/null +++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/ui/viewmodel/DeviceEntryBackgroundViewModelTest.kt @@ -0,0 +1,90 @@ +/* + * Copyright (C) 2024 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.systemui.keyguard.ui.viewmodel + +import androidx.test.ext.junit.runners.AndroidJUnit4 +import androidx.test.filters.SmallTest +import com.android.systemui.SysuiTestCase +import com.android.systemui.biometrics.data.repository.fingerprintPropertyRepository +import com.android.systemui.coroutines.collectLastValue +import com.android.systemui.keyguard.data.repository.fakeKeyguardTransitionRepository +import com.android.systemui.keyguard.shared.model.KeyguardState +import com.android.systemui.keyguard.shared.model.TransitionState +import com.android.systemui.keyguard.shared.model.TransitionState.RUNNING +import com.android.systemui.keyguard.shared.model.TransitionState.STARTED +import com.android.systemui.keyguard.shared.model.TransitionStep +import com.android.systemui.kosmos.testScope +import com.android.systemui.testKosmos +import com.google.common.truth.Truth.assertThat +import kotlinx.coroutines.ExperimentalCoroutinesApi +import kotlinx.coroutines.test.runCurrent +import kotlinx.coroutines.test.runTest +import org.junit.Test +import org.junit.runner.RunWith + +@ExperimentalCoroutinesApi +@SmallTest +@RunWith(AndroidJUnit4::class) +class DeviceEntryBackgroundViewModelTest : SysuiTestCase() { + private val kosmos = testKosmos() + private val testScope = kosmos.testScope + private val underTest: DeviceEntryBackgroundViewModel by lazy { + kosmos.deviceEntryBackgroundViewModel + } + + @Test + fun lockscreenToDozingTransitionChangesBackgroundViewAlphaToZero() = + testScope.runTest { + kosmos.fingerprintPropertyRepository.supportsUdfps() + val alpha by collectLastValue(underTest.alpha) + + kosmos.fakeKeyguardTransitionRepository.sendTransitionSteps( + listOf(dozingToLockscreen(0f, STARTED), dozingToLockscreen(0.1f)), + testScope, + ) + runCurrent() + assertThat(alpha).isEqualTo(1.0f) + + kosmos.fakeKeyguardTransitionRepository.sendTransitionSteps( + listOf(lockscreenToDozing(0f, STARTED)), + testScope, + ) + runCurrent() + + assertThat(alpha).isEqualTo(0.0f) + } + + private fun lockscreenToDozing(value: Float, state: TransitionState = RUNNING): TransitionStep { + return TransitionStep( + from = KeyguardState.LOCKSCREEN, + to = KeyguardState.DOZING, + value = value, + transitionState = state, + ownerName = "DeviceEntryBackgroundViewModelTest", + ) + } + + private fun dozingToLockscreen(value: Float, state: TransitionState = RUNNING): TransitionStep { + return TransitionStep( + from = KeyguardState.DOZING, + to = KeyguardState.LOCKSCREEN, + value = value, + transitionState = state, + ownerName = "DeviceEntryBackgroundViewModelTest", + ) + } +} diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/ui/viewmodel/KeyguardRootViewModelTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/ui/viewmodel/KeyguardRootViewModelTest.kt index 5d606c67a4d7..4b1ed3b2354a 100644 --- a/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/ui/viewmodel/KeyguardRootViewModelTest.kt +++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/ui/viewmodel/KeyguardRootViewModelTest.kt @@ -189,17 +189,6 @@ class KeyguardRootViewModelTest(flags: FlagsParameterization) : SysuiTestCase() } @Test - fun iconContainer_isVisible_bypassEnabled() = - testScope.runTest { - val isVisible by collectLastValue(underTest.isNotifIconContainerVisible) - runCurrent() - deviceEntryRepository.setBypassEnabled(true) - runCurrent() - - assertThat(isVisible?.value).isTrue() - } - - @Test fun iconContainer_isNotVisible_pulseExpanding_notBypassing() = testScope.runTest { val isVisible by collectLastValue(underTest.isNotifIconContainerVisible) @@ -288,22 +277,23 @@ class KeyguardRootViewModelTest(flags: FlagsParameterization) : SysuiTestCase() } @Test - fun iconContainer_isNotVisible_bypassDisabled_onLockscreen() = + fun iconContainer_isNotVisible_notifsFullyHiddenThenVisible_bypassEnabled() = testScope.runTest { val isVisible by collectLastValue(underTest.isNotifIconContainerVisible) runCurrent() - keyguardTransitionRepository.sendTransitionSteps( - from = KeyguardState.AOD, - to = KeyguardState.LOCKSCREEN, - testScope, - ) notificationsKeyguardInteractor.setPulseExpanding(false) - deviceEntryRepository.setBypassEnabled(false) + deviceEntryRepository.setBypassEnabled(true) whenever(dozeParameters.alwaysOn).thenReturn(true) whenever(dozeParameters.displayNeedsBlanking).thenReturn(false) notificationsKeyguardInteractor.setNotificationsFullyHidden(true) runCurrent() + assertThat(isVisible?.value).isTrue() + assertThat(isVisible?.isAnimating).isTrue() + + notificationsKeyguardInteractor.setNotificationsFullyHidden(false) + runCurrent() + assertThat(isVisible?.value).isFalse() assertThat(isVisible?.isAnimating).isTrue() } diff --git a/packages/SystemUI/res/layout/super_notification_shade.xml b/packages/SystemUI/res/layout/super_notification_shade.xml index 22d34eb7b115..fbb07bed4b50 100644 --- a/packages/SystemUI/res/layout/super_notification_shade.xml +++ b/packages/SystemUI/res/layout/super_notification_shade.xml @@ -58,22 +58,22 @@ android:layout_height="match_parent" android:visibility="invisible" /> - <!-- Shared container for the notification stack. Can be positioned by either - the keyguard_root_view or notification_panel --> - <com.android.systemui.statusbar.notification.stack.ui.view.SharedNotificationContainer - android:id="@+id/shared_notification_container" + <!-- Root for all keyguard content. It was previously located within the shade. --> + <com.android.systemui.keyguard.ui.view.KeyguardRootView + android:id="@id/keyguard_root_view" android:layout_width="match_parent" android:layout_height="match_parent" android:clipChildren="false" - android:clipToPadding="false" /> - <!-- Root for all keyguard content. It was previously located within the shade. --> - <com.android.systemui.keyguard.ui.view.KeyguardRootView - android:id="@id/keyguard_root_view" + <!-- Shared container for the notification stack. Can be positioned by either + the keyguard_root_view or notification_panel --> + <com.android.systemui.statusbar.notification.stack.ui.view.SharedNotificationContainer + android:id="@+id/shared_notification_container" android:layout_width="match_parent" android:layout_height="match_parent" android:clipChildren="false" + android:clipToPadding="false" /> <include layout="@layout/brightness_mirror_container" /> diff --git a/packages/SystemUI/src/com/android/systemui/bouncer/domain/interactor/AlternateBouncerInteractor.kt b/packages/SystemUI/src/com/android/systemui/bouncer/domain/interactor/AlternateBouncerInteractor.kt index 373671d01395..0949ea4d7797 100644 --- a/packages/SystemUI/src/com/android/systemui/bouncer/domain/interactor/AlternateBouncerInteractor.kt +++ b/packages/SystemUI/src/com/android/systemui/bouncer/domain/interactor/AlternateBouncerInteractor.kt @@ -16,6 +16,7 @@ package com.android.systemui.bouncer.domain.interactor +import android.util.Log import com.android.keyguard.KeyguardUpdateMonitor import com.android.systemui.biometrics.data.repository.FingerprintPropertyRepository import com.android.systemui.bouncer.data.repository.KeyguardBouncerRepository @@ -46,6 +47,7 @@ import kotlinx.coroutines.flow.distinctUntilChanged import kotlinx.coroutines.flow.flatMapLatest import kotlinx.coroutines.flow.flowOf import kotlinx.coroutines.flow.map +import kotlinx.coroutines.flow.onEach import kotlinx.coroutines.flow.stateIn /** Encapsulates business logic for interacting with the lock-screen alternate bouncer. */ @@ -137,6 +139,8 @@ constructor( flowOf(false) } } + .distinctUntilChanged() + .onEach { Log.d(TAG, "canShowAlternateBouncer changed to $it") } .stateIn( scope = scope, started = WhileSubscribed(), @@ -234,5 +238,7 @@ constructor( companion object { private const val MIN_VISIBILITY_DURATION_UNTIL_TOUCHES_DISMISS_ALTERNATE_BOUNCER_MS = 200L + + private const val TAG = "AlternateBouncerInteractor" } } diff --git a/packages/SystemUI/src/com/android/systemui/dreams/DreamOverlayCallbackController.kt b/packages/SystemUI/src/com/android/systemui/dreams/DreamOverlayCallbackController.kt index d5ff8f21abb2..2b617525fbcc 100644 --- a/packages/SystemUI/src/com/android/systemui/dreams/DreamOverlayCallbackController.kt +++ b/packages/SystemUI/src/com/android/systemui/dreams/DreamOverlayCallbackController.kt @@ -39,8 +39,10 @@ class DreamOverlayCallbackController @Inject constructor() : } fun onWakeUp() { - isDreaming = false - callbacks.forEach { it.onWakeUp() } + if (isDreaming) { + isDreaming = false + callbacks.forEach { it.onWakeUp() } + } } fun onStartDream() { diff --git a/packages/SystemUI/src/com/android/systemui/dreams/DreamOverlayService.java b/packages/SystemUI/src/com/android/systemui/dreams/DreamOverlayService.java index 113e0011f5bd..0b465e9ce6db 100644 --- a/packages/SystemUI/src/com/android/systemui/dreams/DreamOverlayService.java +++ b/packages/SystemUI/src/com/android/systemui/dreams/DreamOverlayService.java @@ -296,6 +296,8 @@ public class DreamOverlayService extends android.service.dreams.DreamOverlayServ mStateController.setLowLightActive(false); mStateController.setEntryAnimationsFinished(false); + mDreamOverlayCallbackController.onWakeUp(); + if (mDreamOverlayContainerViewController != null) { mDreamOverlayContainerViewController.destroy(); mDreamOverlayContainerViewController = null; diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/FromLockscreenTransitionInteractor.kt b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/FromLockscreenTransitionInteractor.kt index afe3481677c3..4d3727657f3e 100644 --- a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/FromLockscreenTransitionInteractor.kt +++ b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/FromLockscreenTransitionInteractor.kt @@ -189,6 +189,7 @@ constructor( internalTransitionInteractor.currentTransitionInfoInternal, keyguardInteractor.statusBarState, keyguardInteractor.isKeyguardDismissible, + keyguardInteractor.isKeyguardOccluded, ) .collect { ( @@ -196,7 +197,8 @@ constructor( startedStep, currentTransitionInfo, statusBarState, - isKeyguardUnlocked) -> + isKeyguardUnlocked, + isKeyguardOccluded) -> val id = transitionId if (id != null) { if (startedStep.to == KeyguardState.PRIMARY_BOUNCER) { @@ -236,9 +238,13 @@ constructor( if (nextState == TransitionState.CANCELED) { transitionRepository.startTransition( TransitionInfo( - ownerName = name, + ownerName = + "$name " + + "(on behalf of FromPrimaryBouncerInteractor)", from = KeyguardState.PRIMARY_BOUNCER, - to = KeyguardState.LOCKSCREEN, + to = + if (isKeyguardOccluded) KeyguardState.OCCLUDED + else KeyguardState.LOCKSCREEN, modeOnCanceled = TransitionModeOnCanceled.REVERSE, animator = getDefaultAnimatorForTransitionsToState( diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/ui/binder/KeyguardPreviewClockViewBinder.kt b/packages/SystemUI/src/com/android/systemui/keyguard/ui/binder/KeyguardPreviewClockViewBinder.kt index 86dae0cbc6aa..69fc012e007a 100644 --- a/packages/SystemUI/src/com/android/systemui/keyguard/ui/binder/KeyguardPreviewClockViewBinder.kt +++ b/packages/SystemUI/src/com/android/systemui/keyguard/ui/binder/KeyguardPreviewClockViewBinder.kt @@ -121,7 +121,10 @@ object KeyguardPreviewClockViewBinder { private fun applyClockDefaultConstraints(context: Context, constraints: ConstraintSet) { constraints.apply { constrainWidth(R.id.lockscreen_clock_view_large, ConstraintSet.WRAP_CONTENT) - constrainHeight(R.id.lockscreen_clock_view_large, ConstraintSet.MATCH_CONSTRAINT) + // The following two lines make lockscreen_clock_view_large is constrained to available + // height when it goes beyond constraints; otherwise, it use WRAP_CONTENT + constrainHeight(R.id.lockscreen_clock_view_large, WRAP_CONTENT) + constrainMaxHeight(R.id.lockscreen_clock_view_large, 0) val largeClockTopMargin = SystemBarUtils.getStatusBarHeight(context) + context.resources.getDimensionPixelSize( @@ -138,7 +141,7 @@ object KeyguardPreviewClockViewBinder { R.id.lockscreen_clock_view_large, ConstraintSet.END, PARENT_ID, - ConstraintSet.END + ConstraintSet.END, ) // In preview, we'll show UDFPS icon for UDFPS devices @@ -160,14 +163,14 @@ object KeyguardPreviewClockViewBinder { BOTTOM, PARENT_ID, BOTTOM, - clockBottomMargin + clockBottomMargin, ) } constrainWidth(R.id.lockscreen_clock_view, WRAP_CONTENT) constrainHeight( R.id.lockscreen_clock_view, - context.resources.getDimensionPixelSize(customizationR.dimen.small_clock_height) + context.resources.getDimensionPixelSize(customizationR.dimen.small_clock_height), ) connect( R.id.lockscreen_clock_view, @@ -175,7 +178,7 @@ object KeyguardPreviewClockViewBinder { PARENT_ID, START, context.resources.getDimensionPixelSize(customizationR.dimen.clock_padding_start) + - context.resources.getDimensionPixelSize(R.dimen.status_view_margin_horizontal) + context.resources.getDimensionPixelSize(R.dimen.status_view_margin_horizontal), ) val smallClockTopMargin = context.resources.getDimensionPixelSize(R.dimen.keyguard_clock_top_margin) + @@ -188,7 +191,7 @@ object KeyguardPreviewClockViewBinder { context: Context, rootView: ConstraintLayout, previewClock: ClockController, - viewModel: KeyguardPreviewClockViewModel + viewModel: KeyguardPreviewClockViewModel, ) { val cs = ConstraintSet().apply { clone(rootView) } applyClockDefaultConstraints(context, cs) diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/DeviceEntryBackgroundViewModel.kt b/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/DeviceEntryBackgroundViewModel.kt index a021de446911..546b32073aca 100644 --- a/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/DeviceEntryBackgroundViewModel.kt +++ b/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/DeviceEntryBackgroundViewModel.kt @@ -59,6 +59,7 @@ constructor( primaryBouncerToAodTransitionViewModel: PrimaryBouncerToAodTransitionViewModel, primaryBouncerToDozingTransitionViewModel: PrimaryBouncerToDozingTransitionViewModel, primaryBouncerToLockscreenTransitionViewModel: PrimaryBouncerToLockscreenTransitionViewModel, + lockscreenToDozingTransitionViewModel: LockscreenToDozingTransitionViewModel, ) { val color: Flow<Int> = deviceEntryIconViewModel.useBackgroundProtection.flatMapLatest { useBackground -> @@ -103,6 +104,7 @@ constructor( primaryBouncerToLockscreenTransitionViewModel .deviceEntryBackgroundViewAlpha, occludedToDozingTransitionViewModel.deviceEntryBackgroundViewAlpha, + lockscreenToDozingTransitionViewModel.deviceEntryBackgroundViewAlpha, ) .merge() .onStart { 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 0b023d9bfead..630fb99bc70a 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 @@ -341,12 +341,8 @@ constructor( when { // If there are no notification icons to show, then it can be hidden !hasAodIcons -> false - // If we're bypassing, then we're visible - isBypassEnabled -> true // If we are pulsing (and not bypassing), then we are hidden isPulseExpanding -> false - // Besides bypass above, they should not be visible on lockscreen - isOnLockscreen -> false // If notifs are fully gone, then we're visible areNotifsFullyHidden -> true // Otherwise, we're hidden diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/LockscreenToDozingTransitionViewModel.kt b/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/LockscreenToDozingTransitionViewModel.kt index d3eefca67037..7abf35de5dae 100644 --- a/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/LockscreenToDozingTransitionViewModel.kt +++ b/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/LockscreenToDozingTransitionViewModel.kt @@ -55,16 +55,16 @@ constructor( onCancel = { 1f }, ) + val deviceEntryBackgroundViewAlpha: Flow<Float> = + transitionAnimation.immediatelyTransitionTo(0f) + override val deviceEntryParentViewAlpha: Flow<Float> = deviceEntryUdfpsInteractor.isUdfpsEnrolledAndEnabled.flatMapLatest { isUdfpsEnrolledAndEnabled -> if (isUdfpsEnrolledAndEnabled) { transitionAnimation.immediatelyTransitionTo(1f) } else { - transitionAnimation.sharedFlow( - duration = 250.milliseconds, - onStep = { 1f - it }, - ) + transitionAnimation.sharedFlow(duration = 250.milliseconds, onStep = { 1f - it }) } } } diff --git a/packages/SystemUI/src/com/android/systemui/media/controls/domain/pipeline/MediaProcessingHelper.kt b/packages/SystemUI/src/com/android/systemui/media/controls/domain/pipeline/MediaProcessingHelper.kt index 55d7b1d498e0..2bdee67dd57a 100644 --- a/packages/SystemUI/src/com/android/systemui/media/controls/domain/pipeline/MediaProcessingHelper.kt +++ b/packages/SystemUI/src/com/android/systemui/media/controls/domain/pipeline/MediaProcessingHelper.kt @@ -42,7 +42,7 @@ fun isSameMediaData( context: Context, newController: MediaController, new: MediaData, - old: MediaData? + old: MediaData?, ): Boolean { if (old == null || !mediaControlsPostsOptimization()) return false @@ -71,7 +71,7 @@ fun isSameMediaData( /** Returns whether actions lists are equal. */ fun areCustomActionListsEqual( first: List<PlaybackState.CustomAction>?, - second: List<PlaybackState.CustomAction>? + second: List<PlaybackState.CustomAction>?, ): Boolean { // Same object, or both null if (first === second) { @@ -94,7 +94,7 @@ fun areCustomActionListsEqual( private fun areCustomActionsEqual( firstAction: PlaybackState.CustomAction, - secondAction: PlaybackState.CustomAction + secondAction: PlaybackState.CustomAction, ): Boolean { if ( firstAction.action != secondAction.action || @@ -139,7 +139,7 @@ private fun areActionsEqual( context: Context, newController: MediaController, new: MediaData, - old: MediaData + old: MediaData, ): Boolean { val oldState = MediaController(context, old.token!!).playbackState return if ( @@ -150,8 +150,7 @@ private fun areActionsEqual( var same = true new.actions.asSequence().zip(old.actions.asSequence()).forEach { if ( - it.first.actionIntent?.intent?.filterEquals(it.second.actionIntent?.intent) != - true || + it.first.actionIntent?.intent != it.second.actionIntent?.intent || it.first.icon != it.second.icon || it.first.contentDescription != it.second.contentDescription ) { @@ -164,7 +163,7 @@ private fun areActionsEqual( oldState?.actions == newController.playbackState?.actions && areCustomActionListsEqual( oldState?.customActions, - newController.playbackState?.customActions + newController.playbackState?.customActions, ) } else { false @@ -172,8 +171,5 @@ private fun areActionsEqual( } private fun areClickIntentsEqual(newIntent: PendingIntent?, oldIntent: PendingIntent?): Boolean { - if ((newIntent == null && oldIntent == null) || newIntent === oldIntent) return true - if (newIntent == null || oldIntent == null) return false - - return newIntent.intent?.filterEquals(oldIntent.intent) == true + return newIntent == oldIntent } diff --git a/packages/SystemUI/src/com/android/systemui/shade/NotificationPanelViewController.java b/packages/SystemUI/src/com/android/systemui/shade/NotificationPanelViewController.java index 0c05dbde6117..e197f03b5575 100644 --- a/packages/SystemUI/src/com/android/systemui/shade/NotificationPanelViewController.java +++ b/packages/SystemUI/src/com/android/systemui/shade/NotificationPanelViewController.java @@ -2710,6 +2710,11 @@ public final class NotificationPanelViewController implements ShadeSurface, Dump } private int calculatePanelHeightShade() { + // Bypass should always occupy the full height + if (mBarState == KEYGUARD && mKeyguardBypassController.getBypassEnabled()) { + return mNotificationStackScrollLayoutController.getHeight(); + } + int emptyBottomMargin = mNotificationStackScrollLayoutController.getEmptyBottomMargin(); int maxHeight = mNotificationStackScrollLayoutController.getHeight() - emptyBottomMargin; diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ActivatableNotificationView.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ActivatableNotificationView.java index 7b6a2cb62b14..560028cb5640 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ActivatableNotificationView.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ActivatableNotificationView.java @@ -444,9 +444,11 @@ public abstract class ActivatableNotificationView extends ExpandableOutlineView if (onFinishedRunnable != null) { onFinishedRunnable.run(); } + if (mRunWithoutInterruptions) { + enableAppearDrawing(false); + } // We need to reset the View state, even if the animation was cancelled - enableAppearDrawing(false); onAppearAnimationFinished(isAppearing); if (mRunWithoutInterruptions) { diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationContentInflater.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationContentInflater.java index 8c80fd400360..36e3e92e4063 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationContentInflater.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationContentInflater.java @@ -203,13 +203,16 @@ public class NotificationContentInflater implements NotificationRowContentBinder messagingStyle = mConversationProcessor .processNotification(entry, builder, mLogger); } - result.mInflatedSingleLineViewModel = SingleLineViewInflater + SingleLineViewModel viewModel = SingleLineViewInflater .inflateSingleLineViewModel( entry.getSbn().getNotification(), messagingStyle, builder, row.getContext() ); + // If the messagingStyle is null, we want to inflate the normal view + isConversation = viewModel.isConversation(); + result.mInflatedSingleLineViewModel = viewModel; result.mInflatedSingleLineView = SingleLineViewInflater.inflatePrivateSingleLineView( isConversation, diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/SingleLineViewInflater.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/SingleLineViewInflater.kt index d67947d1fda8..4e26ae85100c 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/SingleLineViewInflater.kt +++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/SingleLineViewInflater.kt @@ -90,7 +90,7 @@ internal object SingleLineViewInflater { notification = notification, isGroupConversation = isGroupConversation, builder = builder, - systemUiContext = systemUiContext + systemUiContext = systemUiContext, ) val conversationData = @@ -98,7 +98,7 @@ internal object SingleLineViewInflater { // We don't show the sender's name for one-to-one conversation conversationSenderName = if (isGroupConversation) conversationTextData?.senderName else null, - avatar = conversationAvatar + avatar = conversationAvatar, ) return SingleLineViewModel( @@ -111,7 +111,7 @@ internal object SingleLineViewInflater { @JvmStatic fun inflateRedactedSingleLineViewModel( context: Context, - isConversation: Boolean = false + isConversation: Boolean = false, ): SingleLineViewModel { val conversationData = if (isConversation) { @@ -122,7 +122,7 @@ internal object SingleLineViewInflater { com.android.systemui.res.R.drawable .ic_redacted_notification_single_line_icon ) - ) + ), ) } else { null @@ -134,7 +134,7 @@ internal object SingleLineViewInflater { context.getString( com.android.systemui.res.R.string.redacted_notification_single_line_text ), - conversationData + conversationData, ) } @@ -159,11 +159,13 @@ internal object SingleLineViewInflater { } // load the sender's name to display - val name = lastMessage.senderPerson?.name + // null senderPerson means the current user. + val name = lastMessage.senderPerson?.name ?: user.name + val senderName = systemUiContext.resources.getString( R.string.conversation_single_line_name_display, - if (Flags.cleanUpSpansAndNewLines()) name?.toString() else name + if (Flags.cleanUpSpansAndNewLines()) name?.toString() else name, ) // We need to find back-up values for those texts if they are needed and empty @@ -333,7 +335,7 @@ internal object SingleLineViewInflater { sender.icon ?: builder.getDefaultAvatar( name = sender.name, - uniqueNames = uniqueNames + uniqueNames = uniqueNames, ) lastKey = senderKey } else { @@ -341,7 +343,7 @@ internal object SingleLineViewInflater { sender.icon ?: builder.getDefaultAvatar( name = sender.name, - uniqueNames = uniqueNames + uniqueNames = uniqueNames, ) break } @@ -424,7 +426,7 @@ internal object SingleLineViewInflater { private fun Notification.Builder.getDefaultAvatar( name: CharSequence?, - uniqueNames: PeopleHelper.NameToPrefixMap? = null + uniqueNames: PeopleHelper.NameToPrefixMap? = null, ): Icon { val layoutColor = getSmallIconColor(/* isHeader= */ false) if (!name.isNullOrEmpty()) { @@ -432,7 +434,7 @@ internal object SingleLineViewInflater { return peopleHelper.createAvatarSymbol( /* name = */ name, /* symbol = */ symbol, - /* layoutColor = */ layoutColor + /* layoutColor = */ layoutColor, ) } // If name is null, create default avatar with background color diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ui/viewbinder/SingleLineViewBinder.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ui/viewbinder/SingleLineViewBinder.kt index 3b0f1ee22be3..a17197c1f8ea 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ui/viewbinder/SingleLineViewBinder.kt +++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ui/viewbinder/SingleLineViewBinder.kt @@ -24,14 +24,14 @@ import com.android.systemui.statusbar.notification.row.ui.viewmodel.SingleLineVi object SingleLineViewBinder { @JvmStatic fun bind(viewModel: SingleLineViewModel?, view: HybridNotificationView?) { - if (viewModel?.isConversation() == true && view is HybridConversationNotificationView) { + if (view is HybridConversationNotificationView) { if (AsyncHybridViewInflation.isUnexpectedlyInLegacyMode()) return - viewModel.conversationData?.avatar?.let { view.setAvatar(it) } + viewModel?.conversationData?.avatar?.let { view.setAvatar(it) } view.setText( - viewModel.titleText, - viewModel.contentText, - viewModel.conversationData?.conversationSenderName + viewModel?.titleText, + viewModel?.contentText, + viewModel?.conversationData?.conversationSenderName, ) } else { // bind the title and content text views @@ -39,7 +39,7 @@ object SingleLineViewBinder { bind( /* title = */ viewModel?.titleText, /* text = */ viewModel?.contentText, - /* contentView = */ null + /* contentView = */ null, ) } } diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayoutController.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayoutController.java index dad6894a43ce..ae71ca443236 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayoutController.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayoutController.java @@ -24,6 +24,7 @@ import static com.android.internal.jank.InteractionJankMonitor.CUJ_NOTIFICATION_ import static com.android.server.notification.Flags.screenshareNotificationHiding; import static com.android.systemui.Dependency.ALLOW_NOTIFICATION_LONG_PRESS_NAME; import static com.android.systemui.Flags.confineNotificationTouchToViewWidth; +import static com.android.systemui.Flags.ignoreTouchesNextToNotificationShelf; import static com.android.systemui.statusbar.StatusBarState.KEYGUARD; import static com.android.systemui.statusbar.notification.stack.NotificationStackScrollLayout.OnEmptySpaceClickListener; import static com.android.systemui.statusbar.notification.stack.NotificationStackScrollLayout.OnOverscrollTopChangedListener; @@ -604,6 +605,16 @@ public class NotificationStackScrollLayoutController implements Dumpable { true /* requireMinHeight */, false /* ignoreDecors */, !confineNotificationTouchToViewWidth() /* ignoreWidth */); + + // Verify the MotionEvent x,y are actually inside the touch area of the shelf, + // since the shelf may be animated down to a collapsed size on keyguard. + if (ignoreTouchesNextToNotificationShelf()) { + if (child instanceof NotificationShelf shelf) { + if (!NotificationSwipeHelper.isTouchInView(ev, shelf)) { + return null; + } + } + } if (child instanceof ExpandableNotificationRow row) { ExpandableNotificationRow parent = row.getNotificationParent(); if (parent != null && parent.areChildrenExpanded() diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationSwipeHelper.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationSwipeHelper.java index 7e327e66982c..0e94ca351835 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationSwipeHelper.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationSwipeHelper.java @@ -18,6 +18,7 @@ package com.android.systemui.statusbar.notification.stack; import static com.android.internal.jank.InteractionJankMonitor.CUJ_NOTIFICATION_SHADE_ROW_SWIPE; +import static com.android.systemui.Flags.ignoreTouchesNextToNotificationShelf; import android.animation.Animator; import android.animation.AnimatorListenerAdapter; @@ -39,6 +40,7 @@ import com.android.systemui.flags.FeatureFlags; import com.android.systemui.plugins.FalsingManager; import com.android.systemui.plugins.statusbar.NotificationMenuRowPlugin; import com.android.systemui.plugins.statusbar.NotificationSwipeActionHelper; +import com.android.systemui.statusbar.NotificationShelf; import com.android.systemui.statusbar.notification.SourceType; import com.android.systemui.statusbar.notification.row.ExpandableNotificationRow; import com.android.systemui.statusbar.notification.row.ExpandableView; @@ -503,13 +505,21 @@ class NotificationSwipeHelper extends SwipeHelper implements NotificationSwipeAc final int height = (view instanceof ExpandableView) ? ((ExpandableView) view).getActualHeight() : view.getHeight(); + final int width; + if (ignoreTouchesNextToNotificationShelf()) { + width = (view instanceof NotificationShelf) + ? ((NotificationShelf) view).getActualWidth() + : view.getWidth(); + } else { + width = view.getWidth(); + } final int rx = (int) ev.getRawX(); final int ry = (int) ev.getRawY(); int[] temp = new int[2]; view.getLocationOnScreen(temp); final int x = temp[0]; final int y = temp[1]; - Rect rect = new Rect(x, y, x + view.getWidth(), y + height); + Rect rect = new Rect(x, y, x + width, y + height); boolean ret = rect.contains(rx, ry); return ret; } diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManager.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManager.java index 1ea26e5727ac..6fde603af4c6 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManager.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManager.java @@ -528,6 +528,7 @@ public class StatusBarKeyguardViewManager implements RemoteInputController.Callb this::consumeKeyguardAuthenticatedBiometricsHandled ); } else { + // Collector that keeps the AlternateBouncerInteractor#canShowAlternateBouncer flow hot. mListenForCanShowAlternateBouncer = mJavaAdapter.alwaysCollectFlow( mAlternateBouncerInteractor.getCanShowAlternateBouncer(), this::consumeCanShowAlternateBouncer @@ -576,8 +577,17 @@ public class StatusBarKeyguardViewManager implements RemoteInputController.Callb } private void consumeCanShowAlternateBouncer(boolean canShow) { - // do nothing, we only are registering for the flow to ensure that there's at least - // one subscriber that will update AlternateBouncerInteractor.canShowAlternateBouncer.value + // Hack: this is required to fix issues where + // KeyguardBouncerRepository#alternateBouncerVisible state is incorrectly set and then never + // reset. This is caused by usages of show()/forceShow() that only read this flow to set the + // alternate bouncer visible state, if there is a race condition between when that flow + // changes to false and when the read happens, the flow will be set to an incorrect value + // and not reset on time. + if (!canShow) { + Log.d(TAG, "canShowAlternateBouncer turned false, maybe try hiding the alternate " + + "bouncer if it is already visible"); + mAlternateBouncerInteractor.maybeHide(); + } } /** Register a callback, to be invoked by the Predictive Back system. */ diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/SingleLineViewBinderTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/SingleLineViewBinderTest.kt index 6b3fb5b4a2eb..503fa789cb80 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/SingleLineViewBinderTest.kt +++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/SingleLineViewBinderTest.kt @@ -29,12 +29,13 @@ import com.android.systemui.statusbar.notification.row.SingleLineViewInflater.in import com.android.systemui.statusbar.notification.row.SingleLineViewInflater.inflatePublicSingleLineView import com.android.systemui.statusbar.notification.row.shared.AsyncHybridViewInflation import com.android.systemui.statusbar.notification.row.ui.viewbinder.SingleLineViewBinder -import com.android.systemui.util.mockito.mock import kotlin.test.assertEquals import kotlin.test.assertNotNull +import kotlin.test.assertNull import org.junit.Before import org.junit.Test import org.junit.runner.RunWith +import org.mockito.kotlin.mock @SmallTest @RunWith(AndroidJUnit4::class) @@ -69,7 +70,7 @@ class SingleLineViewBinderTest : SysuiTestCase() { reinflateFlags = FLAG_CONTENT_VIEW_SINGLE_LINE, entry = row.entry, context = context, - logger = mock() + logger = mock(), ) val publicView = @@ -78,7 +79,7 @@ class SingleLineViewBinderTest : SysuiTestCase() { reinflateFlags = FLAG_CONTENT_VIEW_PUBLIC_SINGLE_LINE, entry = row.entry, context = context, - logger = mock() + logger = mock(), ) assertNotNull(publicView) @@ -114,7 +115,7 @@ class SingleLineViewBinderTest : SysuiTestCase() { .addMessage( "How about lunch?", System.currentTimeMillis(), - Person.Builder().setName("user2").build() + Person.Builder().setName("user2").build(), ) .setGroupConversation(true) notificationBuilder.setStyle(style).setShortcutId(SHORTCUT_ID) @@ -127,7 +128,7 @@ class SingleLineViewBinderTest : SysuiTestCase() { reinflateFlags = FLAG_CONTENT_VIEW_SINGLE_LINE, entry = row.entry, context = context, - logger = mock() + logger = mock(), ) as HybridConversationNotificationView @@ -137,7 +138,7 @@ class SingleLineViewBinderTest : SysuiTestCase() { reinflateFlags = FLAG_CONTENT_VIEW_PUBLIC_SINGLE_LINE, entry = row.entry, context = context, - logger = mock() + logger = mock(), ) as HybridConversationNotificationView assertNotNull(publicView) @@ -150,10 +151,7 @@ class SingleLineViewBinderTest : SysuiTestCase() { systemUiContext = context, ) // WHEN: binds the view - SingleLineViewBinder.bind( - viewModel, - view, - ) + SingleLineViewBinder.bind(viewModel, view) // THEN: the single-line conversation view should be bound with view model's corresponding // fields @@ -161,10 +159,55 @@ class SingleLineViewBinderTest : SysuiTestCase() { assertEquals(viewModel.contentText, view.textView.text) assertEquals( viewModel.conversationData?.conversationSenderName, - view.conversationSenderNameView.text + view.conversationSenderNameView.text, ) } + @Test + @EnableFlags(AsyncHybridViewInflation.FLAG_NAME) + fun bindConversationSingleLineView_nonConversationViewModel() { + // GIVEN: a ConversationSingleLineView, and a nonConversationViewModel + val style = Notification.BigTextStyle().bigText(CONTENT_TEXT) + notificationBuilder.setStyle(style) + val notification = notificationBuilder.build() + val row: ExpandableNotificationRow = helper.createRow(notification) + + val view = + inflatePrivateSingleLineView( + isConversation = true, + reinflateFlags = FLAG_CONTENT_VIEW_SINGLE_LINE, + entry = row.entry, + context = context, + logger = mock(), + ) + + val publicView = + inflatePublicSingleLineView( + isConversation = true, + reinflateFlags = FLAG_CONTENT_VIEW_PUBLIC_SINGLE_LINE, + entry = row.entry, + context = context, + logger = mock(), + ) + assertNotNull(publicView) + + val viewModel = + SingleLineViewInflater.inflateSingleLineViewModel( + notification = notification, + messagingStyle = null, + builder = notificationBuilder, + systemUiContext = context, + ) + // WHEN: binds the view with the view model + SingleLineViewBinder.bind(viewModel, view) + + // THEN: the single-line view should be bound with view model's corresponding + // fields as a normal non-conversation single-line view + assertEquals(viewModel.titleText, view?.titleView?.text) + assertEquals(viewModel.contentText, view?.textView?.text) + assertNull(viewModel.conversationData) + } + private companion object { const val CHANNEL_ID = "CHANNEL_ID" const val CONTENT_TITLE = "A Cool New Feature" diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/NotificationSwipeHelperTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/NotificationSwipeHelperTest.java index 95db95cd288b..789701f5e4b0 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/NotificationSwipeHelperTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/NotificationSwipeHelperTest.java @@ -13,6 +13,8 @@ package com.android.systemui.statusbar.notification.stack; +import static com.android.systemui.Flags.FLAG_IGNORE_TOUCHES_NEXT_TO_NOTIFICATION_SHELF; + import static junit.framework.Assert.assertEquals; import static junit.framework.Assert.assertFalse; import static junit.framework.Assert.assertTrue; @@ -36,6 +38,7 @@ import static org.mockito.Mockito.when; import android.animation.Animator; import android.animation.ValueAnimator.AnimatorUpdateListener; import android.os.Handler; +import android.platform.test.annotations.DisableFlags; import android.platform.test.annotations.EnableFlags; import android.service.notification.StatusBarNotification; import android.testing.TestableLooper; @@ -52,6 +55,7 @@ import com.android.systemui.flags.FakeFeatureFlags; import com.android.systemui.flags.FeatureFlags; import com.android.systemui.plugins.statusbar.NotificationMenuRowPlugin; import com.android.systemui.plugins.statusbar.NotificationSwipeActionHelper.SnoozeOption; +import com.android.systemui.statusbar.NotificationShelf; import com.android.systemui.statusbar.notification.row.ExpandableNotificationRow; import com.android.systemui.statusbar.notification.shared.NotificationContentAlphaOptimization; @@ -85,6 +89,7 @@ public class NotificationSwipeHelperTest extends SysuiTestCase { private NotificationMenuRowPlugin mMenuRow; private Handler mHandler; private ExpandableNotificationRow mNotificationRow; + private NotificationShelf mShelf; private Runnable mFalsingCheck; private final FeatureFlags mFeatureFlags = new FakeFeatureFlags(); @@ -111,6 +116,7 @@ public class NotificationSwipeHelperTest extends SysuiTestCase { mEvent = mock(MotionEvent.class); mMenuRow = mock(NotificationMenuRowPlugin.class); mNotificationRow = mock(ExpandableNotificationRow.class); + mShelf = mock(NotificationShelf.class); mHandler = mock(Handler.class); mFalsingCheck = mock(Runnable.class); } @@ -665,6 +671,54 @@ public class NotificationSwipeHelperTest extends SysuiTestCase { } @Test + @EnableFlags(FLAG_IGNORE_TOUCHES_NEXT_TO_NOTIFICATION_SHELF) + public void testIsTouchInView_notificationShelf_flagEnabled() { + doReturn(500).when(mShelf).getWidth(); + doReturn(FAKE_ROW_WIDTH).when(mShelf).getActualWidth(); + doReturn(FAKE_ROW_HEIGHT).when(mShelf).getHeight(); + doReturn(FAKE_ROW_HEIGHT).when(mShelf).getActualHeight(); + + Answer answer = (Answer) invocation -> { + int[] arr = invocation.getArgument(0); + arr[0] = 0; + arr[1] = 0; + return null; + }; + + doReturn(5f).when(mEvent).getRawX(); + doReturn(10f).when(mEvent).getRawY(); + doAnswer(answer).when(mShelf).getLocationOnScreen(any()); + assertTrue("Touch is within the view", mSwipeHelper.isTouchInView(mEvent, mShelf)); + + doReturn(50f).when(mEvent).getRawX(); + assertFalse("Touch is not within the view", mSwipeHelper.isTouchInView(mEvent, mShelf)); + } + + @Test + @DisableFlags(FLAG_IGNORE_TOUCHES_NEXT_TO_NOTIFICATION_SHELF) + public void testIsTouchInView_notificationShelf_flagDisabled() { + doReturn(500).when(mShelf).getWidth(); + doReturn(FAKE_ROW_WIDTH).when(mShelf).getActualWidth(); + doReturn(FAKE_ROW_HEIGHT).when(mShelf).getHeight(); + doReturn(FAKE_ROW_HEIGHT).when(mShelf).getActualHeight(); + + Answer answer = (Answer) invocation -> { + int[] arr = invocation.getArgument(0); + arr[0] = 0; + arr[1] = 0; + return null; + }; + + doReturn(5f).when(mEvent).getRawX(); + doReturn(10f).when(mEvent).getRawY(); + doAnswer(answer).when(mShelf).getLocationOnScreen(any()); + assertTrue("Touch is within the view", mSwipeHelper.isTouchInView(mEvent, mShelf)); + + doReturn(50f).when(mEvent).getRawX(); + assertTrue("Touch is within the view", mSwipeHelper.isTouchInView(mEvent, mShelf)); + } + + @Test public void testContentAlphaRemainsUnchangedWhenNotificationIsNotDismissible() { doReturn(FAKE_ROW_WIDTH).when(mNotificationRow).getMeasuredWidth(); diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/ui/viewmodel/DeviceEntryBackgroundViewModelKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/ui/viewmodel/DeviceEntryBackgroundViewModelKosmos.kt new file mode 100644 index 000000000000..09836ed46817 --- /dev/null +++ b/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/ui/viewmodel/DeviceEntryBackgroundViewModelKosmos.kt @@ -0,0 +1,52 @@ +/* + * Copyright (C) 2024 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.systemui.keyguard.ui.viewmodel + +import android.content.applicationContext +import com.android.systemui.common.ui.domain.interactor.configurationInteractor +import com.android.systemui.keyguard.domain.interactor.keyguardTransitionInteractor +import com.android.systemui.kosmos.Kosmos +import com.android.systemui.kosmos.Kosmos.Fixture +import kotlinx.coroutines.ExperimentalCoroutinesApi + +@ExperimentalCoroutinesApi +val Kosmos.deviceEntryBackgroundViewModel by Fixture { + DeviceEntryBackgroundViewModel( + context = applicationContext, + deviceEntryIconViewModel = deviceEntryIconViewModel, + configurationInteractor = configurationInteractor, + keyguardTransitionInteractor = keyguardTransitionInteractor, + alternateBouncerToAodTransitionViewModel = alternateBouncerToAodTransitionViewModel, + alternateBouncerToDozingTransitionViewModel = alternateBouncerToDozingTransitionViewModel, + aodToLockscreenTransitionViewModel = aodToLockscreenTransitionViewModel, + dozingToLockscreenTransitionViewModel = dozingToLockscreenTransitionViewModel, + dreamingToAodTransitionViewModel = dreamingToAodTransitionViewModel, + dreamingToLockscreenTransitionViewModel = dreamingToLockscreenTransitionViewModel, + goneToAodTransitionViewModel = goneToAodTransitionViewModel, + goneToDozingTransitionViewModel = goneToDozingTransitionViewModel, + goneToLockscreenTransitionViewModel = goneToLockscreenTransitionViewModel, + lockscreenToAodTransitionViewModel = lockscreenToAodTransitionViewModel, + occludedToAodTransitionViewModel = occludedToAodTransitionViewModel, + occludedToDozingTransitionViewModel = occludedToDozingTransitionViewModel, + occludedToLockscreenTransitionViewModel = occludedToLockscreenTransitionViewModel, + primaryBouncerToAodTransitionViewModel = primaryBouncerToAodTransitionViewModel, + primaryBouncerToDozingTransitionViewModel = primaryBouncerToDozingTransitionViewModel, + primaryBouncerToLockscreenTransitionViewModel = + primaryBouncerToLockscreenTransitionViewModel, + lockscreenToDozingTransitionViewModel = lockscreenToDozingTransitionViewModel, + ) +} diff --git a/ravenwood/Android.bp b/ravenwood/Android.bp index 66c8d0fa32f9..59043a8356ae 100644 --- a/ravenwood/Android.bp +++ b/ravenwood/Android.bp @@ -182,21 +182,6 @@ java_device_for_host { visibility: [":__subpackages__"], } -// Separated out from ravenwood-junit-impl since it needs to compile -// against `module_current` -java_library { - name: "ravenwood-junit-impl-flag", - srcs: [ - "junit-flag-src/**/*.java", - ], - sdk_version: "module_current", - libs: [ - "junit", - "flag-junit", - ], - visibility: ["//visibility:public"], -} - // Carefully compiles against only module_current to support tests that // want to verify they're unbundled. The "impl" library above is what // ships inside the Ravenwood environment to actually drive any API @@ -651,7 +636,6 @@ android_ravenwood_libgroup { "flag-junit", "ravenwood-framework", "ravenwood-junit-impl", - "ravenwood-junit-impl-flag", "mockito-ravenwood-prebuilt", "inline-mockito-ravenwood-prebuilt", diff --git a/ravenwood/junit-flag-src/android/platform/test/flag/junit/RavenwoodFlagsValueProvider.java b/ravenwood/junit-flag-src/android/platform/test/flag/junit/RavenwoodFlagsValueProvider.java deleted file mode 100644 index 9d6277473298..000000000000 --- a/ravenwood/junit-flag-src/android/platform/test/flag/junit/RavenwoodFlagsValueProvider.java +++ /dev/null @@ -1,54 +0,0 @@ -/* - * Copyright (C) 2024 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package android.platform.test.flag.junit; - -import android.platform.test.flag.junit.CheckFlagsRule; -import android.platform.test.flag.junit.IFlagsValueProvider; - -/** - * Offer to create {@link CheckFlagsRule} instances that are useful on the Ravenwood deviceless - * testing environment. - * - * At the moment, default flag values are not available on Ravenwood, so the only options offered - * here are "all-on" and "all-off" options. Tests that want to exercise specific flag states should - * use {@link android.platform.test.flag.junit.SetFlagsRule}. - */ -public class RavenwoodFlagsValueProvider { - /** - * Create a {@link CheckFlagsRule} instance where flags are in an "all-on" state. - */ - public static CheckFlagsRule createAllOnCheckFlagsRule() { - return new CheckFlagsRule(new IFlagsValueProvider() { - @Override - public boolean getBoolean(String flag) { - return true; - } - }); - } - - /** - * Create a {@link CheckFlagsRule} instance where flags are in an "all-off" state. - */ - public static CheckFlagsRule createAllOffCheckFlagsRule() { - return new CheckFlagsRule(new IFlagsValueProvider() { - @Override - public boolean getBoolean(String flag) { - return false; - } - }); - } -} diff --git a/ravenwood/junit-impl-src/android/platform/test/ravenwood/RavenwoodAwareTestRunner.java b/ravenwood/junit-impl-src/android/platform/test/ravenwood/RavenwoodAwareTestRunner.java index 9644a52a749e..3ebef02284d6 100644 --- a/ravenwood/junit-impl-src/android/platform/test/ravenwood/RavenwoodAwareTestRunner.java +++ b/ravenwood/junit-impl-src/android/platform/test/ravenwood/RavenwoodAwareTestRunner.java @@ -129,7 +129,7 @@ public final class RavenwoodAwareTestRunner extends RavenwoodAwareTestRunnerBase mTestClass = new TestClass(testClass); - Log.v(TAG, "RavenwoodAwareTestRunner starting for " + testClass.getCanonicalName()); + Log.v(TAG, "RavenwoodAwareTestRunner initializing for " + testClass.getCanonicalName()); // Hook point to allow more customization. runAnnotatedMethodsOnRavenwood(RavenwoodTestRunnerInitializing.class, null); @@ -146,7 +146,9 @@ public final class RavenwoodAwareTestRunner extends RavenwoodAwareTestRunnerBase private void runAnnotatedMethodsOnRavenwood(Class<? extends Annotation> annotationClass, Object instance) { - Log.v(TAG, "runAnnotatedMethodsOnRavenwood() " + annotationClass.getName()); + if (RAVENWOOD_VERBOSE_LOGGING) { + Log.v(TAG, "runAnnotatedMethodsOnRavenwood() " + annotationClass.getName()); + } for (var method : mTestClass.getAnnotatedMethods(annotationClass)) { ensureIsPublicVoidMethod(method.getMethod(), /* isStatic=*/ instance == null); @@ -169,12 +171,14 @@ public final class RavenwoodAwareTestRunner extends RavenwoodAwareTestRunnerBase RavenwoodTestStats.getInstance().attachToRunNotifier(notifier); if (mRealRunner instanceof ClassSkippingTestRunner) { - Log.i(TAG, "onClassSkipped: description=" + description); + Log.v(TAG, "onClassSkipped: description=" + description); mRealRunner.run(notifier); return; } - Log.v(TAG, "Starting " + mTestJavaClass.getCanonicalName()); + if (RAVENWOOD_VERBOSE_LOGGING) { + Log.v(TAG, "Running " + mTestJavaClass.getCanonicalName()); + } if (RAVENWOOD_VERBOSE_LOGGING) { dumpDescription(description); } diff --git a/ravenwood/junit-impl-src/android/platform/test/ravenwood/RavenwoodRunnerState.java b/ravenwood/junit-impl-src/android/platform/test/ravenwood/RavenwoodRunnerState.java index a5d0bfd51a0f..70bc52bdaa12 100644 --- a/ravenwood/junit-impl-src/android/platform/test/ravenwood/RavenwoodRunnerState.java +++ b/ravenwood/junit-impl-src/android/platform/test/ravenwood/RavenwoodRunnerState.java @@ -15,6 +15,8 @@ */ package android.platform.test.ravenwood; +import static com.android.ravenwood.common.RavenwoodCommonUtils.RAVENWOOD_VERBOSE_LOGGING; + import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertNotNull; import static org.junit.Assert.assertTrue; @@ -59,16 +61,22 @@ public final class RavenwoodRunnerState { private Description mMethodDescription; public void enterTestRunner() { - Log.i(TAG, "enterTestRunner: " + mRunner); + if (RAVENWOOD_VERBOSE_LOGGING) { + Log.v(TAG, "enterTestRunner: " + mRunner); + } RavenwoodRuntimeEnvironmentController.initForRunner(); } public void enterTestClass() { - Log.i(TAG, "enterTestClass: " + mRunner.mTestJavaClass.getName()); + if (RAVENWOOD_VERBOSE_LOGGING) { + Log.v(TAG, "enterTestClass: " + mRunner.mTestJavaClass.getName()); + } } public void exitTestClass() { - Log.i(TAG, "exitTestClass: " + mRunner.mTestJavaClass.getName()); + if (RAVENWOOD_VERBOSE_LOGGING) { + Log.v(TAG, "exitTestClass: " + mRunner.mTestJavaClass.getName()); + } assertTrue(RAVENWOOD_RULE_ERROR, sActiveProperties.isEmpty()); RavenwoodRuntimeEnvironmentController.exitTestClass(); } diff --git a/ravenwood/junit-impl-src/android/platform/test/ravenwood/RavenwoodRuntimeEnvironmentController.java b/ravenwood/junit-impl-src/android/platform/test/ravenwood/RavenwoodRuntimeEnvironmentController.java index 930914f586eb..3cb6c5a6bd16 100644 --- a/ravenwood/junit-impl-src/android/platform/test/ravenwood/RavenwoodRuntimeEnvironmentController.java +++ b/ravenwood/junit-impl-src/android/platform/test/ravenwood/RavenwoodRuntimeEnvironmentController.java @@ -552,7 +552,7 @@ public class RavenwoodRuntimeEnvironmentController { } private static void dumpCommandLineArgs() { - Log.i(TAG, "JVM arguments:"); + Log.v(TAG, "JVM arguments:"); // Note, we use the wrapper in JUnit4, not the actual class ( // java.lang.management.ManagementFactory), because we can't see the later at the build @@ -561,7 +561,7 @@ public class RavenwoodRuntimeEnvironmentController { var args = ManagementFactory.getRuntimeMXBean().getInputArguments(); for (var arg : args) { - Log.i(TAG, " " + arg); + Log.v(TAG, " " + arg); } } } diff --git a/ravenwood/junit-impl-src/android/platform/test/ravenwood/RavenwoodSystemProperties.java b/ravenwood/junit-impl-src/android/platform/test/ravenwood/RavenwoodSystemProperties.java index fac07910be11..70c161c1f19a 100644 --- a/ravenwood/junit-impl-src/android/platform/test/ravenwood/RavenwoodSystemProperties.java +++ b/ravenwood/junit-impl-src/android/platform/test/ravenwood/RavenwoodSystemProperties.java @@ -84,7 +84,7 @@ public class RavenwoodSystemProperties { var ravenwoodProps = readProperties(path + RAVENWOOD_BUILD_PROP); var deviceProps = readProperties(path + DEVICE_BUILD_PROP); - Log.i(TAG, "Default system properties:"); + Log.v(TAG, "Default system properties:"); ravenwoodProps.forEach((key, origValue) -> { final String value; @@ -100,7 +100,7 @@ public class RavenwoodSystemProperties { } else { value = origValue; } - Log.i(TAG, key + "=" + value); + Log.v(TAG, key + "=" + value); sDefaultValues.put(key, value); }); diff --git a/ravenwood/junit-src/android/platform/test/ravenwood/RavenwoodAwareTestRunnerBase.java b/ravenwood/junit-src/android/platform/test/ravenwood/RavenwoodAwareTestRunnerBase.java index f3688d664142..359210582ba5 100644 --- a/ravenwood/junit-src/android/platform/test/ravenwood/RavenwoodAwareTestRunnerBase.java +++ b/ravenwood/junit-src/android/platform/test/ravenwood/RavenwoodAwareTestRunnerBase.java @@ -15,6 +15,8 @@ */ package android.platform.test.ravenwood; +import static com.android.ravenwood.common.RavenwoodCommonUtils.RAVENWOOD_VERBOSE_LOGGING; + import android.platform.test.annotations.internal.InnerRunner; import android.util.Log; @@ -53,7 +55,9 @@ abstract class RavenwoodAwareTestRunnerBase extends Runner implements Filterable } try { - Log.i(TAG, "Initializing the inner runner: " + runnerClass); + if (RAVENWOOD_VERBOSE_LOGGING) { + Log.v(TAG, "Initializing the inner runner: " + runnerClass); + } try { return runnerClass.getConstructor(Class.class) .newInstance(testClass.getJavaClass()); diff --git a/ravenwood/runtime-jni/ravenwood_initializer.cpp b/ravenwood/runtime-jni/ravenwood_initializer.cpp index dbbc3453b2f1..391c5d56b212 100644 --- a/ravenwood/runtime-jni/ravenwood_initializer.cpp +++ b/ravenwood/runtime-jni/ravenwood_initializer.cpp @@ -140,7 +140,7 @@ static void check_system_property_access(const char* key, bool write) { if (gVM != nullptr && gRunnerState != nullptr) { JNIEnv* env; if (gVM->GetEnv((void**)&env, JNI_VERSION_1_4) >= 0) { - ALOGI("%s access to system property '%s'", write ? "Write" : "Read", key); + ALOGV("%s access to system property '%s'", write ? "Write" : "Read", key); env->CallStaticVoidMethod(gRunnerState, gCheckSystemPropertyAccess, env->NewStringUTF(key), write ? JNI_TRUE : JNI_FALSE); return; @@ -208,7 +208,7 @@ static const JNINativeMethod sMethods[] = { }; extern "C" jint JNI_OnLoad(JavaVM* vm, void* /* reserved */) { - ALOGI("%s: JNI_OnLoad", __FILE__); + ALOGV("%s: JNI_OnLoad", __FILE__); maybeRedirectLog(); diff --git a/ravenwood/runtime-jni/ravenwood_runtime.cpp b/ravenwood/runtime-jni/ravenwood_runtime.cpp index bab4c7e0fd14..8d8ed7119e84 100644 --- a/ravenwood/runtime-jni/ravenwood_runtime.cpp +++ b/ravenwood/runtime-jni/ravenwood_runtime.cpp @@ -204,7 +204,7 @@ static const JNINativeMethod sMethods[] = }; extern "C" jint JNI_OnLoad(JavaVM* vm, void* /* reserved */) { - ALOGI("%s: JNI_OnLoad", __FILE__); + ALOGV("%s: JNI_OnLoad", __FILE__); JNIEnv* env = GetJNIEnvOrDie(vm); g_StructStat = FindGlobalClassOrDie(env, "android/system/StructStat"); diff --git a/services/accessibility/java/com/android/server/accessibility/AccessibilityManagerService.java b/services/accessibility/java/com/android/server/accessibility/AccessibilityManagerService.java index 7580b697b516..49f15e46894d 100644 --- a/services/accessibility/java/com/android/server/accessibility/AccessibilityManagerService.java +++ b/services/accessibility/java/com/android/server/accessibility/AccessibilityManagerService.java @@ -3653,6 +3653,12 @@ public class AccessibilityManagerService extends IAccessibilityManager.Stub return; } + // Magnification connection should not be requested for visible background users. + // (b/332222893) + if (mUmi.isVisibleBackgroundFullUser(userState.mUserId)) { + return; + } + final boolean shortcutEnabled = (userState.isShortcutMagnificationEnabledLocked() || userState.isMagnificationSingleFingerTripleTapEnabledLocked() || (Flags.enableMagnificationMultipleFingerMultipleTapGesture() diff --git a/services/accessibility/java/com/android/server/accessibility/magnification/MagnificationConnectionManager.java b/services/accessibility/java/com/android/server/accessibility/magnification/MagnificationConnectionManager.java index 19e3e690924e..fe06406e580a 100644 --- a/services/accessibility/java/com/android/server/accessibility/magnification/MagnificationConnectionManager.java +++ b/services/accessibility/java/com/android/server/accessibility/magnification/MagnificationConnectionManager.java @@ -19,6 +19,7 @@ package com.android.server.accessibility.magnification; import static android.accessibilityservice.AccessibilityTrace.FLAGS_MAGNIFICATION_CONNECTION; import static android.accessibilityservice.AccessibilityTrace.FLAGS_MAGNIFICATION_CONNECTION_CALLBACK; import static android.os.Build.HW_TIMEOUT_MULTIPLIER; +import static android.os.UserHandle.getCallingUserId; import static android.view.accessibility.MagnificationAnimationCallback.STUB_ANIMATION_CALLBACK; import static com.android.server.accessibility.AccessibilityManagerService.INVALID_SERVICE_ID; @@ -54,6 +55,7 @@ import com.android.internal.annotations.GuardedBy; import com.android.internal.annotations.VisibleForTesting; import com.android.server.LocalServices; import com.android.server.accessibility.AccessibilityTraceManager; +import com.android.server.pm.UserManagerInternal; import com.android.server.statusbar.StatusBarManagerInternal; import com.android.server.wm.WindowManagerInternal; @@ -209,6 +211,7 @@ public class MagnificationConnectionManager implements private final Callback mCallback; private final AccessibilityTraceManager mTrace; private final MagnificationScaleProvider mScaleProvider; + private final UserManagerInternal mUserManagerInternal; public MagnificationConnectionManager(Context context, Object lock, @NonNull Callback callback, AccessibilityTraceManager trace, MagnificationScaleProvider scaleProvider) { @@ -217,6 +220,7 @@ public class MagnificationConnectionManager implements mCallback = callback; mTrace = trace; mScaleProvider = scaleProvider; + mUserManagerInternal = LocalServices.getService(UserManagerInternal.class); } /** @@ -280,12 +284,18 @@ public class MagnificationConnectionManager implements * Requests {@link IMagnificationConnection} through * {@link StatusBarManagerInternal#requestMagnificationConnection(boolean)} and * destroys all window magnifications if necessary. + * NOTE: Currently, this is not allowed to call from visible background users.(b/332222893) * * @param connect {@code true} if needs connection, otherwise set the connection to null and * destroy all window magnifications. * @return {@code true} if {@link IMagnificationConnection} state is going to change. */ public boolean requestConnection(boolean connect) { + final int callingUserId = getCallingUserId(); + if (mUserManagerInternal.isVisibleBackgroundFullUser(callingUserId)) { + throw new SecurityException("Visible background user(u" + callingUserId + + " is not permitted to request magnification connection."); + } if (DBG) { Slog.d(TAG, "requestConnection :" + connect); } diff --git a/services/autofill/java/com/android/server/autofill/AutofillManagerServiceImpl.java b/services/autofill/java/com/android/server/autofill/AutofillManagerServiceImpl.java index c9f892907b59..b52c65054e51 100644 --- a/services/autofill/java/com/android/server/autofill/AutofillManagerServiceImpl.java +++ b/services/autofill/java/com/android/server/autofill/AutofillManagerServiceImpl.java @@ -92,6 +92,7 @@ import com.android.server.autofill.ui.AutoFillUI; import com.android.server.contentcapture.ContentCaptureManagerInternal; import com.android.server.infra.AbstractPerUserSystemService; import com.android.server.inputmethod.InputMethodManagerInternal; +import com.android.server.pm.UserManagerInternal; import com.android.server.wm.ActivityTaskManagerInternal; import java.io.PrintWriter; @@ -192,6 +193,8 @@ final class AutofillManagerServiceImpl private final ContentCaptureManagerInternal mContentCaptureManagerInternal; + private final UserManagerInternal mUserManagerInternal; + private final DisabledInfoCache mDisabledInfoCache; AutofillManagerServiceImpl(AutofillManagerService master, Object lock, @@ -208,6 +211,7 @@ final class AutofillManagerServiceImpl mInputMethodManagerInternal = LocalServices.getService(InputMethodManagerInternal.class); mContentCaptureManagerInternal = LocalServices.getService( ContentCaptureManagerInternal.class); + mUserManagerInternal = LocalServices.getService(UserManagerInternal.class); mDisabledInfoCache = disableCache; updateLocked(disabled); } @@ -379,6 +383,13 @@ final class AutofillManagerServiceImpl return 0; } + // TODO(b/376482880): remove this check once autofill service supports visible + // background users. + if (mUserManagerInternal.isVisibleBackgroundFullUser(mUserId)) { + Slog.d(TAG, "Currently, autofill service does not support visible background users."); + return 0; + } + if (!forAugmentedAutofillOnly && isAutofillDisabledLocked(clientActivity)) { // Standard autofill is enabled, but service disabled autofill for this activity; that // means no session, unless the activity is allowlisted for augmented autofill diff --git a/services/core/java/com/android/server/UiModeManagerService.java b/services/core/java/com/android/server/UiModeManagerService.java index f32031dec43c..f2069d011958 100644 --- a/services/core/java/com/android/server/UiModeManagerService.java +++ b/services/core/java/com/android/server/UiModeManagerService.java @@ -427,6 +427,11 @@ final class UiModeManagerService extends SystemService { mDreamsDisabledByAmbientModeSuppression = disabledByAmbientModeSuppression; } + @VisibleForTesting + void setCurrentUser(int currentUserId) { + mCurrentUser = currentUserId; + } + @Override public void onUserSwitching(@Nullable TargetUser from, @NonNull TargetUser to) { mCurrentUser = to.getUserIdentifier(); @@ -848,9 +853,9 @@ final class UiModeManagerService extends SystemService { throw new IllegalArgumentException("Unknown mode: " + mode); } - final int user = UserHandle.getCallingUserId(); - enforceCurrentUserIfVisibleBackgroundEnabled(user); + enforceCurrentUserIfVisibleBackgroundEnabled(mCurrentUser); + final int user = UserHandle.getCallingUserId(); final long ident = Binder.clearCallingIdentity(); try { synchronized (mLock) { @@ -913,7 +918,7 @@ final class UiModeManagerService extends SystemService { @AttentionModeThemeOverlayType int attentionModeThemeOverlayType) { setAttentionModeThemeOverlay_enforcePermission(); - enforceCurrentUserIfVisibleBackgroundEnabled(UserHandle.getCallingUserId()); + enforceCurrentUserIfVisibleBackgroundEnabled(mCurrentUser); synchronized (mLock) { if (mAttentionModeThemeOverlay != attentionModeThemeOverlayType) { @@ -1004,16 +1009,16 @@ final class UiModeManagerService extends SystemService { return false; } final int user = Binder.getCallingUserHandle().getIdentifier(); - enforceCurrentUserIfVisibleBackgroundEnabled(user); - if (user != mCurrentUser && getContext().checkCallingOrSelfPermission( android.Manifest.permission.INTERACT_ACROSS_USERS) != PackageManager.PERMISSION_GRANTED) { Slog.e(TAG, "Target user is not current user," + " INTERACT_ACROSS_USERS permission is required"); return false; - } + + enforceCurrentUserIfVisibleBackgroundEnabled(mCurrentUser); + // Store the last requested bedtime night mode state so that we don't need to notify // anyone if the user decides to switch to the night mode to bedtime. if (modeCustomType == MODE_NIGHT_CUSTOM_TYPE_BEDTIME) { @@ -1062,9 +1067,10 @@ final class UiModeManagerService extends SystemService { Slog.e(TAG, "Set custom time start, requires MODIFY_DAY_NIGHT_MODE permission"); return; } - final int user = UserHandle.getCallingUserId(); - enforceCurrentUserIfVisibleBackgroundEnabled(user); + enforceCurrentUserIfVisibleBackgroundEnabled(mCurrentUser); + + final int user = UserHandle.getCallingUserId(); final long ident = Binder.clearCallingIdentity(); try { LocalTime newTime = LocalTime.ofNanoOfDay(time * 1000); @@ -1092,9 +1098,10 @@ final class UiModeManagerService extends SystemService { Slog.e(TAG, "Set custom time end, requires MODIFY_DAY_NIGHT_MODE permission"); return; } - final int user = UserHandle.getCallingUserId(); - enforceCurrentUserIfVisibleBackgroundEnabled(user); + enforceCurrentUserIfVisibleBackgroundEnabled(mCurrentUser); + + final int user = UserHandle.getCallingUserId(); final long ident = Binder.clearCallingIdentity(); try { LocalTime newTime = LocalTime.ofNanoOfDay(time * 1000); @@ -1115,7 +1122,7 @@ final class UiModeManagerService extends SystemService { assertLegit(callingPackage); assertSingleProjectionType(projectionType); enforceProjectionTypePermissions(projectionType); - enforceCurrentUserIfVisibleBackgroundEnabled(getCallingUserId()); + enforceCurrentUserIfVisibleBackgroundEnabled(mCurrentUser); synchronized (mLock) { if (mProjectionHolders == null) { @@ -1161,7 +1168,7 @@ final class UiModeManagerService extends SystemService { assertLegit(callingPackage); assertSingleProjectionType(projectionType); enforceProjectionTypePermissions(projectionType); - enforceCurrentUserIfVisibleBackgroundEnabled(getCallingUserId()); + enforceCurrentUserIfVisibleBackgroundEnabled(mCurrentUser); return releaseProjectionUnchecked(projectionType, callingPackage); } @@ -1203,7 +1210,7 @@ final class UiModeManagerService extends SystemService { return; } - enforceCurrentUserIfVisibleBackgroundEnabled(getCallingUserId()); + enforceCurrentUserIfVisibleBackgroundEnabled(mCurrentUser); synchronized (mLock) { if (mProjectionListeners == null) { diff --git a/services/core/java/com/android/server/accounts/AccountManagerService.java b/services/core/java/com/android/server/accounts/AccountManagerService.java index 88edb121c0c8..3499a3a5edde 100644 --- a/services/core/java/com/android/server/accounts/AccountManagerService.java +++ b/services/core/java/com/android/server/accounts/AccountManagerService.java @@ -1773,8 +1773,7 @@ public class AccountManagerService // Create a Session for the target user and pass in the bundle completeCloningAccount(response, result, account, toAccounts, userFrom); } else { - // Bundle format is not defined. - super.onResultSkipSanitization(result); + super.onResult(result); } } }.bind(); @@ -1861,8 +1860,7 @@ public class AccountManagerService // account to avoid retries? // TODO: what we do with the visibility? - // Bundle format is not defined. - super.onResultSkipSanitization(result); + super.onResult(result); } @Override @@ -2108,7 +2106,6 @@ public class AccountManagerService @Override public void onResult(Bundle result) { Bundle.setDefusable(result, true); - result = sanitizeBundle(result); IAccountManagerResponse response = getResponseAndClose(); if (response != null) { try { @@ -2462,7 +2459,6 @@ public class AccountManagerService @Override public void onResult(Bundle result) { Bundle.setDefusable(result, true); - result = sanitizeBundle(result); if (result != null && result.containsKey(AccountManager.KEY_BOOLEAN_RESULT) && !result.containsKey(AccountManager.KEY_INTENT)) { final boolean removalAllowed = result.getBoolean(AccountManager.KEY_BOOLEAN_RESULT); @@ -2977,7 +2973,6 @@ public class AccountManagerService @Override public void onResult(Bundle result) { Bundle.setDefusable(result, true); - result = sanitizeBundle(result); if (result != null) { String label = result.getString(AccountManager.KEY_AUTH_TOKEN_LABEL); Bundle bundle = new Bundle(); @@ -3155,7 +3150,6 @@ public class AccountManagerService @Override public void onResult(Bundle result) { Bundle.setDefusable(result, true); - result = sanitizeBundle(result); if (result != null) { if (result.containsKey(AccountManager.KEY_AUTH_TOKEN_LABEL)) { Intent intent = newGrantCredentialsPermissionIntent( @@ -3627,12 +3621,6 @@ public class AccountManagerService @Override public void onResult(Bundle result) { Bundle.setDefusable(result, true); - Bundle sessionBundle = null; - if (result != null) { - // Session bundle will be removed from result. - sessionBundle = result.getBundle(AccountManager.KEY_ACCOUNT_SESSION_BUNDLE); - } - result = sanitizeBundle(result); mNumResults++; Intent intent = null; if (result != null) { @@ -3694,6 +3682,7 @@ public class AccountManagerService // bundle contains data necessary for finishing the session // later. The session bundle will be encrypted here and // decrypted later when trying to finish the session. + Bundle sessionBundle = result.getBundle(AccountManager.KEY_ACCOUNT_SESSION_BUNDLE); if (sessionBundle != null) { String accountType = sessionBundle.getString(AccountManager.KEY_ACCOUNT_TYPE); if (TextUtils.isEmpty(accountType) @@ -4081,7 +4070,6 @@ public class AccountManagerService @Override public void onResult(Bundle result) { Bundle.setDefusable(result, true); - result = sanitizeBundle(result); IAccountManagerResponse response = getResponseAndClose(); if (response == null) { return; @@ -4395,7 +4383,6 @@ public class AccountManagerService @Override public void onResult(Bundle result) { Bundle.setDefusable(result, true); - result = sanitizeBundle(result); mNumResults++; if (result == null) { onError(AccountManager.ERROR_CODE_INVALID_RESPONSE, "null bundle"); @@ -4952,68 +4939,6 @@ public class AccountManagerService callback, resultReceiver); } - - // All keys for Strings passed from AbstractAccountAuthenticator using Bundle. - private static final String[] sStringBundleKeys = new String[] { - AccountManager.KEY_ACCOUNT_NAME, - AccountManager.KEY_ACCOUNT_TYPE, - AccountManager.KEY_AUTHTOKEN, - AccountManager.KEY_AUTH_TOKEN_LABEL, - AccountManager.KEY_ERROR_MESSAGE, - AccountManager.KEY_PASSWORD, - AccountManager.KEY_ACCOUNT_STATUS_TOKEN}; - - /** - * Keep only documented fields in a Bundle received from AbstractAccountAuthenticator. - */ - protected static Bundle sanitizeBundle(Bundle bundle) { - if (bundle == null) { - return null; - } - Bundle sanitizedBundle = new Bundle(); - Bundle.setDefusable(sanitizedBundle, true); - int updatedKeysCount = 0; - for (String stringKey : sStringBundleKeys) { - if (bundle.containsKey(stringKey)) { - String value = bundle.getString(stringKey); - sanitizedBundle.putString(stringKey, value); - updatedKeysCount++; - } - } - String key = AbstractAccountAuthenticator.KEY_CUSTOM_TOKEN_EXPIRY; - if (bundle.containsKey(key)) { - long expiryMillis = bundle.getLong(key, 0L); - sanitizedBundle.putLong(key, expiryMillis); - updatedKeysCount++; - } - key = AccountManager.KEY_BOOLEAN_RESULT; - if (bundle.containsKey(key)) { - boolean booleanResult = bundle.getBoolean(key, false); - sanitizedBundle.putBoolean(key, booleanResult); - updatedKeysCount++; - } - key = AccountManager.KEY_ERROR_CODE; - if (bundle.containsKey(key)) { - int errorCode = bundle.getInt(key, 0); - sanitizedBundle.putInt(key, errorCode); - updatedKeysCount++; - } - key = AccountManager.KEY_INTENT; - if (bundle.containsKey(key)) { - Intent intent = bundle.getParcelable(key, Intent.class); - sanitizedBundle.putParcelable(key, intent); - updatedKeysCount++; - } - if (bundle.containsKey(AccountManager.KEY_ACCOUNT_SESSION_BUNDLE)) { - // The field is not copied in sanitized bundle. - updatedKeysCount++; - } - if (updatedKeysCount != bundle.size()) { - Log.w(TAG, "Size mismatch after sanitizeBundle call."); - } - return sanitizedBundle; - } - private abstract class Session extends IAccountAuthenticatorResponse.Stub implements IBinder.DeathRecipient, ServiceConnection { private final Object mSessionLock = new Object(); @@ -5304,15 +5229,10 @@ public class AccountManagerService } } } + @Override public void onResult(Bundle result) { Bundle.setDefusable(result, true); - result = sanitizeBundle(result); - onResultSkipSanitization(result); - } - - public void onResultSkipSanitization(Bundle result) { - Bundle.setDefusable(result, true); mNumResults++; Intent intent = null; if (result != null) { diff --git a/services/core/java/com/android/server/am/ActiveServices.java b/services/core/java/com/android/server/am/ActiveServices.java index 36665240c16b..f9197e3c5c42 100644 --- a/services/core/java/com/android/server/am/ActiveServices.java +++ b/services/core/java/com/android/server/am/ActiveServices.java @@ -5077,7 +5077,10 @@ public final class ActiveServices { + " requires " + r.permission); return new ServiceLookupResult(r.permission); } else if ((Manifest.permission.BIND_HOTWORD_DETECTION_SERVICE.equals(r.permission) - || Manifest.permission.BIND_VISUAL_QUERY_DETECTION_SERVICE.equals(r.permission)) + || Manifest.permission.BIND_VISUAL_QUERY_DETECTION_SERVICE.equals(r.permission) + || Manifest.permission.BIND_WEARABLE_SENSING_SERVICE.equals(r.permission) + || Manifest.permission.BIND_ON_DEVICE_SANDBOXED_INFERENCE_SERVICE.equals( + r.permission)) && callingUid != Process.SYSTEM_UID) { // Hotword detection and visual query detection must run in its own sandbox, and we // don't even trust its enclosing application to bind to it - only the system. diff --git a/services/core/java/com/android/server/audio/AudioService.java b/services/core/java/com/android/server/audio/AudioService.java index f64a16359028..e1909d91a77d 100644 --- a/services/core/java/com/android/server/audio/AudioService.java +++ b/services/core/java/com/android/server/audio/AudioService.java @@ -1583,8 +1583,11 @@ public class AudioService extends IAudioService.Stub synchronized (mCachedAbsVolDrivingStreamsLock) { mCachedAbsVolDrivingStreams.forEach((dev, stream) -> { - mAudioSystem.setDeviceAbsoluteVolumeEnabled(dev, /*address=*/"", /*enabled=*/true, - stream); + boolean enabled = true; + if (dev == AudioSystem.DEVICE_OUT_BLUETOOTH_A2DP) { + enabled = mAvrcpAbsVolSupported; + } + mAudioSystem.setDeviceAbsoluteVolumeEnabled(dev, /*address=*/"", enabled, stream); }); } } @@ -4848,7 +4851,7 @@ public class AudioService extends IAudioService.Stub if (absDev == AudioSystem.DEVICE_OUT_BLUETOOTH_A2DP) { enabled = mAvrcpAbsVolSupported; } - if (stream != streamType) { + if (stream != streamType || !enabled) { mAudioSystem.setDeviceAbsoluteVolumeEnabled(absDev, /*address=*/"", enabled, streamType); } @@ -10354,10 +10357,10 @@ public class AudioService extends IAudioService.Stub } /*package*/ void setAvrcpAbsoluteVolumeSupported(boolean support) { - mAvrcpAbsVolSupported = support; - if (absVolumeIndexFix()) { - int a2dpDev = AudioSystem.DEVICE_OUT_BLUETOOTH_A2DP; - synchronized (mCachedAbsVolDrivingStreamsLock) { + synchronized (mCachedAbsVolDrivingStreamsLock) { + mAvrcpAbsVolSupported = support; + if (absVolumeIndexFix()) { + int a2dpDev = AudioSystem.DEVICE_OUT_BLUETOOTH_A2DP; mCachedAbsVolDrivingStreams.compute(a2dpDev, (dev, stream) -> { if (!mAvrcpAbsVolSupported) { mAudioSystem.setDeviceAbsoluteVolumeEnabled(a2dpDev, /*address=*/ @@ -12420,6 +12423,12 @@ public class AudioService extends IAudioService.Stub pw.println("\nLoudness alignment:"); mLoudnessCodecHelper.dump(pw); + pw.println("\nAbsolute voume devices:"); + synchronized (mCachedAbsVolDrivingStreamsLock) { + mCachedAbsVolDrivingStreams.forEach((dev, stream) -> pw.println( + "Device type: 0x" + Integer.toHexString(dev) + ", driving stream " + stream)); + } + mAudioSystem.dump(pw); } diff --git a/services/core/java/com/android/server/pm/PackageManagerService.java b/services/core/java/com/android/server/pm/PackageManagerService.java index 8a7dabdeceda..cc41b73fb677 100644 --- a/services/core/java/com/android/server/pm/PackageManagerService.java +++ b/services/core/java/com/android/server/pm/PackageManagerService.java @@ -3389,18 +3389,31 @@ public class PackageManagerService implements PackageSender, TestUtilityService return true; } // Does it contain a device admin for any user? - int[] users; + int[] allUsers = mUserManager.getUserIds(); + int[] targetUsers; if (userId == UserHandle.USER_ALL) { - users = mUserManager.getUserIds(); + targetUsers = allUsers; } else { - users = new int[]{userId}; + targetUsers = new int[]{userId}; } - for (int i = 0; i < users.length; ++i) { - if (dpm.packageHasActiveAdmins(packageName, users[i])) { + + for (int i = 0; i < targetUsers.length; ++i) { + if (dpm.packageHasActiveAdmins(packageName, targetUsers[i])) { return true; } - if (isDeviceManagementRoleHolder(packageName, users[i]) - && dpmi.isUserOrganizationManaged(users[i])) { + } + + // If a package is DMRH on a managed user, it should also be treated as an admin on + // that user. If that package is also a system package, it should also be protected + // on other users otherwise "uninstall updates" on an unmanaged user may break + // management on other users because apk version is shared between all users. + var packageState = snapshotComputer().getPackageStateInternal(packageName); + if (packageState == null) { + return false; + } + for (int user : packageState.isSystem() ? allUsers : targetUsers) { + if (isDeviceManagementRoleHolder(packageName, user) + && dpmi.isUserOrganizationManaged(user)) { return true; } } diff --git a/services/core/java/com/android/server/pm/permission/PermissionManagerService.java b/services/core/java/com/android/server/pm/permission/PermissionManagerService.java index df9f7fb3d6e5..5fc3e332b95c 100644 --- a/services/core/java/com/android/server/pm/permission/PermissionManagerService.java +++ b/services/core/java/com/android/server/pm/permission/PermissionManagerService.java @@ -1015,8 +1015,7 @@ public class PermissionManagerService extends IPermissionManager.Stub { permission, attributionSource, message, forDataDelivery, startDataDelivery, fromDatasource, attributedOp); // Finish any started op if some step in the attribution chain failed. - if (startDataDelivery && result != PermissionChecker.PERMISSION_GRANTED - && result != PermissionChecker.PERMISSION_SOFT_DENIED) { + if (startDataDelivery && result != PermissionChecker.PERMISSION_GRANTED) { if (attributedOp == AppOpsManager.OP_NONE) { finishDataDelivery(AppOpsManager.permissionToOpCode(permission), attributionSource.asState(), fromDatasource); diff --git a/services/core/java/com/android/server/policy/PhoneWindowManager.java b/services/core/java/com/android/server/policy/PhoneWindowManager.java index 63491e8434bf..e0c4ebeb9f89 100644 --- a/services/core/java/com/android/server/policy/PhoneWindowManager.java +++ b/services/core/java/com/android/server/policy/PhoneWindowManager.java @@ -37,6 +37,7 @@ import static android.content.pm.PackageManager.PERMISSION_GRANTED; 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.os.UserManager.isVisibleBackgroundUsersEnabled; import static android.provider.Settings.Secure.VOLUME_HUSH_OFF; import static android.view.Display.DEFAULT_DISPLAY; import static android.view.Display.INVALID_DISPLAY; @@ -184,6 +185,7 @@ import android.service.dreams.IDreamManager; import android.service.vr.IPersistentVrStateCallbacks; import android.speech.RecognizerIntent; import android.telecom.TelecomManager; +import android.util.ArraySet; import android.util.Log; import android.util.MathUtils; import android.util.MutableBoolean; @@ -256,6 +258,7 @@ import java.io.FileNotFoundException; import java.io.FileReader; import java.io.IOException; import java.io.PrintWriter; +import java.util.Arrays; import java.util.HashSet; import java.util.List; import java.util.Set; @@ -718,6 +721,25 @@ public class PhoneWindowManager implements WindowManagerPolicy { // Timeout for showing the keyguard after the screen is on, in case no "ready" is received. private int mKeyguardDrawnTimeout = 1000; + private final boolean mVisibleBackgroundUsersEnabled = isVisibleBackgroundUsersEnabled(); + + // Key codes that should be ignored for visible background users in MUMD environment. + private static final Set<Integer> KEY_CODES_IGNORED_FOR_VISIBLE_BACKGROUND_USERS = + new ArraySet<>(Arrays.asList( + KeyEvent.KEYCODE_POWER, + KeyEvent.KEYCODE_SLEEP, + KeyEvent.KEYCODE_WAKEUP, + KeyEvent.KEYCODE_CALL, + KeyEvent.KEYCODE_ENDCALL, + KeyEvent.KEYCODE_ASSIST, + KeyEvent.KEYCODE_VOICE_ASSIST, + KeyEvent.KEYCODE_MUTE, + KeyEvent.KEYCODE_VOLUME_MUTE, + KeyEvent.KEYCODE_RECENT_APPS, + KeyEvent.KEYCODE_APP_SWITCH, + KeyEvent.KEYCODE_NOTIFICATION + )); + private static final int MSG_DISPATCH_MEDIA_KEY_WITH_WAKE_LOCK = 3; private static final int MSG_DISPATCH_MEDIA_KEY_REPEAT_WITH_WAKE_LOCK = 4; private static final int MSG_KEYGUARD_DRAWN_COMPLETE = 5; @@ -811,7 +833,11 @@ public class PhoneWindowManager implements WindowManagerPolicy { event.recycle(); break; case MSG_HANDLE_ALL_APPS: - launchAllAppsAction(); + KeyEvent keyEvent = (KeyEvent) msg.obj; + if (isKeyEventForCurrentUser(keyEvent.getDisplayId(), keyEvent.getKeyCode(), + "launchAllAppsViaA11y")) { + launchAllAppsAction(); + } break; case MSG_RINGER_TOGGLE_CHORD: handleRingerChordGesture(); @@ -2054,12 +2080,21 @@ public class PhoneWindowManager implements WindowManagerPolicy { } switch (mDoubleTapOnHomeBehavior) { case DOUBLE_TAP_HOME_RECENT_SYSTEM_UI: + if (!isKeyEventForCurrentUser( + event.getDisplayId(), event.getKeyCode(), "toggleRecentApps")) { + break; + } notifyKeyGestureCompleted(event, KeyGestureEvent.KEY_GESTURE_TYPE_APP_SWITCH); mHomeConsumed = true; toggleRecentApps(); break; case DOUBLE_TAP_HOME_PIP_MENU: + if (!isKeyEventForCurrentUser( + event.getDisplayId(), event.getKeyCode(), + "showPictureInPictureMenu")) { + break; + } mHomeConsumed = true; showPictureInPictureMenuInternal(); break; @@ -2082,15 +2117,26 @@ public class PhoneWindowManager implements WindowManagerPolicy { switch (mLongPressOnHomeBehavior) { case LONG_PRESS_HOME_ALL_APPS: notifyKeyGestureCompleted(event, KeyGestureEvent.KEY_GESTURE_TYPE_ALL_APPS); - launchAllAppsAction(); + if (isKeyEventForCurrentUser(event.getDisplayId(), event.getKeyCode(), + "launchAllAppsViaA11y")) { + launchAllAppsAction(); + } break; case LONG_PRESS_HOME_ASSIST: + if (!isKeyEventForCurrentUser( + event.getDisplayId(), event.getKeyCode(), "launchAssistAction")) { + break; + } notifyKeyGestureCompleted(event, KeyGestureEvent.KEY_GESTURE_TYPE_LAUNCH_ASSISTANT); launchAssistAction(null, event.getDeviceId(), event.getEventTime(), AssistUtils.INVOCATION_TYPE_HOME_BUTTON_LONG_PRESS); break; case LONG_PRESS_HOME_NOTIFICATION_PANEL: + if (!isKeyEventForCurrentUser( + event.getDisplayId(), event.getKeyCode(), "toggleNotificationPanel")) { + break; + } notifyKeyGestureCompleted(event, KeyGestureEvent.KEY_GESTURE_TYPE_TOGGLE_NOTIFICATION_PANEL); toggleNotificationPanel(); @@ -3451,7 +3497,11 @@ public class PhoneWindowManager implements WindowManagerPolicy { if (isUserSetupComplete() && !keyguardOn) { if (mModifierShortcutManager.interceptKey(event)) { - dismissKeyboardShortcutsMenu(); + if (isKeyEventForCurrentUser( + event.getDisplayId(), event.getKeyCode(), + "dismissKeyboardShortcutsMenu")) { + dismissKeyboardShortcutsMenu(); + } mPendingMetaAction = false; mPendingCapsLockToggle = false; return true; @@ -3763,7 +3813,10 @@ public class PhoneWindowManager implements WindowManagerPolicy { KeyGestureEvent.KEY_GESTURE_TYPE_TOGGLE_CAPS_LOCK); } else if (mPendingMetaAction) { if (!canceled) { - launchAllAppsAction(); + if (isKeyEventForCurrentUser(event.getDisplayId(), event.getKeyCode(), + "launchAllAppsViaA11y")) { + launchAllAppsAction(); + } notifyKeyGestureCompleted(event, KeyGestureEvent.KEY_GESTURE_TYPE_ALL_APPS); } @@ -4030,7 +4083,8 @@ public class PhoneWindowManager implements WindowManagerPolicy { return true; case KeyGestureEvent.KEY_GESTURE_TYPE_ALL_APPS: case KeyGestureEvent.KEY_GESTURE_TYPE_ACCESSIBILITY_ALL_APPS: - if (complete) { + if (complete && isKeyEventForCurrentUser(event.getDisplayId(), + event.getKeycodes()[0], "launchAllAppsViaA11y")) { launchAllAppsAction(); } return true; @@ -4703,7 +4757,10 @@ public class PhoneWindowManager implements WindowManagerPolicy { } // no keyguard stuff to worry about, just launch home! - if (mRecentsVisible) { + // If Recents is visible and the action is not from visible background users, + // hide Recents and notify it to launch Home. + if (mRecentsVisible + && (!mVisibleBackgroundUsersEnabled || displayId == DEFAULT_DISPLAY)) { try { ActivityManager.getService().stopAppSwitches(); } catch (RemoteException e) {} @@ -4859,6 +4916,14 @@ public class PhoneWindowManager implements WindowManagerPolicy { boolean isWakeKey = (policyFlags & WindowManagerPolicy.FLAG_WAKE) != 0 || event.isWakeKey(); + // There are key events that perform the operation as the current user, + // and these should be ignored for visible background users. + if (mVisibleBackgroundUsersEnabled + && KEY_CODES_IGNORED_FOR_VISIBLE_BACKGROUND_USERS.contains(keyCode) + && !isKeyEventForCurrentUser(event.getDisplayId(), keyCode, null)) { + return 0; + } + if (!mSystemBooted) { // If we have not yet booted, don't let key events do anything. // Exception: Wake and power key events are forwarded to PowerManager to allow it to @@ -5439,6 +5504,9 @@ public class PhoneWindowManager implements WindowManagerPolicy { * Notify the StatusBar that a system key was pressed. */ private void sendSystemKeyToStatusBar(KeyEvent key) { + if (!isKeyEventForCurrentUser(key.getDisplayId(), key.getKeyCode(), "handleSystemKey")) { + return; + } IStatusBarService statusBar = getStatusBarService(); if (statusBar != null) { try { @@ -5866,6 +5934,10 @@ public class PhoneWindowManager implements WindowManagerPolicy { } private void wakeUpFromWakeKey(KeyEvent event) { + if (!isKeyEventForCurrentUser( + event.getDisplayId(), event.getKeyCode(), "wakeUpFromWakeKey")) { + return; + } wakeUpFromWakeKey( event.getEventTime(), event.getKeyCode(), @@ -6445,6 +6517,12 @@ public class PhoneWindowManager implements WindowManagerPolicy { // TODO (b/113840485): Move this logic to DisplayPolicy when lockscreen supports multi-display. @Override public void setAllowLockscreenWhenOn(int displayId, boolean allow) { + // We should ignore this operation for visible background users + // until lockscreen supports multi-display. + if (mVisibleBackgroundUsersEnabled + && mUserManagerInternal.getUserAssignedToDisplay(displayId) != mCurrentUserId) { + return; + } if (allow) { mAllowLockscreenWhenOnDisplays.add(displayId); } else { @@ -7253,4 +7331,29 @@ public class PhoneWindowManager implements WindowManagerPolicy { } return DEFAULT_DISPLAY; } + + /** + * This method is intended to prevent key events for visible background users + * from interfering with the current user's experience in MUMD environment. + * + * @param displayId the displayId of the key event. + * @param keyCode the key code of the event. + * + * @return false if the key event is for a visible background user. + */ + private boolean isKeyEventForCurrentUser(int displayId, int keyCode, @Nullable String purpose) { + if (!mVisibleBackgroundUsersEnabled) { + return true; + } + int assignedUser = mUserManagerInternal.getUserAssignedToDisplay(displayId); + if (assignedUser == mCurrentUserId) { + return true; + } + if (DEBUG_INPUT) { + Slog.w(TAG, "Cannot handle " + KeyEvent.keyCodeToString(keyCode) + + (purpose != null ? " to " + purpose : "") + + " for visible background user(u" + assignedUser + ")"); + } + return false; + } } diff --git a/services/core/java/com/android/server/search/SearchManagerService.java b/services/core/java/com/android/server/search/SearchManagerService.java index 9b39fa1e177c..a49a9fdf4cca 100644 --- a/services/core/java/com/android/server/search/SearchManagerService.java +++ b/services/core/java/com/android/server/search/SearchManagerService.java @@ -46,6 +46,7 @@ import com.android.internal.util.IndentingPrintWriter; import com.android.server.LocalServices; import com.android.server.SystemService; import com.android.server.SystemService.TargetUser; +import com.android.server.pm.UserManagerInternal; import com.android.server.statusbar.StatusBarManagerInternal; import java.io.FileDescriptor; @@ -89,6 +90,8 @@ public class SearchManagerService extends ISearchManager.Stub { @GuardedBy("mSearchables") private final SparseArray<Searchables> mSearchables = new SparseArray<>(); + private final UserManagerInternal mUserManagerInternal; + /** * Initializes the Search Manager service in the provided system context. * Only one instance of this object should be created! @@ -101,6 +104,7 @@ public class SearchManagerService extends ISearchManager.Stub { mMyPackageMonitor.register(context, null, UserHandle.ALL, true); new GlobalSearchProviderObserver(context.getContentResolver()); mHandler = BackgroundThread.getHandler(); + mUserManagerInternal = LocalServices.getService(UserManagerInternal.class); } private Searchables getSearchables(int userId) { @@ -336,6 +340,14 @@ public class SearchManagerService extends ISearchManager.Stub { @Override public void launchAssist(int userHandle, Bundle args) { + // Currently, visible background users are not allowed to launch assist.(b/332222893) + // TODO(b/368715893): Consider indirect calls from system service when checking the + // calling user. + final int callingUserId = UserHandle.getCallingUserId(); + if (mUserManagerInternal.isVisibleBackgroundFullUser(callingUserId)) { + throw new SecurityException("Visible background user(u" + callingUserId + + ") is not permitted to launch assist."); + } StatusBarManagerInternal statusBarManager = LocalServices.getService(StatusBarManagerInternal.class); if (statusBarManager != null) { diff --git a/services/core/java/com/android/server/vibrator/VibrationSettings.java b/services/core/java/com/android/server/vibrator/VibrationSettings.java index b8840790a816..102306fa3c42 100644 --- a/services/core/java/com/android/server/vibrator/VibrationSettings.java +++ b/services/core/java/com/android/server/vibrator/VibrationSettings.java @@ -31,6 +31,7 @@ import static android.os.VibrationAttributes.USAGE_UNKNOWN; import android.annotation.NonNull; import android.annotation.Nullable; import android.app.ActivityManager; +import android.app.IActivityManager; import android.app.SynchronousUserSwitchObserver; import android.app.UidObserver; import android.content.BroadcastReceiver; @@ -74,6 +75,7 @@ import java.util.ArrayList; import java.util.Arrays; import java.util.HashSet; import java.util.List; +import java.util.Objects; import java.util.Set; /** Controls all the system settings related to vibration. */ @@ -147,9 +149,6 @@ final class VibrationSettings { PowerManager.GO_TO_SLEEP_REASON_INATTENTIVE, PowerManager.GO_TO_SLEEP_REASON_TIMEOUT)); - private static final IntentFilter INTERNAL_RINGER_MODE_CHANGED_INTENT_FILTER = - new IntentFilter(AudioManager.INTERNAL_RINGER_MODE_CHANGED_ACTION); - /** Listener for changes on vibration settings. */ interface OnVibratorSettingsChanged { /** Callback triggered when any of the vibrator settings change. */ @@ -158,15 +157,18 @@ final class VibrationSettings { private final Object mLock = new Object(); private final Context mContext; - private final String mSystemUiPackage; @VisibleForTesting final SettingsContentObserver mSettingObserver; @VisibleForTesting - final SettingsBroadcastReceiver mSettingChangeReceiver; + final RingerModeBroadcastReceiver mRingerModeBroadcastReceiver; + @VisibleForTesting + final BatteryBroadcastReceiver mBatteryBroadcastReceiver; @VisibleForTesting final VibrationUidObserver mUidObserver; @VisibleForTesting final VibrationUserSwitchObserver mUserSwitchObserver; + @VisibleForTesting + final VibrationLowPowerModeListener mLowPowerModeListener; @GuardedBy("mLock") private final List<OnVibratorSettingsChanged> mListeners = new ArrayList<>(); @@ -180,10 +182,13 @@ final class VibrationSettings { @GuardedBy("mLock") @Nullable private PowerManagerInternal mPowerManagerInternal; + @GuardedBy("mLock") @Nullable private VirtualDeviceManagerInternal mVirtualDeviceManagerInternal; @GuardedBy("mLock") + private String mSystemUiPackage; + @GuardedBy("mLock") private boolean mVibrateInputDevices; @GuardedBy("mLock") private SparseIntArray mCurrentVibrationIntensities = new SparseIntArray(); @@ -205,11 +210,11 @@ final class VibrationSettings { mContext = context; mVibrationConfig = config; mSettingObserver = new SettingsContentObserver(handler); - mSettingChangeReceiver = new SettingsBroadcastReceiver(); + mRingerModeBroadcastReceiver = new RingerModeBroadcastReceiver(); + mBatteryBroadcastReceiver = new BatteryBroadcastReceiver(); mUidObserver = new VibrationUidObserver(); mUserSwitchObserver = new VibrationUserSwitchObserver(); - mSystemUiPackage = LocalServices.getService(PackageManagerInternal.class) - .getSystemUiServiceComponent().getPackageName(); + mLowPowerModeListener = new VibrationLowPowerModeListener(); VibrationEffect clickEffect = createEffectFromResource( com.android.internal.R.array.config_virtualKeyVibePattern); @@ -233,18 +238,34 @@ final class VibrationSettings { } public void onSystemReady() { - PowerManagerInternal pm = LocalServices.getService(PowerManagerInternal.class); - AudioManager am = mContext.getSystemService(AudioManager.class); - int ringerMode = (am == null) ? mRingerMode : am.getRingerModeInternal(); + onSystemReady(LocalServices.getService(PackageManagerInternal.class), + LocalServices.getService(PowerManagerInternal.class), + ActivityManager.getService(), + LocalServices.getService(VirtualDeviceManagerInternal.class), + mContext.getSystemService(AudioManager.class)); + } + + @VisibleForTesting + void onSystemReady(PackageManagerInternal packageManagerInternal, + PowerManagerInternal powerManagerInternal, + IActivityManager activityManagerInternal, + @Nullable VirtualDeviceManagerInternal virtualDeviceManagerInternal, + @Nullable AudioManager audioManager) { + int ringerMode = (audioManager == null) + ? AudioManager.RINGER_MODE_NORMAL + : audioManager.getRingerModeInternal(); + String sysUiPackage = packageManagerInternal.getSystemUiServiceComponent().getPackageName(); synchronized (mLock) { - mPowerManagerInternal = pm; - mAudioManager = am; + mPowerManagerInternal = powerManagerInternal; + mVirtualDeviceManagerInternal = virtualDeviceManagerInternal; + mAudioManager = audioManager; mRingerMode = ringerMode; + mSystemUiPackage = sysUiPackage; } try { - ActivityManager.getService().registerUidObserver(mUidObserver, + activityManagerInternal.registerUidObserver(mUidObserver, ActivityManager.UID_OBSERVER_PROCSTATE | ActivityManager.UID_OBSERVER_GONE, ActivityManager.PROCESS_STATE_UNKNOWN, /* callingPackage= */ null); } catch (RemoteException e) { @@ -252,32 +273,16 @@ final class VibrationSettings { } try { - ActivityManager.getService().registerUserSwitchObserver(mUserSwitchObserver, TAG); + activityManagerInternal.registerUserSwitchObserver(mUserSwitchObserver, TAG); } catch (RemoteException e) { // ignored; both services live in system_server } - pm.registerLowPowerModeObserver( - new PowerManagerInternal.LowPowerModeListener() { - @Override - public int getServiceType() { - return PowerManager.ServiceType.VIBRATION; - } - - @Override - public void onLowPowerModeChanged(PowerSaveState result) { - boolean shouldNotifyListeners; - synchronized (mLock) { - shouldNotifyListeners = result.batterySaverEnabled != mBatterySaverMode; - mBatterySaverMode = result.batterySaverEnabled; - } - if (shouldNotifyListeners) { - notifyListeners(); - } - } - }); - - registerSettingsChangeReceiver(INTERNAL_RINGER_MODE_CHANGED_INTENT_FILTER); + powerManagerInternal.registerLowPowerModeObserver(mLowPowerModeListener); + + mContext.registerReceiver(mRingerModeBroadcastReceiver, + new IntentFilter(AudioManager.INTERNAL_RINGER_MODE_CHANGED_ACTION), + Context.RECEIVER_EXPORTED_UNAUDITED); // Listen to all settings that might affect the result of Vibrator.getVibrationIntensity. registerSettingsObserver(Settings.System.getUriFor(Settings.System.VIBRATE_INPUT_DEVICES)); @@ -301,12 +306,7 @@ final class VibrationSettings { if (mVibrationConfig.ignoreVibrationsOnWirelessCharger()) { Intent batteryStatus = mContext.registerReceiver( - new BroadcastReceiver() { - @Override - public void onReceive(Context context, Intent intent) { - updateBatteryInfo(intent); - } - }, + mBatteryBroadcastReceiver, new IntentFilter(Intent.ACTION_BATTERY_CHANGED), Context.RECEIVER_NOT_EXPORTED); // After registering the receiver for battery status, process the sticky broadcast that @@ -476,8 +476,10 @@ final class VibrationSettings { public boolean shouldCancelVibrationOnScreenOff(@NonNull CallerInfo callerInfo, long vibrationStartUptimeMillis) { PowerManagerInternal pm; + String sysUiPackageName; synchronized (mLock) { pm = mPowerManagerInternal; + sysUiPackageName = mSystemUiPackage; } if (pm != null) { // The SleepData from PowerManager may refer to a more recent sleep than the broadcast @@ -501,7 +503,7 @@ final class VibrationSettings { } // Only allow vibrations from System packages to continue vibrating when the screen goes off return callerInfo.uid != Process.SYSTEM_UID && callerInfo.uid != 0 - && !mSystemUiPackage.equals(callerInfo.opPkg); + && !Objects.equals(sysUiPackageName, callerInfo.opPkg); } /** @@ -782,11 +784,6 @@ final class VibrationSettings { UserHandle.USER_ALL); } - private void registerSettingsChangeReceiver(IntentFilter intentFilter) { - mContext.registerReceiver(mSettingChangeReceiver, intentFilter, - Context.RECEIVER_EXPORTED_UNAUDITED); - } - @Nullable private VibrationEffect createEffectFromResource(int resId) { return createEffectFromResource(mContext.getResources(), resId); @@ -833,12 +830,11 @@ final class VibrationSettings { } private boolean isAppRunningOnAnyVirtualDevice(int uid) { - if (mVirtualDeviceManagerInternal == null) { - mVirtualDeviceManagerInternal = - LocalServices.getService(VirtualDeviceManagerInternal.class); + VirtualDeviceManagerInternal vdm; + synchronized (mLock) { + vdm = mVirtualDeviceManagerInternal; } - return mVirtualDeviceManagerInternal != null - && mVirtualDeviceManagerInternal.isAppRunningOnAnyVirtualDevice(uid); + return vdm != null && vdm.isAppRunningOnAnyVirtualDevice(uid); } /** Implementation of {@link ContentObserver} to be registered to a setting {@link Uri}. */ @@ -857,7 +853,7 @@ final class VibrationSettings { /** Implementation of {@link BroadcastReceiver} to update on ringer mode change. */ @VisibleForTesting - final class SettingsBroadcastReceiver extends BroadcastReceiver { + final class RingerModeBroadcastReceiver extends BroadcastReceiver { @Override public void onReceive(Context context, Intent intent) { String action = intent.getAction(); @@ -868,6 +864,18 @@ final class VibrationSettings { } } + /** Implementation of {@link BroadcastReceiver} to update on battery mode change. */ + @VisibleForTesting + final class BatteryBroadcastReceiver extends BroadcastReceiver { + @Override + public void onReceive(Context context, Intent intent) { + String action = intent.getAction(); + if (Intent.ACTION_BATTERY_CHANGED.equals(action)) { + updateBatteryInfo(intent); + } + } + } + /** Implementation of {@link ContentObserver} to be registered to a setting {@link Uri}. */ @VisibleForTesting final class VibrationUidObserver extends UidObserver { @@ -913,4 +921,25 @@ final class VibrationSettings { update(); } } + + /** Implementation of {@link PowerManagerInternal.LowPowerModeListener} for low battery. */ + @VisibleForTesting + final class VibrationLowPowerModeListener implements PowerManagerInternal.LowPowerModeListener { + @Override + public int getServiceType() { + return PowerManager.ServiceType.VIBRATION; + } + + @Override + public void onLowPowerModeChanged(PowerSaveState result) { + boolean shouldNotifyListeners; + synchronized (mLock) { + shouldNotifyListeners = result.batterySaverEnabled != mBatterySaverMode; + mBatterySaverMode = result.batterySaverEnabled; + } + if (shouldNotifyListeners) { + notifyListeners(); + } + } + } } diff --git a/services/core/java/com/android/server/wm/ActivityRecord.java b/services/core/java/com/android/server/wm/ActivityRecord.java index de0ec30fb9e8..96b924336881 100644 --- a/services/core/java/com/android/server/wm/ActivityRecord.java +++ b/services/core/java/com/android/server/wm/ActivityRecord.java @@ -5863,6 +5863,7 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A return; } + final State prevState = mState; mState = state; if (getTaskFragment() != null) { @@ -5903,6 +5904,14 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A mAtmService.updateBatteryStats(this, false); mAtmService.updateActivityUsageStats(this, Event.ACTIVITY_PAUSED); break; + case STOPPING: + // It is possible that an Activity is scheduled to be STOPPED directly from RESUMED + // state. Updating the PAUSED usage state in that case, since the Activity will be + // STOPPED while cycled through the PAUSED state. + if (prevState == RESUMED) { + mAtmService.updateActivityUsageStats(this, Event.ACTIVITY_PAUSED); + } + break; case STOPPED: mAtmService.updateActivityUsageStats(this, Event.ACTIVITY_STOPPED); if (mDisplayContent != null) { diff --git a/services/core/java/com/android/server/wm/ConfigurationContainer.java b/services/core/java/com/android/server/wm/ConfigurationContainer.java index 670a61dca5c8..05dcbb7f9af4 100644 --- a/services/core/java/com/android/server/wm/ConfigurationContainer.java +++ b/services/core/java/com/android/server/wm/ConfigurationContainer.java @@ -25,6 +25,7 @@ import static android.app.WindowConfiguration.ACTIVITY_TYPE_UNDEFINED; import static android.app.WindowConfiguration.ROTATION_UNDEFINED; 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.app.WindowConfiguration.activityTypeToString; @@ -268,7 +269,16 @@ public abstract class ConfigurationContainer<E extends ConfigurationContainer> { } final DisplayPolicy.DecorInsets.Info decor = displayContent.getDisplayPolicy().getDecorInsetsInfo(rotation, dw, dh); - outAppBounds.intersectUnchecked(decor.mOverrideNonDecorFrame); + if (!outAppBounds.intersect(decor.mOverrideNonDecorFrame)) { + // TODO (b/364883053): When a split screen is requested from an app intent for a new + // task, the bounds is not the final bounds, and this is also not a bounds change + // event handled correctly with the offset. Revert back to legacy method for this + // case. + if (inOutConfig.windowConfiguration.getWindowingMode() + == WINDOWING_MODE_MULTI_WINDOW) { + outAppBounds.inset(decor.mOverrideNonDecorInsets); + } + } if (task != null && (task.mOffsetYForInsets != 0 || task.mOffsetXForInsets != 0)) { outAppBounds.offset(-task.mOffsetXForInsets, -task.mOffsetYForInsets); } diff --git a/services/core/java/com/android/server/wm/InsetsSourceProvider.java b/services/core/java/com/android/server/wm/InsetsSourceProvider.java index 57b879277326..d3cae4c7b940 100644 --- a/services/core/java/com/android/server/wm/InsetsSourceProvider.java +++ b/services/core/java/com/android/server/wm/InsetsSourceProvider.java @@ -400,7 +400,7 @@ class InsetsSourceProvider { } final Point position = getWindowFrameSurfacePosition(); if (!mPosition.equals(position)) { - mPosition.set(position.x, position.y); + mPosition.set(position); if (windowState != null && windowState.getWindowFrames().didFrameSizeChange() && windowState.mWinAnimator.getShown() && mWindowContainer.okToDisplay()) { windowState.applyWithNextDraw(mSetControlPositionConsumer); @@ -543,6 +543,7 @@ class InsetsSourceProvider { } boolean initiallyVisible = mClientVisible; final Point surfacePosition = getWindowFrameSurfacePosition(); + mPosition.set(surfacePosition); mAdapter = new ControlAdapter(surfacePosition); if (mSource.getType() == WindowInsets.Type.ime()) { if (android.view.inputmethod.Flags.refactorInsetsController()) { diff --git a/services/core/java/com/android/server/wm/Transition.java b/services/core/java/com/android/server/wm/Transition.java index d042b3859c3e..dd5f6134e2eb 100644 --- a/services/core/java/com/android/server/wm/Transition.java +++ b/services/core/java/com/android/server/wm/Transition.java @@ -1385,7 +1385,16 @@ class Transition implements BLASTSyncEngine.TransactionReadyListener { // Commit wallpaper visibility after activity, because usually the wallpaper target token is // an activity, and wallpaper's visibility depends on activity's visibility. for (int i = mParticipants.size() - 1; i >= 0; --i) { - final WallpaperWindowToken wt = mParticipants.valueAt(i).asWallpaperToken(); + final WindowContainer<?> wc = mParticipants.valueAt(i); + WallpaperWindowToken wt = wc.asWallpaperToken(); + if (!Flags.ensureWallpaperInTransitions()) { + if (wt == null) { + final WindowState windowState = wc.asWindowState(); + if (windowState != null) { + wt = windowState.mToken.asWallpaperToken(); + } + } + } if (wt == null) continue; final WindowState target = wt.mDisplayContent.mWallpaperController.getWallpaperTarget(); final boolean isTargetInvisible = target == null || !target.mToken.isVisible(); diff --git a/services/tests/servicestests/src/com/android/server/accessibility/magnification/MagnificationConnectionManagerTest.java b/services/tests/servicestests/src/com/android/server/accessibility/magnification/MagnificationConnectionManagerTest.java index 87fe6cf8f283..6d27dddfc357 100644 --- a/services/tests/servicestests/src/com/android/server/accessibility/magnification/MagnificationConnectionManagerTest.java +++ b/services/tests/servicestests/src/com/android/server/accessibility/magnification/MagnificationConnectionManagerTest.java @@ -62,6 +62,7 @@ import androidx.test.filters.FlakyTest; import com.android.internal.util.test.FakeSettingsProvider; import com.android.server.LocalServices; import com.android.server.accessibility.AccessibilityTraceManager; +import com.android.server.pm.UserManagerInternal; import com.android.server.statusbar.StatusBarManagerInternal; import org.junit.Before; @@ -92,12 +93,16 @@ public class MagnificationConnectionManagerTest { private MagnificationConnectionManager.Callback mMockCallback; private MockContentResolver mResolver; private MagnificationConnectionManager mMagnificationConnectionManager; + @Mock + private UserManagerInternal mMockUserManagerInternal; @Before public void setUp() throws RemoteException { MockitoAnnotations.initMocks(this); LocalServices.removeServiceForTest(StatusBarManagerInternal.class); + LocalServices.removeServiceForTest(UserManagerInternal.class); LocalServices.addService(StatusBarManagerInternal.class, mMockStatusBarManagerInternal); + LocalServices.addService(UserManagerInternal.class, mMockUserManagerInternal); mResolver = new MockContentResolver(); mMockConnection = new MockMagnificationConnection(); mMagnificationConnectionManager = new MagnificationConnectionManager(mContext, new Object(), @@ -110,6 +115,8 @@ public class MagnificationConnectionManagerTest { Settings.Secure.putFloatForUser(mResolver, Settings.Secure.ACCESSIBILITY_DISPLAY_MAGNIFICATION_SCALE, 2.5f, CURRENT_USER_ID); + + when(mMockUserManagerInternal.isVisibleBackgroundFullUser(anyInt())).thenReturn(false); } private void stubSetConnection(boolean needDelay) { diff --git a/services/tests/servicestests/src/com/android/server/accounts/AccountManagerServiceTest.java b/services/tests/servicestests/src/com/android/server/accounts/AccountManagerServiceTest.java index b9ce8ad0b018..0c92abce7254 100644 --- a/services/tests/servicestests/src/com/android/server/accounts/AccountManagerServiceTest.java +++ b/services/tests/servicestests/src/com/android/server/accounts/AccountManagerServiceTest.java @@ -1163,6 +1163,16 @@ public class AccountManagerServiceTest extends AndroidTestCase { verify(mMockAccountManagerResponse).onResult(mBundleCaptor.capture()); Bundle result = mBundleCaptor.getValue(); + Bundle sessionBundle = result.getBundle(AccountManager.KEY_ACCOUNT_SESSION_BUNDLE); + assertNotNull(sessionBundle); + // Assert that session bundle is decrypted and hence data is visible. + assertEquals(AccountManagerServiceTestFixtures.SESSION_DATA_VALUE_1, + sessionBundle.getString(AccountManagerServiceTestFixtures.SESSION_DATA_NAME_1)); + // Assert finishSessionAsUser added calling uid and pid into the sessionBundle + assertTrue(sessionBundle.containsKey(AccountManager.KEY_CALLER_UID)); + assertTrue(sessionBundle.containsKey(AccountManager.KEY_CALLER_PID)); + assertEquals(sessionBundle.getString( + AccountManager.KEY_ANDROID_PACKAGE_NAME), "APCT.package"); // Verify response data assertNull(result.getString(AccountManager.KEY_AUTHTOKEN, null)); @@ -2111,6 +2121,12 @@ public class AccountManagerServiceTest extends AndroidTestCase { result.getString(AccountManager.KEY_ACCOUNT_NAME)); assertEquals(AccountManagerServiceTestFixtures.ACCOUNT_TYPE_1, result.getString(AccountManager.KEY_ACCOUNT_TYPE)); + + Bundle optionBundle = result.getParcelable( + AccountManagerServiceTestFixtures.KEY_OPTIONS_BUNDLE); + // Assert addAccountAsUser added calling uid and pid into the option bundle + assertTrue(optionBundle.containsKey(AccountManager.KEY_CALLER_UID)); + assertTrue(optionBundle.containsKey(AccountManager.KEY_CALLER_PID)); } @SmallTest @@ -3441,52 +3457,6 @@ public class AccountManagerServiceTest extends AndroidTestCase { + (readTotalTime.doubleValue() / readerCount / loopSize)); } - @SmallTest - public void testSanitizeBundle_expectedFields() throws Exception { - Bundle bundle = new Bundle(); - bundle.putString(AccountManager.KEY_ACCOUNT_NAME, "name"); - bundle.putString(AccountManager.KEY_ACCOUNT_TYPE, "type"); - bundle.putString(AccountManager.KEY_AUTHTOKEN, "token"); - bundle.putString(AccountManager.KEY_AUTH_TOKEN_LABEL, "label"); - bundle.putString(AccountManager.KEY_ERROR_MESSAGE, "error message"); - bundle.putString(AccountManager.KEY_PASSWORD, "password"); - bundle.putString(AccountManager.KEY_ACCOUNT_STATUS_TOKEN, "status"); - - bundle.putLong(AbstractAccountAuthenticator.KEY_CUSTOM_TOKEN_EXPIRY, 123L); - bundle.putBoolean(AccountManager.KEY_BOOLEAN_RESULT, true); - bundle.putInt(AccountManager.KEY_ERROR_CODE, 456); - - Bundle sanitizedBundle = AccountManagerService.sanitizeBundle(bundle); - assertEquals(sanitizedBundle.getString(AccountManager.KEY_ACCOUNT_NAME), "name"); - assertEquals(sanitizedBundle.getString(AccountManager.KEY_ACCOUNT_TYPE), "type"); - assertEquals(sanitizedBundle.getString(AccountManager.KEY_AUTHTOKEN), "token"); - assertEquals(sanitizedBundle.getString(AccountManager.KEY_AUTH_TOKEN_LABEL), "label"); - assertEquals(sanitizedBundle.getString(AccountManager.KEY_ERROR_MESSAGE), "error message"); - assertEquals(sanitizedBundle.getString(AccountManager.KEY_PASSWORD), "password"); - assertEquals(sanitizedBundle.getString(AccountManager.KEY_ACCOUNT_STATUS_TOKEN), "status"); - - assertEquals(sanitizedBundle.getLong( - AbstractAccountAuthenticator.KEY_CUSTOM_TOKEN_EXPIRY, 0), 123L); - assertEquals(sanitizedBundle.getBoolean(AccountManager.KEY_BOOLEAN_RESULT, false), true); - assertEquals(sanitizedBundle.getInt(AccountManager.KEY_ERROR_CODE, 0), 456); - } - - @SmallTest - public void testSanitizeBundle_filtersUnexpectedFields() throws Exception { - Bundle bundle = new Bundle(); - bundle.putString(AccountManager.KEY_ACCOUNT_NAME, "name"); - bundle.putString("unknown_key", "value"); - Bundle sessionBundle = new Bundle(); - bundle.putBundle(AccountManager.KEY_ACCOUNT_SESSION_BUNDLE, sessionBundle); - - Bundle sanitizedBundle = AccountManagerService.sanitizeBundle(bundle); - - assertEquals(sanitizedBundle.getString(AccountManager.KEY_ACCOUNT_NAME), "name"); - assertFalse(sanitizedBundle.containsKey("unknown_key")); - // It is a valid response from Authenticator which will be accessed using original Bundle - assertFalse(sanitizedBundle.containsKey(AccountManager.KEY_ACCOUNT_SESSION_BUNDLE)); - } - private void waitForCyclicBarrier(CyclicBarrier cyclicBarrier) { try { cyclicBarrier.await(LATCH_TIMEOUT_MS, TimeUnit.MILLISECONDS); diff --git a/services/tests/uiservicestests/src/com/android/server/UiModeManagerServiceTest.java b/services/tests/uiservicestests/src/com/android/server/UiModeManagerServiceTest.java index c247c08c8010..3b0cb4ad8779 100644 --- a/services/tests/uiservicestests/src/com/android/server/UiModeManagerServiceTest.java +++ b/services/tests/uiservicestests/src/com/android/server/UiModeManagerServiceTest.java @@ -68,6 +68,7 @@ import static org.testng.Assert.assertThrows; import android.Manifest; import android.app.Activity; +import android.app.ActivityManager; import android.app.AlarmManager; import android.app.Flags; import android.app.IOnProjectionStateChangedListener; @@ -247,6 +248,8 @@ public class UiModeManagerServiceTest extends UiServiceTestCase { mInjector = spy(new TestInjector()); mUiManagerService = new UiModeManagerService(mContext, /* setupWizardComplete= */ true, mTwilightManager, mInjector); + // Initialize the current user. + mUiManagerService.setCurrentUser(ActivityManager.getCurrentUser()); try { mUiManagerService.onBootPhase(SystemService.PHASE_SYSTEM_SERVICES_READY); } catch (SecurityException e) {/* ignore for permission denial */} diff --git a/services/tests/vibrator/src/com/android/server/vibrator/VibrationSettingsTest.java b/services/tests/vibrator/src/com/android/server/vibrator/VibrationSettingsTest.java index 492f108cd79f..e4a6efdd5304 100644 --- a/services/tests/vibrator/src/com/android/server/vibrator/VibrationSettingsTest.java +++ b/services/tests/vibrator/src/com/android/server/vibrator/VibrationSettingsTest.java @@ -44,7 +44,8 @@ import static org.mockito.ArgumentMatchers.any; import static org.mockito.ArgumentMatchers.anyInt; import static org.mockito.ArgumentMatchers.argThat; import static org.mockito.ArgumentMatchers.eq; -import static org.mockito.Mockito.doAnswer; +import static org.mockito.Mockito.doReturn; +import static org.mockito.Mockito.never; import static org.mockito.Mockito.spy; import static org.mockito.Mockito.times; import static org.mockito.Mockito.verify; @@ -52,12 +53,14 @@ import static org.mockito.Mockito.verifyNoMoreInteractions; import static org.mockito.Mockito.when; import android.app.ActivityManager; +import android.app.IActivityManager; import android.content.BroadcastReceiver; import android.content.ComponentName; import android.content.ContentResolver; import android.content.Context; import android.content.ContextWrapper; import android.content.Intent; +import android.content.IntentFilter; import android.content.pm.PackageManagerInternal; import android.media.AudioManager; import android.os.Handler; @@ -79,12 +82,10 @@ import androidx.test.InstrumentationRegistry; import com.android.internal.util.test.FakeSettingsProvider; import com.android.internal.util.test.FakeSettingsProviderRule; -import com.android.server.LocalServices; import com.android.server.companion.virtual.VirtualDeviceManagerInternal; import com.android.server.vibrator.VibrationSession.CallerInfo; import com.android.server.vibrator.VibrationSession.Status; -import org.junit.After; import org.junit.Before; import org.junit.Rule; import org.junit.Test; @@ -101,8 +102,7 @@ public class VibrationSettingsTest { @Rule public final CheckFlagsRule mCheckFlagsRule = DeviceFlagsValueProvider.createCheckFlagsRule(); - private static final int OLD_USER_ID = 123; - private static final int NEW_USER_ID = 456; + private static final int USER_ID = 123; private static final int UID = 1; private static final int VIRTUAL_DEVICE_ID = 1; private static final String SYSUI_PACKAGE_NAME = "sysui"; @@ -132,13 +132,12 @@ public class VibrationSettingsTest { @Mock private VirtualDeviceManagerInternal mVirtualDeviceManagerInternalMock; @Mock private PackageManagerInternal mPackageManagerInternalMock; @Mock private AudioManager mAudioManagerMock; + @Mock private IActivityManager mActivityManagerMock; @Mock private VibrationConfig mVibrationConfigMock; private TestLooper mTestLooper; private ContextWrapper mContextSpy; private VibrationSettings mVibrationSettings; - private PowerManagerInternal.LowPowerModeListener mRegisteredPowerModeListener; - private BroadcastReceiver mRegisteredBatteryBroadcastReceiver; @Before public void setUp() throws Exception { @@ -146,24 +145,20 @@ public class VibrationSettingsTest { mContextSpy = spy(new ContextWrapper(InstrumentationRegistry.getContext())); ContentResolver contentResolver = mSettingsProviderRule.mockContentResolver(mContextSpy); - when(mContextSpy.getContentResolver()).thenReturn(contentResolver); - when(mContextSpy.getSystemService(eq(Context.AUDIO_SERVICE))).thenReturn(mAudioManagerMock); - doAnswer(invocation -> { - mRegisteredPowerModeListener = invocation.getArgument(0); - return null; - }).when(mPowerManagerInternalMock).registerLowPowerModeObserver(any()); + doReturn(contentResolver).when(mContextSpy).getContentResolver(); + + // Make sure broadcast receivers are not registered for this test, to avoid flakes. + doReturn(null).when(mContextSpy) + .registerReceiver(any(BroadcastReceiver.class), any(IntentFilter.class), anyInt()); when(mPackageManagerInternalMock.getSystemUiServiceComponent()) .thenReturn(new ComponentName(SYSUI_PACKAGE_NAME, "")); - removeServicesForTest(); - addServicesForTest(); - setDefaultIntensity(VIBRATION_INTENSITY_MEDIUM); setIgnoreVibrationsOnWirelessCharger(false); - createSystemReadyVibrationSettings(); mockGoToSleep(/* goToSleepTime= */ 0, PowerManager.GO_TO_SLEEP_REASON_TIMEOUT); + createSystemReadyVibrationSettings(); } private void createSystemReadyVibrationSettings() { @@ -177,38 +172,18 @@ public class VibrationSettingsTest { setUserSetting(Settings.System.APPLY_RAMPING_RINGER, 0); setRingerMode(AudioManager.RINGER_MODE_NORMAL); - mVibrationSettings.onSystemReady(); - } - - private void removeServicesForTest() { - LocalServices.removeServiceForTest(PowerManagerInternal.class); - LocalServices.removeServiceForTest(PackageManagerInternal.class); - LocalServices.removeServiceForTest(VirtualDeviceManagerInternal.class); - } - - private void addServicesForTest() { - LocalServices.addService(PowerManagerInternal.class, mPowerManagerInternalMock); - LocalServices.addService(PackageManagerInternal.class, mPackageManagerInternalMock); - LocalServices.addService(VirtualDeviceManagerInternal.class, - mVirtualDeviceManagerInternalMock); - } - - @After - public void tearDown() throws Exception { - removeServicesForTest(); + mVibrationSettings.onSystemReady(mPackageManagerInternalMock, mPowerManagerInternalMock, + mActivityManagerMock, mVirtualDeviceManagerInternalMock, mAudioManagerMock); } @Test public void create_withOnlyRequiredSystemServices() { - // The only core services that we depend on are PowerManager and PackageManager - removeServicesForTest(); - LocalServices.addService(PowerManagerInternal.class, mPowerManagerInternalMock); - LocalServices.addService(PackageManagerInternal.class, mPackageManagerInternalMock); - when(mContextSpy.getSystemService(eq(Context.AUDIO_SERVICE))).thenReturn(null); - VibrationSettings minimalVibrationSettings = new VibrationSettings(mContextSpy, new Handler(mTestLooper.getLooper()), mVibrationConfigMock); - minimalVibrationSettings.onSystemReady(); + + // The only core services that we depend on are Power, Package and Activity managers + minimalVibrationSettings.onSystemReady(mPackageManagerInternalMock, + mPowerManagerInternalMock, mActivityManagerMock, null, null); } @Test @@ -216,8 +191,8 @@ public class VibrationSettingsTest { mVibrationSettings.addListener(mListenerMock); // Testing the broadcast flow manually. - mVibrationSettings.mUserSwitchObserver.onUserSwitching(NEW_USER_ID); - mVibrationSettings.mUserSwitchObserver.onUserSwitchComplete(NEW_USER_ID); + mVibrationSettings.mUserSwitchObserver.onUserSwitching(USER_ID); + mVibrationSettings.mUserSwitchObserver.onUserSwitchComplete(USER_ID); verify(mListenerMock, times(2)).onChange(); } @@ -227,9 +202,9 @@ public class VibrationSettingsTest { mVibrationSettings.addListener(mListenerMock); // Testing the broadcast flow manually. - mVibrationSettings.mSettingChangeReceiver.onReceive(mContextSpy, + mVibrationSettings.mRingerModeBroadcastReceiver.onReceive(mContextSpy, new Intent(AudioManager.INTERNAL_RINGER_MODE_CHANGED_ACTION)); - mVibrationSettings.mSettingChangeReceiver.onReceive(mContextSpy, + mVibrationSettings.mRingerModeBroadcastReceiver.onReceive(mContextSpy, new Intent(AudioManager.INTERNAL_RINGER_MODE_CHANGED_ACTION)); verify(mListenerMock, times(2)).onChange(); @@ -251,9 +226,9 @@ public class VibrationSettingsTest { mVibrationSettings.addListener(mListenerMock); // Testing the broadcast flow manually. - mRegisteredPowerModeListener.onLowPowerModeChanged(LOW_POWER_STATE); - mRegisteredPowerModeListener.onLowPowerModeChanged(NORMAL_POWER_STATE); - mRegisteredPowerModeListener.onLowPowerModeChanged(NORMAL_POWER_STATE); // No change. + mVibrationSettings.mLowPowerModeListener.onLowPowerModeChanged(LOW_POWER_STATE); + mVibrationSettings.mLowPowerModeListener.onLowPowerModeChanged(NORMAL_POWER_STATE); + mVibrationSettings.mLowPowerModeListener.onLowPowerModeChanged(NORMAL_POWER_STATE); // Noop. verify(mListenerMock, times(2)).onChange(); } @@ -268,10 +243,9 @@ public class VibrationSettingsTest { mVibrationSettings.removeListener(mListenerMock); // Trigger multiple observers manually. - mVibrationSettings.mSettingObserver.onChange(false); - mRegisteredPowerModeListener.onLowPowerModeChanged(LOW_POWER_STATE); - mVibrationSettings.mUserSwitchObserver.onUserSwitchComplete(NEW_USER_ID); - mVibrationSettings.mSettingChangeReceiver.onReceive(mContextSpy, + mVibrationSettings.mLowPowerModeListener.onLowPowerModeChanged(LOW_POWER_STATE); + mVibrationSettings.mUserSwitchObserver.onUserSwitchComplete(USER_ID); + mVibrationSettings.mRingerModeBroadcastReceiver.onReceive(mContextSpy, new Intent(AudioManager.INTERNAL_RINGER_MODE_CHANGED_ACTION)); verifyNoMoreInteractions(mListenerMock); @@ -312,11 +286,12 @@ public class VibrationSettingsTest { @Test public void wirelessChargingVibrationsEnabled_doesNotRegisterBatteryReceiver_allowsAnyUsage() { - setBatteryReceiverRegistrationResult(getBatteryChangedIntent(BATTERY_PLUGGED_WIRELESS)); setIgnoreVibrationsOnWirelessCharger(false); createSystemReadyVibrationSettings(); - assertNull(mRegisteredBatteryBroadcastReceiver); + verify(mContextSpy, never()).registerReceiver(any(BroadcastReceiver.class), + argThat(filter -> filter.matchAction(Intent.ACTION_BATTERY_CHANGED)), anyInt()); + for (int usage : ALL_USAGES) { assertVibrationNotIgnoredForUsage(usage); } @@ -324,7 +299,6 @@ public class VibrationSettingsTest { @Test public void shouldIgnoreVibration_noBatteryIntentWhenSystemReady_allowsAnyUsage() { - setBatteryReceiverRegistrationResult(null); setIgnoreVibrationsOnWirelessCharger(true); createSystemReadyVibrationSettings(); @@ -336,7 +310,9 @@ public class VibrationSettingsTest { @Test public void shouldIgnoreVibration_onNonWirelessChargerWhenSystemReady_allowsAnyUsage() { Intent nonWirelessChargingIntent = getBatteryChangedIntent(BATTERY_PLUGGED_USB); - setBatteryReceiverRegistrationResult(nonWirelessChargingIntent); + doReturn(nonWirelessChargingIntent).when(mContextSpy).registerReceiver( + any(BroadcastReceiver.class), + argThat(filter -> filter.matchAction(Intent.ACTION_BATTERY_CHANGED)), anyInt()); setIgnoreVibrationsOnWirelessCharger(true); createSystemReadyVibrationSettings(); @@ -348,7 +324,9 @@ public class VibrationSettingsTest { @Test public void shouldIgnoreVibration_onWirelessChargerWhenSystemReady_doesNotAllowFromAnyUsage() { Intent wirelessChargingIntent = getBatteryChangedIntent(BATTERY_PLUGGED_WIRELESS); - setBatteryReceiverRegistrationResult(wirelessChargingIntent); + doReturn(wirelessChargingIntent).when(mContextSpy).registerReceiver( + any(BroadcastReceiver.class), + argThat(filter -> filter.matchAction(Intent.ACTION_BATTERY_CHANGED)), anyInt()); setIgnoreVibrationsOnWirelessCharger(true); createSystemReadyVibrationSettings(); @@ -359,13 +337,12 @@ public class VibrationSettingsTest { @Test public void shouldIgnoreVibration_receivesWirelessChargingIntent_doesNotAllowFromAnyUsage() { - Intent nonWirelessChargingIntent = getBatteryChangedIntent(BATTERY_PLUGGED_USB); - setBatteryReceiverRegistrationResult(nonWirelessChargingIntent); setIgnoreVibrationsOnWirelessCharger(true); createSystemReadyVibrationSettings(); Intent wirelessChargingIntent = getBatteryChangedIntent(BATTERY_PLUGGED_WIRELESS); - mRegisteredBatteryBroadcastReceiver.onReceive(mContextSpy, wirelessChargingIntent); + mVibrationSettings.mBatteryBroadcastReceiver.onReceive( + mContextSpy, wirelessChargingIntent); for (int usage : ALL_USAGES) { assertVibrationIgnoredForUsage(usage, Status.IGNORED_ON_WIRELESS_CHARGER); @@ -374,17 +351,21 @@ public class VibrationSettingsTest { @Test public void shouldIgnoreVibration_receivesNonWirelessChargingIntent_allowsAnyUsage() { - Intent wirelessChargingIntent = getBatteryChangedIntent(BATTERY_PLUGGED_WIRELESS); - setBatteryReceiverRegistrationResult(wirelessChargingIntent); setIgnoreVibrationsOnWirelessCharger(true); createSystemReadyVibrationSettings(); + + Intent wirelessChargingIntent = getBatteryChangedIntent(BATTERY_PLUGGED_WIRELESS); + mVibrationSettings.mBatteryBroadcastReceiver.onReceive( + mContextSpy, wirelessChargingIntent); + // Check that initially, all usages are ignored due to the wireless charging. for (int usage : ALL_USAGES) { assertVibrationIgnoredForUsage(usage, Status.IGNORED_ON_WIRELESS_CHARGER); } Intent nonWirelessChargingIntent = getBatteryChangedIntent(BATTERY_PLUGGED_USB); - mRegisteredBatteryBroadcastReceiver.onReceive(mContextSpy, nonWirelessChargingIntent); + mVibrationSettings.mBatteryBroadcastReceiver.onReceive( + mContextSpy, nonWirelessChargingIntent); for (int usage : ALL_USAGES) { assertVibrationNotIgnoredForUsage(usage); @@ -401,7 +382,7 @@ public class VibrationSettingsTest { USAGE_HARDWARE_FEEDBACK )); - mRegisteredPowerModeListener.onLowPowerModeChanged(LOW_POWER_STATE); + mVibrationSettings.mLowPowerModeListener.onLowPowerModeChanged(LOW_POWER_STATE); for (int usage : ALL_USAGES) { if (expectedAllowedVibrations.contains(usage)) { @@ -414,7 +395,7 @@ public class VibrationSettingsTest { @Test public void shouldIgnoreVibration_notInBatterySaverMode_allowsAnyUsage() { - mRegisteredPowerModeListener.onLowPowerModeChanged(NORMAL_POWER_STATE); + mVibrationSettings.mLowPowerModeListener.onLowPowerModeChanged(NORMAL_POWER_STATE); for (int usage : ALL_USAGES) { assertVibrationNotIgnoredForUsage(usage); @@ -606,7 +587,7 @@ public class VibrationSettingsTest { // Testing the broadcast flow manually. when(mAudioManagerMock.getRingerModeInternal()).thenReturn(AudioManager.RINGER_MODE_SILENT); - mVibrationSettings.mSettingChangeReceiver.onReceive(mContextSpy, + mVibrationSettings.mRingerModeBroadcastReceiver.onReceive(mContextSpy, new Intent(AudioManager.INTERNAL_RINGER_MODE_CHANGED_ACTION)); assertVibrationIgnoredForUsage(USAGE_RINGTONE, Status.IGNORED_FOR_RINGER_MODE); @@ -862,16 +843,15 @@ public class VibrationSettingsTest { mVibrationSettings.getCurrentIntensity(USAGE_RINGTONE)); // Test early update of settings based on new user id. - putUserSetting(Settings.System.RING_VIBRATION_INTENSITY, VIBRATION_INTENSITY_LOW, - NEW_USER_ID); - mVibrationSettings.mUserSwitchObserver.onUserSwitching(NEW_USER_ID); + putUserSetting(Settings.System.RING_VIBRATION_INTENSITY, VIBRATION_INTENSITY_LOW, USER_ID); + mVibrationSettings.mUserSwitchObserver.onUserSwitching(USER_ID); assertEquals(VIBRATION_INTENSITY_LOW, mVibrationSettings.getCurrentIntensity(USAGE_RINGTONE)); // Test later update of settings for UserHandle.USER_CURRENT. putUserSetting(Settings.System.RING_VIBRATION_INTENSITY, VIBRATION_INTENSITY_LOW, UserHandle.USER_CURRENT); - mVibrationSettings.mUserSwitchObserver.onUserSwitchComplete(NEW_USER_ID); + mVibrationSettings.mUserSwitchObserver.onUserSwitchComplete(USER_ID); assertEquals(VIBRATION_INTENSITY_LOW, mVibrationSettings.getCurrentIntensity(USAGE_RINGTONE)); } @@ -1019,7 +999,7 @@ public class VibrationSettingsTest { private void setRingerMode(int ringerMode) { when(mAudioManagerMock.getRingerModeInternal()).thenReturn(ringerMode); // Mock AudioManager broadcast of internal ringer mode change. - mVibrationSettings.mSettingChangeReceiver.onReceive(mContextSpy, + mVibrationSettings.mRingerModeBroadcastReceiver.onReceive(mContextSpy, new Intent(AudioManager.INTERNAL_RINGER_MODE_CHANGED_ACTION)); } @@ -1034,14 +1014,6 @@ public class VibrationSettingsTest { return new CallerInfo(attrs, uid, VIRTUAL_DEVICE_ID, opPkg, null); } - private void setBatteryReceiverRegistrationResult(Intent result) { - doAnswer(invocation -> { - mRegisteredBatteryBroadcastReceiver = invocation.getArgument(0); - return result; - }).when(mContextSpy).registerReceiver(any(BroadcastReceiver.class), - argThat(filter -> filter.matchAction(Intent.ACTION_BATTERY_CHANGED)), anyInt()); - } - private Intent getBatteryChangedIntent(int extraPluggedValue) { Intent batteryIntent = new Intent(Intent.ACTION_BATTERY_CHANGED); batteryIntent.putExtra(EXTRA_PLUGGED, extraPluggedValue); diff --git a/services/tests/wmtests/src/com/android/server/wm/InsetsSourceProviderTest.java b/services/tests/wmtests/src/com/android/server/wm/InsetsSourceProviderTest.java index e8d089c61362..f48ba65217e2 100644 --- a/services/tests/wmtests/src/com/android/server/wm/InsetsSourceProviderTest.java +++ b/services/tests/wmtests/src/com/android/server/wm/InsetsSourceProviderTest.java @@ -30,6 +30,7 @@ import static org.junit.Assert.assertNull; import static org.junit.Assert.assertTrue; import android.graphics.Insets; +import android.graphics.Point; import android.graphics.Rect; import android.platform.test.annotations.Presubmit; import android.view.InsetsSource; @@ -260,6 +261,27 @@ public class InsetsSourceProviderTest extends WindowTestsBase { } @Test + public void testUpdateInsetsControlPosition() { + final WindowState target = createWindow(null, TYPE_APPLICATION, "target"); + + final WindowState ime1 = createWindow(null, TYPE_INPUT_METHOD, "ime1"); + ime1.getFrame().set(new Rect(0, 0, 0, 0)); + mImeProvider.setWindowContainer(ime1, null, null); + mImeProvider.updateControlForTarget(target, false /* force */, null /* statsToken */); + ime1.getFrame().set(new Rect(0, 400, 500, 500)); + mImeProvider.updateInsetsControlPosition(ime1); + assertEquals(new Point(0, 400), mImeProvider.getControl(target).getSurfacePosition()); + + final WindowState ime2 = createWindow(null, TYPE_INPUT_METHOD, "ime2"); + ime2.getFrame().set(new Rect(0, 0, 0, 0)); + mImeProvider.setWindowContainer(ime2, null, null); + mImeProvider.updateControlForTarget(target, false /* force */, null /* statsToken */); + ime2.getFrame().set(new Rect(0, 400, 500, 500)); + mImeProvider.updateInsetsControlPosition(ime2); + assertEquals(new Point(0, 400), mImeProvider.getControl(target).getSurfacePosition()); + } + + @Test public void testSetRequestedVisibleTypes() { final WindowState statusBar = createWindow(null, TYPE_APPLICATION, "statusBar"); final WindowState target = createWindow(null, TYPE_APPLICATION, "target"); diff --git a/tests/NetworkSecurityConfigTest/res/xml/ct_domains.xml b/tests/NetworkSecurityConfigTest/res/xml/ct_domains.xml new file mode 100644 index 000000000000..67d4397afe7d --- /dev/null +++ b/tests/NetworkSecurityConfigTest/res/xml/ct_domains.xml @@ -0,0 +1,38 @@ +<?xml version="1.0" encoding="utf-8"?> +<network-security-config> + <base-config> + <certificateTransparency enabled="true" /> + </base-config> + <domain-config> + <domain>android.com</domain> + <trust-anchors> + <certificates src="system" /> + </trust-anchors> + </domain-config> + <domain-config> + <domain>subdomain_user.android.com</domain> + <trust-anchors> + <certificates src="user" /> + </trust-anchors> + </domain-config> + <domain-config> + <certificateTransparency enabled="true" /> + <domain>subdomain_user_ct.android.com</domain> + <trust-anchors> + <certificates src="user" /> + </trust-anchors> + </domain-config> + <domain-config> + <domain>subdomain_inline.android.com</domain> + <trust-anchors> + <certificates src="@raw/ca_certs_pem" /> + </trust-anchors> + </domain-config> + <domain-config> + <certificateTransparency enabled="true" /> + <domain>subdomain_inline_ct.android.com</domain> + <trust-anchors> + <certificates src="@raw/ca_certs_pem" /> + </trust-anchors> + </domain-config> +</network-security-config> diff --git a/tests/NetworkSecurityConfigTest/res/xml/ct_users.xml b/tests/NetworkSecurityConfigTest/res/xml/ct_users.xml new file mode 100644 index 000000000000..c35fd71c3178 --- /dev/null +++ b/tests/NetworkSecurityConfigTest/res/xml/ct_users.xml @@ -0,0 +1,15 @@ +<?xml version="1.0" encoding="utf-8"?> +<network-security-config> + <base-config> + <trust-anchors> + <certificates src="user" /> + </trust-anchors> + </base-config> + <domain-config> + <domain>android.com</domain> + </domain-config> + <domain-config> + <certificateTransparency enabled="true" /> + <domain>subdomain.android.com</domain> + </domain-config> +</network-security-config> diff --git a/tests/NetworkSecurityConfigTest/src/android/security/net/config/NetworkSecurityConfigTests.java b/tests/NetworkSecurityConfigTest/src/android/security/net/config/NetworkSecurityConfigTests.java index 0494f174f191..c6fe06858e3f 100644 --- a/tests/NetworkSecurityConfigTest/src/android/security/net/config/NetworkSecurityConfigTests.java +++ b/tests/NetworkSecurityConfigTest/src/android/security/net/config/NetworkSecurityConfigTests.java @@ -111,7 +111,8 @@ public class NetworkSecurityConfigTests extends ActivityUnitTestCase<Activity> { private NetworkSecurityConfig getSystemStoreConfig() { return new NetworkSecurityConfig.Builder() .addCertificatesEntryRef( - new CertificatesEntryRef(SystemCertificateSource.getInstance(), false)) + new CertificatesEntryRef( + SystemCertificateSource.getInstance(), false, false)) .build(); } @@ -141,7 +142,8 @@ public class NetworkSecurityConfigTests extends ActivityUnitTestCase<Activity> { NetworkSecurityConfig domain = new NetworkSecurityConfig.Builder() .setPinSet(new PinSet(pins, Long.MAX_VALUE)) .addCertificatesEntryRef( - new CertificatesEntryRef(SystemCertificateSource.getInstance(), false)) + new CertificatesEntryRef( + SystemCertificateSource.getInstance(), false, false)) .build(); ArraySet<Pair<Domain, NetworkSecurityConfig>> domainMap = new ArraySet<Pair<Domain, NetworkSecurityConfig>>(); @@ -159,7 +161,8 @@ public class NetworkSecurityConfigTests extends ActivityUnitTestCase<Activity> { NetworkSecurityConfig domain = new NetworkSecurityConfig.Builder() .setPinSet(new PinSet(pins, Long.MAX_VALUE)) .addCertificatesEntryRef( - new CertificatesEntryRef(SystemCertificateSource.getInstance(), false)) + new CertificatesEntryRef( + SystemCertificateSource.getInstance(), false, false)) .build(); ArraySet<Pair<Domain, NetworkSecurityConfig>> domainMap = new ArraySet<Pair<Domain, NetworkSecurityConfig>>(); @@ -178,7 +181,8 @@ public class NetworkSecurityConfigTests extends ActivityUnitTestCase<Activity> { NetworkSecurityConfig domain = new NetworkSecurityConfig.Builder() .setPinSet(new PinSet(pins, Long.MAX_VALUE)) .addCertificatesEntryRef( - new CertificatesEntryRef(SystemCertificateSource.getInstance(), true)) + new CertificatesEntryRef( + SystemCertificateSource.getInstance(), true, false)) .build(); ArraySet<Pair<Domain, NetworkSecurityConfig>> domainMap = new ArraySet<Pair<Domain, NetworkSecurityConfig>>(); @@ -245,7 +249,8 @@ public class NetworkSecurityConfigTests extends ActivityUnitTestCase<Activity> { NetworkSecurityConfig domain = new NetworkSecurityConfig.Builder() .setPinSet(new PinSet(pins, Long.MAX_VALUE)) .addCertificatesEntryRef( - new CertificatesEntryRef(SystemCertificateSource.getInstance(), false)) + new CertificatesEntryRef( + SystemCertificateSource.getInstance(), false, false)) .build(); ArraySet<Pair<Domain, NetworkSecurityConfig>> domainMap = new ArraySet<Pair<Domain, NetworkSecurityConfig>>(); diff --git a/tests/NetworkSecurityConfigTest/src/android/security/net/config/XmlConfigTests.java b/tests/NetworkSecurityConfigTest/src/android/security/net/config/XmlConfigTests.java index 81e05c1d4e42..542465d62a66 100644 --- a/tests/NetworkSecurityConfigTest/src/android/security/net/config/XmlConfigTests.java +++ b/tests/NetworkSecurityConfigTest/src/android/security/net/config/XmlConfigTests.java @@ -502,4 +502,47 @@ public class XmlConfigTests extends AndroidTestCase { TestUtils.assertConnectionSucceeds(context, "android.com", 443); TestUtils.assertConnectionSucceeds(context, "developer.android.com", 443); } + + public void testCertificateTransparencyDomainConfig() throws Exception { + XmlConfigSource source = new XmlConfigSource(getContext(), R.xml.ct_domains, + TestUtils.makeApplicationInfo()); + ApplicationConfig appConfig = new ApplicationConfig(source); + assertTrue(appConfig.hasPerDomainConfigs()); + NetworkSecurityConfig config = appConfig.getConfigForHostname(""); + assertNotNull(config); + // Check defaults. + assertTrue(config.isCertificateTransparencyVerificationRequired()); + + config = appConfig.getConfigForHostname("android.com"); + assertTrue(config.isCertificateTransparencyVerificationRequired()); + + config = appConfig.getConfigForHostname("subdomain_user.android.com"); + assertFalse(config.isCertificateTransparencyVerificationRequired()); + + config = appConfig.getConfigForHostname("subdomain_user_ct.android.com"); + assertTrue(config.isCertificateTransparencyVerificationRequired()); + + config = appConfig.getConfigForHostname("subdomain_inline.android.com"); + assertFalse(config.isCertificateTransparencyVerificationRequired()); + + config = appConfig.getConfigForHostname("subdomain_inline_ct.android.com"); + assertTrue(config.isCertificateTransparencyVerificationRequired()); + } + + public void testCertificateTransparencyUserConfig() throws Exception { + XmlConfigSource source = new XmlConfigSource(getContext(), R.xml.ct_users, + TestUtils.makeApplicationInfo()); + ApplicationConfig appConfig = new ApplicationConfig(source); + assertTrue(appConfig.hasPerDomainConfigs()); + NetworkSecurityConfig config = appConfig.getConfigForHostname(""); + assertNotNull(config); + // Check defaults. + assertFalse(config.isCertificateTransparencyVerificationRequired()); + + config = appConfig.getConfigForHostname("android.com"); + assertFalse(config.isCertificateTransparencyVerificationRequired()); + + config = appConfig.getConfigForHostname("subdomain.android.com"); + assertTrue(config.isCertificateTransparencyVerificationRequired()); + } } |