diff options
150 files changed, 3519 insertions, 2418 deletions
diff --git a/apex/jobscheduler/framework/java/android/os/DeviceIdleManager.java b/apex/jobscheduler/framework/java/android/os/DeviceIdleManager.java index 752c36e53bf9..6cdf5853339a 100644 --- a/apex/jobscheduler/framework/java/android/os/DeviceIdleManager.java +++ b/apex/jobscheduler/framework/java/android/os/DeviceIdleManager.java @@ -65,7 +65,7 @@ public class DeviceIdleManager { * @return package names the system has white-listed to opt out of power save restrictions, * except for device idle mode. * - * @hide Should be migrated to PowerWhitelistManager + * @hide Should be migrated to PowerExemptionManager */ @TestApi public @NonNull String[] getSystemPowerWhitelistExceptIdle() { @@ -80,7 +80,7 @@ public class DeviceIdleManager { * @return package names the system has white-listed to opt out of power save restrictions for * all modes. * - * @hide Should be migrated to PowerWhitelistManager + * @hide Should be migrated to PowerExemptionManager */ @TestApi public @NonNull String[] getSystemPowerWhitelist() { diff --git a/apex/jobscheduler/framework/java/android/os/IDeviceIdleController.aidl b/apex/jobscheduler/framework/java/android/os/IDeviceIdleController.aidl index 43d4873a3540..9d18dfe98a34 100644 --- a/apex/jobscheduler/framework/java/android/os/IDeviceIdleController.aidl +++ b/apex/jobscheduler/framework/java/android/os/IDeviceIdleController.aidl @@ -42,7 +42,7 @@ interface IDeviceIdleController { boolean isPowerSaveWhitelistExceptIdleApp(String name); boolean isPowerSaveWhitelistApp(String name); @UnsupportedAppUsage(maxTargetSdk = 30, - publicAlternatives = "Use SystemApi {@code PowerWhitelistManager#whitelistAppTemporarily(String, int, String)}.") + publicAlternatives = "Use SystemApi {@code PowerExemptionManager#addToTemporaryAllowList(String, int, int, String)}.") void addPowerSaveTempWhitelistApp(String name, long duration, int userId, int reasonCode, String reason); long addPowerSaveTempWhitelistAppForMms(String name, int userId, int reasonCode, String reason); long addPowerSaveTempWhitelistAppForSms(String name, int userId, int reasonCode, String reason); diff --git a/apex/jobscheduler/framework/java/android/os/PowerExemptionManager.java b/apex/jobscheduler/framework/java/android/os/PowerExemptionManager.java index 8445335b568e..d9a49aa52365 100644 --- a/apex/jobscheduler/framework/java/android/os/PowerExemptionManager.java +++ b/apex/jobscheduler/framework/java/android/os/PowerExemptionManager.java @@ -170,7 +170,7 @@ public class PowerExemptionManager { /** @hide */ public static final int REASON_EXEMPTED_PACKAGE = 64; /** @hide */ - public static final int REASON_ALLOWLISTED_PACKAGE = 65; + public static final int REASON_ALLOWLISTED_PACKAGE = 65; /** @hide */ public static final int REASON_APPOP = 66; @@ -193,6 +193,10 @@ public class PowerExemptionManager { * Set temp-allow-list for activity recognition. */ public static final int REASON_ACTIVITY_RECOGNITION = 103; + /** + * Set temp-allow-list for transferring accounts between users. + */ + public static final int REASON_ACCOUNT_TRANSFER = 104; /* Reason code range 200-299 are reserved for broadcast actions */ /** @@ -216,7 +220,7 @@ public class PowerExemptionManager { * Device idle system allow list, including EXCEPT-IDLE * @hide */ - public static final int REASON_SYSTEM_ALLOW_LISTED = 300; + public static final int REASON_SYSTEM_ALLOW_LISTED = 300; /** @hide */ public static final int REASON_ALARM_MANAGER_ALARM_CLOCK = 301; /** @@ -329,6 +333,7 @@ public class PowerExemptionManager { REASON_PUSH_MESSAGING, REASON_PUSH_MESSAGING_OVER_QUOTA, REASON_ACTIVITY_RECOGNITION, + REASON_ACCOUNT_TRANSFER, REASON_BOOT_COMPLETED, REASON_PRE_BOOT_COMPLETED, REASON_LOCKED_BOOT_COMPLETED, @@ -579,6 +584,8 @@ public class PowerExemptionManager { return "PUSH_MESSAGING_OVER_QUOTA"; case REASON_ACTIVITY_RECOGNITION: return "ACTIVITY_RECOGNITION"; + case REASON_ACCOUNT_TRANSFER: + return "REASON_ACCOUNT_TRANSFER"; case REASON_BOOT_COMPLETED: return "BOOT_COMPLETED"; case REASON_PRE_BOOT_COMPLETED: diff --git a/apex/jobscheduler/framework/java/android/os/PowerWhitelistManager.java b/apex/jobscheduler/framework/java/android/os/PowerWhitelistManager.java index b1b733a599c6..eba39c7573be 100644 --- a/apex/jobscheduler/framework/java/android/os/PowerWhitelistManager.java +++ b/apex/jobscheduler/framework/java/android/os/PowerWhitelistManager.java @@ -16,13 +16,6 @@ package android.os; -import static android.app.ActivityManager.PROCESS_STATE_BOUND_FOREGROUND_SERVICE; -import static android.app.ActivityManager.PROCESS_STATE_BOUND_TOP; -import static android.app.ActivityManager.PROCESS_STATE_FOREGROUND_SERVICE; -import static android.app.ActivityManager.PROCESS_STATE_PERSISTENT; -import static android.app.ActivityManager.PROCESS_STATE_PERSISTENT_UI; -import static android.app.ActivityManager.PROCESS_STATE_TOP; - import android.annotation.IntDef; import android.annotation.NonNull; import android.annotation.Nullable; @@ -33,7 +26,6 @@ import android.content.Context; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; -import java.util.Collections; import java.util.List; /** @@ -43,9 +35,11 @@ import java.util.List; * placed on the temporary whitelist are removed from that whitelist after a predetermined amount of * time. * + * @deprecated Use {@link PowerExemptionManager} instead * @hide */ @SystemApi +@Deprecated @SystemService(Context.POWER_WHITELIST_MANAGER) public class PowerWhitelistManager { private final Context mContext; @@ -53,21 +47,23 @@ public class PowerWhitelistManager { // TODO: migrate to PowerWhitelistController private final IDeviceIdleController mService; + private final PowerExemptionManager mPowerExemptionManager; + /** * Indicates that an unforeseen event has occurred and the app should be whitelisted to handle * it. */ - public static final int EVENT_UNSPECIFIED = 0; + public static final int EVENT_UNSPECIFIED = PowerExemptionManager.EVENT_UNSPECIFIED; /** * Indicates that an SMS event has occurred and the app should be whitelisted to handle it. */ - public static final int EVENT_SMS = 1; + public static final int EVENT_SMS = PowerExemptionManager.EVENT_SMS; /** * Indicates that an MMS event has occurred and the app should be whitelisted to handle it. */ - public static final int EVENT_MMS = 2; + public static final int EVENT_MMS = PowerExemptionManager.EVENT_MMS; /** * @hide @@ -84,12 +80,14 @@ public class PowerWhitelistManager { /** * Allow the temp allowlist behavior, plus allow foreground service start from background. */ - public static final int TEMPORARY_ALLOWLIST_TYPE_FOREGROUND_SERVICE_ALLOWED = 0; + public static final int TEMPORARY_ALLOWLIST_TYPE_FOREGROUND_SERVICE_ALLOWED = + PowerExemptionManager.TEMPORARY_ALLOW_LIST_TYPE_FOREGROUND_SERVICE_ALLOWED; /** * Only allow the temp allowlist behavior, not allow foreground service start from * background. */ - public static final int TEMPORARY_ALLOWLIST_TYPE_FOREGROUND_SERVICE_NOT_ALLOWED = 1; + public static final int TEMPORARY_ALLOWLIST_TYPE_FOREGROUND_SERVICE_NOT_ALLOWED = + PowerExemptionManager.TEMPORARY_ALLOW_LIST_TYPE_FOREGROUND_SERVICE_NOT_ALLOWED; /** * The list of temp allowlist types. @@ -107,73 +105,83 @@ public class PowerWhitelistManager { * BG-FGS-launch is denied. * @hide */ - public static final int REASON_DENIED = -1; + public static final int REASON_DENIED = PowerExemptionManager.REASON_DENIED; /* Reason code range 0-9 are reserved for default reasons */ /** * The default reason code if reason is unknown. */ - public static final int REASON_UNKNOWN = 0; + public static final int REASON_UNKNOWN = PowerExemptionManager.REASON_UNKNOWN; /** * Use REASON_OTHER if there is no better choice. */ - public static final int REASON_OTHER = 1; + public static final int REASON_OTHER = PowerExemptionManager.REASON_OTHER; /* Reason code range 10-49 are reserved for BG-FGS-launch allowed proc states */ /** @hide */ - public static final int REASON_PROC_STATE_PERSISTENT = 10; + public static final int REASON_PROC_STATE_PERSISTENT = + PowerExemptionManager.REASON_PROC_STATE_PERSISTENT; /** @hide */ - public static final int REASON_PROC_STATE_PERSISTENT_UI = 11; + public static final int REASON_PROC_STATE_PERSISTENT_UI = + PowerExemptionManager.REASON_PROC_STATE_PERSISTENT_UI; /** @hide */ - public static final int REASON_PROC_STATE_TOP = 12; + public static final int REASON_PROC_STATE_TOP = PowerExemptionManager.REASON_PROC_STATE_TOP; /** @hide */ - public static final int REASON_PROC_STATE_BTOP = 13; + public static final int REASON_PROC_STATE_BTOP = PowerExemptionManager.REASON_PROC_STATE_BTOP; /** @hide */ - public static final int REASON_PROC_STATE_FGS = 14; + public static final int REASON_PROC_STATE_FGS = PowerExemptionManager.REASON_PROC_STATE_FGS; /** @hide */ - public static final int REASON_PROC_STATE_BFGS = 15; + public static final int REASON_PROC_STATE_BFGS = PowerExemptionManager.REASON_PROC_STATE_BFGS; /* Reason code range 50-99 are reserved for BG-FGS-launch allowed reasons */ /** @hide */ - public static final int REASON_UID_VISIBLE = 50; + public static final int REASON_UID_VISIBLE = PowerExemptionManager.REASON_UID_VISIBLE; /** @hide */ - public static final int REASON_SYSTEM_UID = 51; + public static final int REASON_SYSTEM_UID = PowerExemptionManager.REASON_SYSTEM_UID; /** @hide */ - public static final int REASON_ACTIVITY_STARTER = 52; + public static final int REASON_ACTIVITY_STARTER = PowerExemptionManager.REASON_ACTIVITY_STARTER; /** @hide */ - public static final int REASON_START_ACTIVITY_FLAG = 53; + public static final int REASON_START_ACTIVITY_FLAG = + PowerExemptionManager.REASON_START_ACTIVITY_FLAG; /** @hide */ - public static final int REASON_FGS_BINDING = 54; + public static final int REASON_FGS_BINDING = PowerExemptionManager.REASON_FGS_BINDING; /** @hide */ - public static final int REASON_DEVICE_OWNER = 55; + public static final int REASON_DEVICE_OWNER = PowerExemptionManager.REASON_DEVICE_OWNER; /** @hide */ - public static final int REASON_PROFILE_OWNER = 56; + public static final int REASON_PROFILE_OWNER = PowerExemptionManager.REASON_PROFILE_OWNER; /** @hide */ - public static final int REASON_COMPANION_DEVICE_MANAGER = 57; + public static final int REASON_COMPANION_DEVICE_MANAGER = + PowerExemptionManager.REASON_COMPANION_DEVICE_MANAGER; /** * START_ACTIVITIES_FROM_BACKGROUND permission. * @hide */ - public static final int REASON_BACKGROUND_ACTIVITY_PERMISSION = 58; + public static final int REASON_BACKGROUND_ACTIVITY_PERMISSION = + PowerExemptionManager.REASON_BACKGROUND_ACTIVITY_PERMISSION; /** * START_FOREGROUND_SERVICES_FROM_BACKGROUND permission. * @hide */ - public static final int REASON_BACKGROUND_FGS_PERMISSION = 59; + public static final int REASON_BACKGROUND_FGS_PERMISSION = + PowerExemptionManager.REASON_BACKGROUND_FGS_PERMISSION; /** @hide */ - public static final int REASON_INSTR_BACKGROUND_ACTIVITY_PERMISSION = 60; + public static final int REASON_INSTR_BACKGROUND_ACTIVITY_PERMISSION = + PowerExemptionManager.REASON_INSTR_BACKGROUND_ACTIVITY_PERMISSION; /** @hide */ - public static final int REASON_INSTR_BACKGROUND_FGS_PERMISSION = 61; + public static final int REASON_INSTR_BACKGROUND_FGS_PERMISSION = + PowerExemptionManager.REASON_INSTR_BACKGROUND_FGS_PERMISSION; /** @hide */ - public static final int REASON_SYSTEM_ALERT_WINDOW_PERMISSION = 62; + public static final int REASON_SYSTEM_ALERT_WINDOW_PERMISSION = + PowerExemptionManager.REASON_SYSTEM_ALERT_WINDOW_PERMISSION; /** @hide */ - public static final int REASON_DEVICE_DEMO_MODE = 63; + public static final int REASON_DEVICE_DEMO_MODE = PowerExemptionManager.REASON_DEVICE_DEMO_MODE; /** @hide */ - public static final int REASON_EXEMPTED_PACKAGE = 64; + public static final int REASON_EXEMPTED_PACKAGE = PowerExemptionManager.REASON_EXEMPTED_PACKAGE; /** @hide */ - public static final int REASON_ALLOWLISTED_PACKAGE = 65; + public static final int REASON_ALLOWLISTED_PACKAGE = + PowerExemptionManager.REASON_ALLOWLISTED_PACKAGE; /** @hide */ - public static final int REASON_APPOP = 66; + public static final int REASON_APPOP = PowerExemptionManager.REASON_APPOP; /* BG-FGS-launch is allowed by temp-allowlist or system-allowlist. Reason code for temp and system allowlist starts here. @@ -181,117 +189,128 @@ public class PowerWhitelistManager { /** * Set temp-allowlist for location geofence purpose. */ - public static final int REASON_GEOFENCING = 100; + public static final int REASON_GEOFENCING = PowerExemptionManager.REASON_GEOFENCING; /** * Set temp-allowlist for server push messaging. */ - public static final int REASON_PUSH_MESSAGING = 101; + public static final int REASON_PUSH_MESSAGING = PowerExemptionManager.REASON_PUSH_MESSAGING; /** * Set temp-allowlist for server push messaging over the quota. */ - public static final int REASON_PUSH_MESSAGING_OVER_QUOTA = 102; + public static final int REASON_PUSH_MESSAGING_OVER_QUOTA = + PowerExemptionManager.REASON_PUSH_MESSAGING_OVER_QUOTA; /** * Set temp-allowlist for activity recognition. */ - public static final int REASON_ACTIVITY_RECOGNITION = 103; + public static final int REASON_ACTIVITY_RECOGNITION = + PowerExemptionManager.REASON_ACTIVITY_RECOGNITION; /* Reason code range 200-299 are reserved for broadcast actions */ /** * Broadcast ACTION_BOOT_COMPLETED. * @hide */ - public static final int REASON_BOOT_COMPLETED = 200; + public static final int REASON_BOOT_COMPLETED = PowerExemptionManager.REASON_BOOT_COMPLETED; /** * Broadcast ACTION_PRE_BOOT_COMPLETED. * @hide */ - public static final int REASON_PRE_BOOT_COMPLETED = 201; + public static final int REASON_PRE_BOOT_COMPLETED = + PowerExemptionManager.REASON_PRE_BOOT_COMPLETED; /** * Broadcast ACTION_LOCKED_BOOT_COMPLETED. * @hide */ - public static final int REASON_LOCKED_BOOT_COMPLETED = 202; + public static final int REASON_LOCKED_BOOT_COMPLETED = + PowerExemptionManager.REASON_LOCKED_BOOT_COMPLETED; /* Reason code range 300-399 are reserved for other internal reasons */ /** * Device idle system allowlist, including EXCEPT-IDLE * @hide */ - public static final int REASON_SYSTEM_ALLOW_LISTED = 300; + public static final int REASON_SYSTEM_ALLOW_LISTED = + PowerExemptionManager.REASON_SYSTEM_ALLOW_LISTED; /** @hide */ - public static final int REASON_ALARM_MANAGER_ALARM_CLOCK = 301; + public static final int REASON_ALARM_MANAGER_ALARM_CLOCK = + PowerExemptionManager.REASON_ALARM_MANAGER_ALARM_CLOCK; /** * AlarmManagerService. * @hide */ - public static final int REASON_ALARM_MANAGER_WHILE_IDLE = 302; + public static final int REASON_ALARM_MANAGER_WHILE_IDLE = + PowerExemptionManager.REASON_ALARM_MANAGER_WHILE_IDLE; /** * ActiveServices. * @hide */ - public static final int REASON_SERVICE_LAUNCH = 303; + public static final int REASON_SERVICE_LAUNCH = PowerExemptionManager.REASON_SERVICE_LAUNCH; /** * KeyChainSystemService. * @hide */ - public static final int REASON_KEY_CHAIN = 304; + public static final int REASON_KEY_CHAIN = PowerExemptionManager.REASON_KEY_CHAIN; /** * PackageManagerService. * @hide */ - public static final int REASON_PACKAGE_VERIFIER = 305; + public static final int REASON_PACKAGE_VERIFIER = PowerExemptionManager.REASON_PACKAGE_VERIFIER; /** * SyncManager. * @hide */ - public static final int REASON_SYNC_MANAGER = 306; + public static final int REASON_SYNC_MANAGER = PowerExemptionManager.REASON_SYNC_MANAGER; /** * DomainVerificationProxyV1. * @hide */ - public static final int REASON_DOMAIN_VERIFICATION_V1 = 307; + public static final int REASON_DOMAIN_VERIFICATION_V1 = + PowerExemptionManager.REASON_DOMAIN_VERIFICATION_V1; /** * DomainVerificationProxyV2. * @hide */ - public static final int REASON_DOMAIN_VERIFICATION_V2 = 308; + public static final int REASON_DOMAIN_VERIFICATION_V2 = + PowerExemptionManager.REASON_DOMAIN_VERIFICATION_V2; /** @hide */ public static final int REASON_VPN = 309; /** * NotificationManagerService. * @hide */ - public static final int REASON_NOTIFICATION_SERVICE = 310; + public static final int REASON_NOTIFICATION_SERVICE = + PowerExemptionManager.REASON_NOTIFICATION_SERVICE; /** * Broadcast ACTION_MY_PACKAGE_REPLACED. * @hide */ - public static final int REASON_PACKAGE_REPLACED = 311; + public static final int REASON_PACKAGE_REPLACED = PowerExemptionManager.REASON_PACKAGE_REPLACED; /** * LocationProviderManager. * @hide */ - public static final int REASON_LOCATION_PROVIDER = 312; + public static final int REASON_LOCATION_PROVIDER = + PowerExemptionManager.REASON_LOCATION_PROVIDER; /** * MediaButtonReceiver. * @hide */ - public static final int REASON_MEDIA_BUTTON = 313; + public static final int REASON_MEDIA_BUTTON = PowerExemptionManager.REASON_MEDIA_BUTTON; /** * InboundSmsHandler. * @hide */ - public static final int REASON_EVENT_SMS = 314; + public static final int REASON_EVENT_SMS = PowerExemptionManager.REASON_EVENT_SMS; /** * InboundSmsHandler. * @hide */ - public static final int REASON_EVENT_MMS = 315; + public static final int REASON_EVENT_MMS = PowerExemptionManager.REASON_EVENT_MMS; /** * Shell app. * @hide */ - public static final int REASON_SHELL = 316; + public static final int REASON_SHELL = PowerExemptionManager.REASON_SHELL; /** * The list of BG-FGS-Launch and temp-allowlist reason code. @@ -360,26 +379,29 @@ public class PowerWhitelistManager { public PowerWhitelistManager(@NonNull Context context) { mContext = context; mService = context.getSystemService(DeviceIdleManager.class).getService(); + mPowerExemptionManager = context.getSystemService(PowerExemptionManager.class); } /** * Add the specified package to the permanent power save whitelist. + * + * @deprecated Use {@link PowerExemptionManager#addToPermanentAllowList(String)} instead */ + @Deprecated @RequiresPermission(android.Manifest.permission.DEVICE_POWER) public void addToWhitelist(@NonNull String packageName) { - addToWhitelist(Collections.singletonList(packageName)); + mPowerExemptionManager.addToPermanentAllowList(packageName); } /** * Add the specified packages to the permanent power save whitelist. + * + * @deprecated Use {@link PowerExemptionManager#addToPermanentAllowList(List)} instead */ + @Deprecated @RequiresPermission(android.Manifest.permission.DEVICE_POWER) public void addToWhitelist(@NonNull List<String> packageNames) { - try { - mService.addPowerSaveWhitelistApps(packageNames); - } catch (RemoteException e) { - throw e.rethrowFromSystemServer(); - } + mPowerExemptionManager.addToPermanentAllowList(packageNames); } /** @@ -388,19 +410,13 @@ public class PowerWhitelistManager { * * @param includingIdle Set to true if the app should be whitelisted from device idle as well * as other power save restrictions + * @deprecated Use {@link PowerExemptionManager#getAllowListedAppIds(boolean)} instead * @hide */ + @Deprecated @NonNull public int[] getWhitelistedAppIds(boolean includingIdle) { - try { - if (includingIdle) { - return mService.getAppIdWhitelist(); - } else { - return mService.getAppIdWhitelistExceptIdle(); - } - } catch (RemoteException e) { - throw e.rethrowFromSystemServer(); - } + return mPowerExemptionManager.getAllowListedAppIds(includingIdle); } /** @@ -409,18 +425,12 @@ public class PowerWhitelistManager { * * @param includingIdle Set to true if the app should be whitelisted from device * idle as well as other power save restrictions + * @deprecated Use {@link PowerExemptionManager#isAllowListed(String, boolean)} instead * @hide */ + @Deprecated public boolean isWhitelisted(@NonNull String packageName, boolean includingIdle) { - try { - if (includingIdle) { - return mService.isPowerSaveWhitelistApp(packageName); - } else { - return mService.isPowerSaveWhitelistExceptIdleApp(packageName); - } - } catch (RemoteException e) { - throw e.rethrowFromSystemServer(); - } + return mPowerExemptionManager.isAllowListed(packageName, includingIdle); } /** @@ -429,14 +439,12 @@ public class PowerWhitelistManager { * whitelisted by default by the system cannot be removed. * * @param packageName The app to remove from the whitelist + * @deprecated Use {@link PowerExemptionManager#removeFromAllowList(String)} instead */ + @Deprecated @RequiresPermission(android.Manifest.permission.DEVICE_POWER) public void removeFromWhitelist(@NonNull String packageName) { - try { - mService.removePowerSaveWhitelistApp(packageName); - } catch (RemoteException e) { - throw e.rethrowFromSystemServer(); - } + mPowerExemptionManager.removeFromAllowList(packageName); } /** @@ -446,16 +454,14 @@ public class PowerWhitelistManager { * @param durationMs How long to keep the app on the temp whitelist for (in milliseconds) * @param reasonCode one of {@link ReasonCode}, use {@link #REASON_UNKNOWN} if not sure. * @param reason a optional human readable reason string, could be null or empty string. + * @deprecated Use {@link PowerExemptionManager#addToTemporaryAllowList( + * String, long, int, String)} instead */ + @Deprecated @RequiresPermission(android.Manifest.permission.CHANGE_DEVICE_IDLE_TEMP_WHITELIST) public void whitelistAppTemporarily(@NonNull String packageName, long durationMs, @ReasonCode int reasonCode, @Nullable String reason) { - try { - mService.addPowerSaveTempWhitelistApp(packageName, durationMs, mContext.getUserId(), - reasonCode, reason); - } catch (RemoteException e) { - throw e.rethrowFromSystemServer(); - } + mPowerExemptionManager.addToTemporaryAllowList(packageName, durationMs, reasonCode, reason); } /** @@ -463,12 +469,14 @@ public class PowerWhitelistManager { * * @param packageName The package to add to the temp whitelist * @param durationMs How long to keep the app on the temp whitelist for (in milliseconds) - * @deprecated Use {@link #whitelistAppTemporarily(String, long, int, String)} instead + * @deprecated Use {@link PowerExemptionManager#addToTemporaryAllowList( + * String, long, int, String)} instead */ @Deprecated @RequiresPermission(android.Manifest.permission.CHANGE_DEVICE_IDLE_TEMP_WHITELIST) public void whitelistAppTemporarily(@NonNull String packageName, long durationMs) { - whitelistAppTemporarily(packageName, durationMs, REASON_UNKNOWN, packageName); + mPowerExemptionManager.addToTemporaryAllowList( + packageName, durationMs, REASON_UNKNOWN, packageName); } /** @@ -481,13 +489,15 @@ public class PowerWhitelistManager { * @param reason A human-readable reason explaining why the app is temp whitelisted. Only * used for logging purposes. Could be null or empty string. * @return The duration (in milliseconds) that the app is whitelisted for - * @deprecated Use {@link #whitelistAppTemporarilyForEvent(String, int, int, String)} instead + * @deprecated Use {@link PowerExemptionManager#addToTemporaryAllowListForEvent( + * String, int, int, String)} instead */ @Deprecated @RequiresPermission(android.Manifest.permission.CHANGE_DEVICE_IDLE_TEMP_WHITELIST) public long whitelistAppTemporarilyForEvent(@NonNull String packageName, @WhitelistEvent int event, @Nullable String reason) { - return whitelistAppTemporarilyForEvent(packageName, event, REASON_UNKNOWN, reason); + return mPowerExemptionManager.addToTemporaryAllowListForEvent( + packageName, event, REASON_UNKNOWN, reason); } /** @@ -501,47 +511,25 @@ public class PowerWhitelistManager { * @param reason A human-readable reason explaining why the app is temp whitelisted. Only * used for logging purposes. Could be null or empty string. * @return The duration (in milliseconds) that the app is whitelisted for + * @deprecated Use {@link PowerExemptionManager#addToTemporaryAllowListForEvent( + * String, int, int, String)} instead */ + @Deprecated @RequiresPermission(android.Manifest.permission.CHANGE_DEVICE_IDLE_TEMP_WHITELIST) public long whitelistAppTemporarilyForEvent(@NonNull String packageName, @WhitelistEvent int event, @ReasonCode int reasonCode, @Nullable String reason) { - try { - switch (event) { - case EVENT_MMS: - return mService.addPowerSaveTempWhitelistAppForMms( - packageName, mContext.getUserId(), reasonCode, reason); - case EVENT_SMS: - return mService.addPowerSaveTempWhitelistAppForSms( - packageName, mContext.getUserId(), reasonCode, reason); - case EVENT_UNSPECIFIED: - default: - return mService.whitelistAppTemporarily( - packageName, mContext.getUserId(), reasonCode, reason); - } - } catch (RemoteException e) { - throw e.rethrowFromSystemServer(); - } + return mPowerExemptionManager.addToTemporaryAllowListForEvent( + packageName, event, reasonCode, reason); } /** * @hide + * + * @deprecated Use {@link PowerExemptionManager#getReasonCodeFromProcState(int)} instead */ + @Deprecated public static @ReasonCode int getReasonCodeFromProcState(int procState) { - if (procState <= PROCESS_STATE_PERSISTENT) { - return REASON_PROC_STATE_PERSISTENT; - } else if (procState <= PROCESS_STATE_PERSISTENT_UI) { - return REASON_PROC_STATE_PERSISTENT_UI; - } else if (procState <= PROCESS_STATE_TOP) { - return REASON_PROC_STATE_TOP; - } else if (procState <= PROCESS_STATE_BOUND_TOP) { - return REASON_PROC_STATE_BTOP; - } else if (procState <= PROCESS_STATE_FOREGROUND_SERVICE) { - return REASON_PROC_STATE_FGS; - } else if (procState <= PROCESS_STATE_BOUND_FOREGROUND_SERVICE) { - return REASON_PROC_STATE_BFGS; - } else { - return REASON_DENIED; - } + return PowerExemptionManager.getReasonCodeFromProcState(procState); } /** @@ -549,111 +537,10 @@ public class PowerWhitelistManager { * @hide * @param reasonCode * @return string name of the reason code. + * @deprecated Use {@link PowerExemptionManager#reasonCodeToString(int)} instead */ + @Deprecated public static String reasonCodeToString(@ReasonCode int reasonCode) { - switch (reasonCode) { - case REASON_DENIED: - return "DENIED"; - case REASON_UNKNOWN: - return "UNKNOWN"; - case REASON_OTHER: - return "OTHER"; - case REASON_PROC_STATE_PERSISTENT: - return "PROC_STATE_PERSISTENT"; - case REASON_PROC_STATE_PERSISTENT_UI: - return "PROC_STATE_PERSISTENT_UI"; - case REASON_PROC_STATE_TOP: - return "PROC_STATE_TOP"; - case REASON_PROC_STATE_BTOP: - return "PROC_STATE_BTOP"; - case REASON_PROC_STATE_FGS: - return "PROC_STATE_FGS"; - case REASON_PROC_STATE_BFGS: - return "PROC_STATE_BFGS"; - case REASON_UID_VISIBLE: - return "UID_VISIBLE"; - case REASON_SYSTEM_UID: - return "SYSTEM_UID"; - case REASON_ACTIVITY_STARTER: - return "ACTIVITY_STARTER"; - case REASON_START_ACTIVITY_FLAG: - return "START_ACTIVITY_FLAG"; - case REASON_FGS_BINDING: - return "FGS_BINDING"; - case REASON_DEVICE_OWNER: - return "DEVICE_OWNER"; - case REASON_PROFILE_OWNER: - return "PROFILE_OWNER"; - case REASON_COMPANION_DEVICE_MANAGER: - return "COMPANION_DEVICE_MANAGER"; - case REASON_BACKGROUND_ACTIVITY_PERMISSION: - return "BACKGROUND_ACTIVITY_PERMISSION"; - case REASON_BACKGROUND_FGS_PERMISSION: - return "BACKGROUND_FGS_PERMISSION"; - case REASON_INSTR_BACKGROUND_ACTIVITY_PERMISSION: - return "INSTR_BACKGROUND_ACTIVITY_PERMISSION"; - case REASON_INSTR_BACKGROUND_FGS_PERMISSION: - return "INSTR_BACKGROUND_FGS_PERMISSION"; - case REASON_SYSTEM_ALERT_WINDOW_PERMISSION: - return "SYSTEM_ALERT_WINDOW_PERMISSION"; - case REASON_DEVICE_DEMO_MODE: - return "DEVICE_DEMO_MODE"; - case REASON_EXEMPTED_PACKAGE: - return "EXEMPTED_PACKAGE"; - case REASON_ALLOWLISTED_PACKAGE: - return "ALLOWLISTED_PACKAGE"; - case REASON_APPOP: - return "APPOP"; - case REASON_GEOFENCING: - return "GEOFENCING"; - case REASON_PUSH_MESSAGING: - return "PUSH_MESSAGING"; - case REASON_PUSH_MESSAGING_OVER_QUOTA: - return "PUSH_MESSAGING_OVER_QUOTA"; - case REASON_ACTIVITY_RECOGNITION: - return "ACTIVITY_RECOGNITION"; - case REASON_BOOT_COMPLETED: - return "BOOT_COMPLETED"; - case REASON_PRE_BOOT_COMPLETED: - return "PRE_BOOT_COMPLETED"; - case REASON_LOCKED_BOOT_COMPLETED: - return "LOCKED_BOOT_COMPLETED"; - case REASON_SYSTEM_ALLOW_LISTED: - return "SYSTEM_ALLOW_LISTED"; - case REASON_ALARM_MANAGER_ALARM_CLOCK: - return "ALARM_MANAGER_ALARM_CLOCK"; - case REASON_ALARM_MANAGER_WHILE_IDLE: - return "ALARM_MANAGER_WHILE_IDLE"; - case REASON_SERVICE_LAUNCH: - return "SERVICE_LAUNCH"; - case REASON_KEY_CHAIN: - return "KEY_CHAIN"; - case REASON_PACKAGE_VERIFIER: - return "PACKAGE_VERIFIER"; - case REASON_SYNC_MANAGER: - return "SYNC_MANAGER"; - case REASON_DOMAIN_VERIFICATION_V1: - return "DOMAIN_VERIFICATION_V1"; - case REASON_DOMAIN_VERIFICATION_V2: - return "DOMAIN_VERIFICATION_V2"; - case REASON_VPN: - return "VPN"; - case REASON_NOTIFICATION_SERVICE: - return "NOTIFICATION_SERVICE"; - case REASON_PACKAGE_REPLACED: - return "PACKAGE_REPLACED"; - case REASON_LOCATION_PROVIDER: - return "LOCATION_PROVIDER"; - case REASON_MEDIA_BUTTON: - return "MEDIA_BUTTON"; - case REASON_EVENT_SMS: - return "EVENT_SMS"; - case REASON_EVENT_MMS: - return "EVENT_MMS"; - case REASON_SHELL: - return "SHELL"; - default: - return "(unknown:" + reasonCode + ")"; - } + return PowerExemptionManager.reasonCodeToString(reasonCode); } } diff --git a/core/api/current.txt b/core/api/current.txt index 5a3125a0373b..c0940d6b81bc 100644 --- a/core/api/current.txt +++ b/core/api/current.txt @@ -10501,6 +10501,7 @@ package android.content { field public static final String DEVICE_POLICY_SERVICE = "device_policy"; field public static final String DISPLAY_HASH_SERVICE = "display_hash"; field public static final String DISPLAY_SERVICE = "display"; + field public static final String DOMAIN_VERIFICATION_SERVICE = "domain_verification"; field public static final String DOWNLOAD_SERVICE = "download"; field public static final String DROPBOX_SERVICE = "dropbox"; field public static final String EUICC_SERVICE = "euicc"; @@ -42015,6 +42016,7 @@ package android.telephony { method public static int getDefaultSmsSubscriptionId(); method public static int getDefaultSubscriptionId(); method public static int getDefaultVoiceSubscriptionId(); + method public int getDeviceToDeviceStatusSharing(int); method @NonNull @RequiresPermission(android.Manifest.permission.READ_PHONE_STATE) public java.util.List<android.telephony.SubscriptionInfo> getOpportunisticSubscriptions(); method public static int getSlotIndex(int); method @Nullable public int[] getSubscriptionIds(int); @@ -42027,6 +42029,7 @@ package android.telephony { method public void removeOnOpportunisticSubscriptionsChangedListener(@NonNull android.telephony.SubscriptionManager.OnOpportunisticSubscriptionsChangedListener); method public void removeOnSubscriptionsChangedListener(android.telephony.SubscriptionManager.OnSubscriptionsChangedListener); method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public void removeSubscriptionsFromGroup(@NonNull java.util.List<java.lang.Integer>, @NonNull android.os.ParcelUuid); + method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public void setDeviceToDeviceStatusSharing(int, int); method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public boolean setOpportunistic(boolean, int); method public void setSubscriptionOverrideCongested(int, boolean, long); method public void setSubscriptionOverrideCongested(int, boolean, @NonNull int[], long); @@ -42038,6 +42041,11 @@ package android.telephony { field public static final String ACTION_DEFAULT_SUBSCRIPTION_CHANGED = "android.telephony.action.DEFAULT_SUBSCRIPTION_CHANGED"; field public static final String ACTION_MANAGE_SUBSCRIPTION_PLANS = "android.telephony.action.MANAGE_SUBSCRIPTION_PLANS"; field public static final String ACTION_REFRESH_SUBSCRIPTION_PLANS = "android.telephony.action.REFRESH_SUBSCRIPTION_PLANS"; + field public static final int D2D_SHARING_ALL = 3; // 0x3 + field public static final int D2D_SHARING_ALL_CONTACTS = 1; // 0x1 + field public static final int D2D_SHARING_DISABLED = 0; // 0x0 + field public static final int D2D_SHARING_STARRED_CONTACTS = 2; // 0x2 + field public static final String D2D_STATUS_SHARING = "d2d_sharing_status"; field public static final int DATA_ROAMING_DISABLE = 0; // 0x0 field public static final int DATA_ROAMING_ENABLE = 1; // 0x1 field public static final int DEFAULT_SUBSCRIPTION_ID = 2147483647; // 0x7fffffff @@ -51451,7 +51459,6 @@ package android.view.inputmethod { method public int describeContents(); method public void dump(android.util.Printer, String); method public android.content.ComponentName getComponent(); - method public int getConfigChanges(); method public String getId(); method public int getIsDefaultResourceId(); method public String getPackageName(); diff --git a/core/api/system-current.txt b/core/api/system-current.txt index 6019ab56dea7..bfc205b9f9a6 100644 --- a/core/api/system-current.txt +++ b/core/api/system-current.txt @@ -2162,7 +2162,6 @@ package android.content { field public static final int BIND_ALLOW_FOREGROUND_SERVICE_STARTS_FROM_BACKGROUND = 262144; // 0x40000 field public static final String CONTENT_SUGGESTIONS_SERVICE = "content_suggestions"; field public static final String CONTEXTHUB_SERVICE = "contexthub"; - field public static final String DOMAIN_VERIFICATION_SERVICE = "domain_verification"; field public static final String ETHERNET_SERVICE = "ethernet"; field public static final String EUICC_CARD_SERVICE = "euicc_card"; field public static final String FONT_SERVICE = "font"; @@ -2174,7 +2173,6 @@ package android.content { field public static final String OEM_LOCK_SERVICE = "oem_lock"; field public static final String PERMISSION_SERVICE = "permission"; field public static final String PERSISTENT_DATA_BLOCK_SERVICE = "persistent_data_block"; - field public static final String POWER_EXEMPTION_SERVICE = "power_exemption"; field public static final String REBOOT_READINESS_SERVICE = "reboot_readiness"; field public static final String ROLLBACK_SERVICE = "rollback"; field public static final String SEARCH_UI_SERVICE = "search_ui"; @@ -2241,6 +2239,7 @@ package android.content { field @RequiresPermission(android.Manifest.permission.REVIEW_ACCESSIBILITY_SERVICES) public static final String ACTION_REVIEW_ACCESSIBILITY_SERVICES = "android.intent.action.REVIEW_ACCESSIBILITY_SERVICES"; field @RequiresPermission(android.Manifest.permission.GRANT_RUNTIME_PERMISSIONS) public static final String ACTION_REVIEW_ONGOING_PERMISSION_USAGE = "android.intent.action.REVIEW_ONGOING_PERMISSION_USAGE"; field public static final String ACTION_REVIEW_PERMISSIONS = "android.intent.action.REVIEW_PERMISSIONS"; + field @RequiresPermission(android.Manifest.permission.GRANT_RUNTIME_PERMISSIONS) public static final String ACTION_REVIEW_PERMISSION_HISTORY = "android.intent.action.REVIEW_PERMISSION_HISTORY"; field @RequiresPermission(android.Manifest.permission.GRANT_RUNTIME_PERMISSIONS) public static final String ACTION_REVIEW_PERMISSION_USAGE = "android.intent.action.REVIEW_PERMISSION_USAGE"; field public static final String ACTION_ROLLBACK_COMMITTED = "android.intent.action.ROLLBACK_COMMITTED"; field public static final String ACTION_SHOW_SUSPENDED_APP_DETAILS = "android.intent.action.SHOW_SUSPENDED_APP_DETAILS"; @@ -7521,12 +7520,12 @@ package android.net.util { package android.net.vcn { public class VcnManager { - method @RequiresPermission(android.Manifest.permission.NETWORK_FACTORY) public void addVcnNetworkPolicyListener(@NonNull java.util.concurrent.Executor, @NonNull android.net.vcn.VcnManager.VcnNetworkPolicyListener); + method @RequiresPermission(android.Manifest.permission.NETWORK_FACTORY) public void addVcnNetworkPolicyChangeListener(@NonNull java.util.concurrent.Executor, @NonNull android.net.vcn.VcnManager.VcnNetworkPolicyChangeListener); method @NonNull @RequiresPermission(android.Manifest.permission.NETWORK_FACTORY) public android.net.vcn.VcnNetworkPolicyResult applyVcnNetworkPolicy(@NonNull android.net.NetworkCapabilities, @NonNull android.net.LinkProperties); - method public void removeVcnNetworkPolicyListener(@NonNull android.net.vcn.VcnManager.VcnNetworkPolicyListener); + method @RequiresPermission(android.Manifest.permission.NETWORK_FACTORY) public void removeVcnNetworkPolicyChangeListener(@NonNull android.net.vcn.VcnManager.VcnNetworkPolicyChangeListener); } - public static interface VcnManager.VcnNetworkPolicyListener { + public static interface VcnManager.VcnNetworkPolicyChangeListener { method public void onPolicyChanged(); } @@ -8184,6 +8183,7 @@ package android.os { field public static final int EVENT_MMS = 2; // 0x2 field public static final int EVENT_SMS = 1; // 0x1 field public static final int EVENT_UNSPECIFIED = 0; // 0x0 + field public static final int REASON_ACCOUNT_TRANSFER = 104; // 0x68 field public static final int REASON_ACTIVITY_RECOGNITION = 103; // 0x67 field public static final int REASON_GEOFENCING = 100; // 0x64 field public static final int REASON_OTHER = 1; // 0x1 @@ -8224,25 +8224,25 @@ package android.os { field public static final int USER_ACTIVITY_FLAG_NO_CHANGE_LIGHTS = 1; // 0x1 } - public class PowerWhitelistManager { - method @RequiresPermission(android.Manifest.permission.DEVICE_POWER) public void addToWhitelist(@NonNull String); - method @RequiresPermission(android.Manifest.permission.DEVICE_POWER) public void addToWhitelist(@NonNull java.util.List<java.lang.String>); - method @RequiresPermission(android.Manifest.permission.DEVICE_POWER) public void removeFromWhitelist(@NonNull String); - method @RequiresPermission(android.Manifest.permission.CHANGE_DEVICE_IDLE_TEMP_WHITELIST) public void whitelistAppTemporarily(@NonNull String, long, int, @Nullable String); + @Deprecated public class PowerWhitelistManager { + method @Deprecated @RequiresPermission(android.Manifest.permission.DEVICE_POWER) public void addToWhitelist(@NonNull String); + method @Deprecated @RequiresPermission(android.Manifest.permission.DEVICE_POWER) public void addToWhitelist(@NonNull java.util.List<java.lang.String>); + method @Deprecated @RequiresPermission(android.Manifest.permission.DEVICE_POWER) public void removeFromWhitelist(@NonNull String); + method @Deprecated @RequiresPermission(android.Manifest.permission.CHANGE_DEVICE_IDLE_TEMP_WHITELIST) public void whitelistAppTemporarily(@NonNull String, long, int, @Nullable String); method @Deprecated @RequiresPermission(android.Manifest.permission.CHANGE_DEVICE_IDLE_TEMP_WHITELIST) public void whitelistAppTemporarily(@NonNull String, long); method @Deprecated @RequiresPermission(android.Manifest.permission.CHANGE_DEVICE_IDLE_TEMP_WHITELIST) public long whitelistAppTemporarilyForEvent(@NonNull String, int, @Nullable String); - method @RequiresPermission(android.Manifest.permission.CHANGE_DEVICE_IDLE_TEMP_WHITELIST) public long whitelistAppTemporarilyForEvent(@NonNull String, int, int, @Nullable String); - field public static final int EVENT_MMS = 2; // 0x2 - field public static final int EVENT_SMS = 1; // 0x1 - field public static final int EVENT_UNSPECIFIED = 0; // 0x0 - field public static final int REASON_ACTIVITY_RECOGNITION = 103; // 0x67 - field public static final int REASON_GEOFENCING = 100; // 0x64 - field public static final int REASON_OTHER = 1; // 0x1 - field public static final int REASON_PUSH_MESSAGING = 101; // 0x65 - field public static final int REASON_PUSH_MESSAGING_OVER_QUOTA = 102; // 0x66 - field public static final int REASON_UNKNOWN = 0; // 0x0 - field public static final int TEMPORARY_ALLOWLIST_TYPE_FOREGROUND_SERVICE_ALLOWED = 0; // 0x0 - field public static final int TEMPORARY_ALLOWLIST_TYPE_FOREGROUND_SERVICE_NOT_ALLOWED = 1; // 0x1 + method @Deprecated @RequiresPermission(android.Manifest.permission.CHANGE_DEVICE_IDLE_TEMP_WHITELIST) public long whitelistAppTemporarilyForEvent(@NonNull String, int, int, @Nullable String); + field @Deprecated public static final int EVENT_MMS = 2; // 0x2 + field @Deprecated public static final int EVENT_SMS = 1; // 0x1 + field @Deprecated public static final int EVENT_UNSPECIFIED = 0; // 0x0 + field @Deprecated public static final int REASON_ACTIVITY_RECOGNITION = 103; // 0x67 + field @Deprecated public static final int REASON_GEOFENCING = 100; // 0x64 + field @Deprecated public static final int REASON_OTHER = 1; // 0x1 + field @Deprecated public static final int REASON_PUSH_MESSAGING = 101; // 0x65 + field @Deprecated public static final int REASON_PUSH_MESSAGING_OVER_QUOTA = 102; // 0x66 + field @Deprecated public static final int REASON_UNKNOWN = 0; // 0x0 + field @Deprecated public static final int TEMPORARY_ALLOWLIST_TYPE_FOREGROUND_SERVICE_ALLOWED = 0; // 0x0 + field @Deprecated public static final int TEMPORARY_ALLOWLIST_TYPE_FOREGROUND_SERVICE_NOT_ALLOWED = 1; // 0x1 } public class RecoverySystem { @@ -10363,6 +10363,7 @@ package android.telecom { public abstract class CallDiagnosticService extends android.app.Service { ctor public CallDiagnosticService(); + method @NonNull public java.util.concurrent.Executor getExecutor(); method @Nullable public android.os.IBinder onBind(@NonNull android.content.Intent); method public abstract void onBluetoothCallQualityReportReceived(@NonNull android.telecom.BluetoothCallQualityReport); method public abstract void onCallAudioStateChanged(@NonNull android.telecom.CallAudioState); @@ -10435,16 +10436,12 @@ package android.telecom { ctor public DiagnosticCall(); method public final void clearDiagnosticMessage(int); method public final void displayDiagnosticMessage(int, @NonNull CharSequence); - method @NonNull public android.telecom.Call.Details getCallDetails(); method public abstract void onCallDetailsChanged(@NonNull android.telecom.Call.Details); method @Nullable public abstract CharSequence onCallDisconnected(int, int); method @Nullable public abstract CharSequence onCallDisconnected(@NonNull android.telephony.ims.ImsReasonInfo); method public abstract void onCallQualityReceived(@NonNull android.telephony.CallQuality); method public abstract void onReceiveDeviceToDeviceMessage(int, int); method public final void sendDeviceToDeviceMessage(int, int); - field public static final int AUDIO_CODEC_AMR_NB = 3; // 0x3 - field public static final int AUDIO_CODEC_AMR_WB = 2; // 0x2 - field public static final int AUDIO_CODEC_EVS = 1; // 0x1 field public static final int BATTERY_STATE_CHARGING = 3; // 0x3 field public static final int BATTERY_STATE_GOOD = 2; // 0x2 field public static final int BATTERY_STATE_LOW = 1; // 0x1 @@ -10454,9 +10451,6 @@ package android.telecom { field public static final int MESSAGE_CALL_NETWORK_TYPE = 1; // 0x1 field public static final int MESSAGE_DEVICE_BATTERY_STATE = 3; // 0x3 field public static final int MESSAGE_DEVICE_NETWORK_COVERAGE = 4; // 0x4 - field public static final int NETWORK_TYPE_IWLAN = 2; // 0x2 - field public static final int NETWORK_TYPE_LTE = 1; // 0x1 - field public static final int NETWORK_TYPE_NR = 3; // 0x3 } public abstract class InCallService extends android.app.Service { @@ -11478,7 +11472,7 @@ package android.telephony { } public static interface TelephonyCallback.AllowedNetworkTypesListener { - method @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public void onAllowedNetworkTypesChanged(@NonNull java.util.Map<java.lang.Integer,java.lang.Long>); + method @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public void onAllowedNetworkTypesChanged(int, long); } public static interface TelephonyCallback.CallAttributesListener { @@ -11962,7 +11956,7 @@ package android.telephony.data { method @NonNull public android.telephony.data.DataCallResponse.Builder setMtuV4(int); method @NonNull public android.telephony.data.DataCallResponse.Builder setMtuV6(int); method @NonNull public android.telephony.data.DataCallResponse.Builder setPcscfAddresses(@NonNull java.util.List<java.net.InetAddress>); - method @NonNull public android.telephony.data.DataCallResponse.Builder setPduSessionId(int); + method @NonNull public android.telephony.data.DataCallResponse.Builder setPduSessionId(@IntRange(from=android.telephony.data.DataCallResponse.PDU_SESSION_ID_NOT_SET, to=15) int); method @NonNull public android.telephony.data.DataCallResponse.Builder setProtocolType(int); method @NonNull public android.telephony.data.DataCallResponse.Builder setRetryDurationMillis(long); method @NonNull public android.telephony.data.DataCallResponse.Builder setSliceInfo(@Nullable android.telephony.data.SliceInfo); @@ -13039,6 +13033,7 @@ package android.telephony.ims { method public void onAutoConfigurationErrorReceived(int, @NonNull String); method public void onConfigurationChanged(@NonNull byte[]); method public void onConfigurationReset(); + method public void onPreProvisioningReceived(@NonNull byte[]); method public void onRemoved(); } @@ -13508,6 +13503,7 @@ package android.telephony.ims.stub { method public int getConfigInt(int); method public String getConfigString(int); method public final void notifyAutoConfigurationErrorReceived(int, @NonNull String); + method public final void notifyPreProvisioningReceived(@NonNull byte[]); method public final void notifyProvisionedValueChanged(int, int); method public final void notifyProvisionedValueChanged(int, String); method public void notifyRcsAutoConfigurationReceived(@NonNull byte[], boolean); diff --git a/core/api/test-current.txt b/core/api/test-current.txt index 1713e2d50b81..9fde79171cf6 100644 --- a/core/api/test-current.txt +++ b/core/api/test-current.txt @@ -699,7 +699,8 @@ package android.content { field public static final String DEVICE_IDLE_CONTROLLER = "deviceidle"; field public static final String DREAM_SERVICE = "dream"; field public static final String FONT_SERVICE = "font"; - field public static final String POWER_WHITELIST_MANAGER = "power_whitelist"; + field public static final String POWER_EXEMPTION_SERVICE = "power_exemption"; + field @Deprecated public static final String POWER_WHITELIST_MANAGER = "power_whitelist"; field public static final String TEST_NETWORK_SERVICE = "test_network"; } @@ -2733,10 +2734,6 @@ package android.view.inputmethod { method @NonNull public static android.view.inputmethod.InlineSuggestionsResponse newInlineSuggestionsResponse(@NonNull java.util.List<android.view.inputmethod.InlineSuggestion>); } - public final class InputMethodInfo implements android.os.Parcelable { - ctor public InputMethodInfo(@NonNull String, @NonNull String, @NonNull CharSequence, @NonNull String, int); - } - public final class InputMethodManager { method public int getDisplayId(); method public boolean hasActiveInputConnection(@Nullable android.view.View); diff --git a/core/java/android/app/AppOpsManager.java b/core/java/android/app/AppOpsManager.java index dd1bc7c61547..d310e8f0ef5c 100644 --- a/core/java/android/app/AppOpsManager.java +++ b/core/java/android/app/AppOpsManager.java @@ -56,6 +56,7 @@ import android.os.RemoteException; import android.os.ServiceManager; import android.os.SystemClock; import android.os.UserManager; +import android.provider.DeviceConfig; import android.provider.Settings; import android.util.ArrayMap; import android.util.ArraySet; @@ -200,9 +201,12 @@ public class AppOpsManager { @EnabledAfter(targetSdkVersion = Build.VERSION_CODES.R) public static final long SECURITY_EXCEPTION_ON_INVALID_ATTRIBUTION_TAG_CHANGE = 151105954L; + private static final String FULL_LOG = "privacy_attribution_tag_full_log_enabled"; private static final int MAX_UNFORWARDED_OPS = 10; + private static Boolean sFullLog = null; + final Context mContext; @UnsupportedAppUsage @@ -6972,6 +6976,26 @@ public class AppOpsManager { AppOpsManager(Context context, IAppOpsService service) { mContext = context; mService = service; + + if (mContext != null) { + final PackageManager pm = mContext.getPackageManager(); + try { + if (pm != null && pm.checkPermission(Manifest.permission.READ_DEVICE_CONFIG, + mContext.getPackageName()) == PackageManager.PERMISSION_GRANTED) { + DeviceConfig.addOnPropertiesChangedListener(DeviceConfig.NAMESPACE_PRIVACY, + mContext.getMainExecutor(), properties -> { + if (properties.getKeyset().contains(FULL_LOG)) { + sFullLog = properties.getBoolean(FULL_LOG, false); + } + }); + return; + } + } catch (Exception e) { + // This manager was made before DeviceConfig is ready, so it's a low-level + // system app. We likely don't care about its logs. + } + } + sFullLog = false; } /** @@ -9110,10 +9134,20 @@ public class AppOpsManager { StringBuilder sb = new StringBuilder(); for (int i = firstInteresting; i <= lastInteresting; i++) { + if (sFullLog == null) { + try { + sFullLog = DeviceConfig.getBoolean(DeviceConfig.NAMESPACE_PRIVACY, + FULL_LOG, false); + } catch (SecurityException e) { + // This should not happen, but it may, in rare cases + sFullLog = false; + } + } + if (i != firstInteresting) { sb.append('\n'); } - if (sb.length() + trace[i].toString().length() > 600) { + if (!sFullLog && sb.length() + trace[i].toString().length() > 600) { break; } sb.append(trace[i]); diff --git a/core/java/android/content/Context.java b/core/java/android/content/Context.java index 0509e3f77c1f..25234592f4c4 100644 --- a/core/java/android/content/Context.java +++ b/core/java/android/content/Context.java @@ -3713,6 +3713,9 @@ public abstract class Context { * usage statistics. * <dt> {@link #HARDWARE_PROPERTIES_SERVICE} ("hardware_properties") * <dd> A {@link android.os.HardwarePropertiesManager} for accessing hardware properties. + * <dt> {@link #DOMAIN_VERIFICATION_SERVICE} ("domain_verification") + * <dd> A {@link android.content.pm.verify.domain.DomainVerificationManager} for accessing + * web domain approval state. * </dl> * * <p>Note: System services obtained via this API may be closely associated with @@ -3794,6 +3797,8 @@ public abstract class Context { * @see android.app.usage.NetworkStatsManager * @see android.os.HardwarePropertiesManager * @see #HARDWARE_PROPERTIES_SERVICE + * @see #DOMAIN_VERIFICATION_SERVICE + * @see android.content.pm.verify.domain.DomainVerificationManager */ public abstract @Nullable Object getSystemService(@ServiceName @NonNull String name); @@ -3813,7 +3818,8 @@ public abstract class Context { * {@link android.view.inputmethod.InputMethodManager}, * {@link android.app.UiModeManager}, {@link android.app.DownloadManager}, * {@link android.os.BatteryManager}, {@link android.app.job.JobScheduler}, - * {@link android.app.usage.NetworkStatsManager}. + * {@link android.app.usage.NetworkStatsManager}, + * {@link android.content.pm.verify.domain.DomainVerificationManager}. * </p> * * <p> @@ -4833,7 +4839,8 @@ public abstract class Context { * @hide */ @TestApi - @SuppressLint("ServiceName") // TODO: This should be renamed to POWER_WHITELIST_SERVICE + @Deprecated + @SuppressLint("ServiceName") public static final String POWER_WHITELIST_MANAGER = "power_whitelist"; /** @@ -4842,7 +4849,7 @@ public abstract class Context { * @see #getSystemService(String) * @hide */ - @SystemApi + @TestApi public static final String POWER_EXEMPTION_SERVICE = "power_exemption"; /** @@ -5544,12 +5551,13 @@ public abstract class Context { public static final String GAME_SERVICE = "game"; /** - * Use with {@link #getSystemService(String)} to access domain verification service. + * Use with {@link #getSystemService(String)} to access + * {@link android.content.pm.verify.domain.DomainVerificationManager} to retrieve approval and + * user state for declared web domains. * * @see #getSystemService(String) - * @hide + * @see android.content.pm.verify.domain.DomainVerificationManager */ - @SystemApi public static final String DOMAIN_VERIFICATION_SERVICE = "domain_verification"; /** diff --git a/core/java/android/content/Intent.java b/core/java/android/content/Intent.java index 04f93ca6991b..c601aabb582b 100644 --- a/core/java/android/content/Intent.java +++ b/core/java/android/content/Intent.java @@ -2172,6 +2172,29 @@ public class Intent implements Parcelable, Cloneable { "android.intent.action.REVIEW_PERMISSION_USAGE"; /** + * Activity action: Launch UI to review the timeline history of permissions. + * <p> + * Input: {@link #EXTRA_PERMISSION_GROUP_NAME} specifies the permission group name + * that will be displayed by the launched UI. + * </p> + * <p> + * Output: Nothing. + * </p> + * <p class="note"> + * This requires {@link android.Manifest.permission#GRANT_RUNTIME_PERMISSIONS} permission. + * </p> + * + * @see #EXTRA_PERMISSION_GROUP_NAME + * + * @hide + */ + @SystemApi + @RequiresPermission(android.Manifest.permission.GRANT_RUNTIME_PERMISSIONS) + @SdkConstant(SdkConstantType.ACTIVITY_INTENT_ACTION) + public static final String ACTION_REVIEW_PERMISSION_HISTORY = + "android.intent.action.REVIEW_PERMISSION_HISTORY"; + + /** * Activity action: Launch UI to review ongoing app uses of permissions. * <p> * Input: {@link #EXTRA_DURATION_MILLIS} specifies the minimum number of milliseconds of recent diff --git a/core/java/android/content/pm/IDataLoaderStatusListener.aidl b/core/java/android/content/pm/IDataLoaderStatusListener.aidl index 745c39b460fa..79b70f2bd5ee 100644 --- a/core/java/android/content/pm/IDataLoaderStatusListener.aidl +++ b/core/java/android/content/pm/IDataLoaderStatusListener.aidl @@ -23,32 +23,34 @@ package android.content.pm; oneway interface IDataLoaderStatusListener { /** The DataLoader process died, binder disconnected or class destroyed. */ const int DATA_LOADER_DESTROYED = 0; + /** The system is in process of binding to the DataLoader. */ + const int DATA_LOADER_BINDING = 1; /** DataLoader process is running and bound to. */ - const int DATA_LOADER_BOUND = 1; + const int DATA_LOADER_BOUND = 2; /** DataLoader has handled onCreate(). */ - const int DATA_LOADER_CREATED = 2; + const int DATA_LOADER_CREATED = 3; /** DataLoader can receive missing pages and read pages notifications, * and ready to provide data. */ - const int DATA_LOADER_STARTED = 3; + const int DATA_LOADER_STARTED = 4; /** DataLoader no longer ready to provide data and is not receiving * any notifications from IncFS. */ - const int DATA_LOADER_STOPPED = 4; + const int DATA_LOADER_STOPPED = 5; /** DataLoader streamed everything necessary to continue installation. */ - const int DATA_LOADER_IMAGE_READY = 5; + const int DATA_LOADER_IMAGE_READY = 6; /** Installation can't continue as DataLoader failed to stream necessary data. */ - const int DATA_LOADER_IMAGE_NOT_READY = 6; + const int DATA_LOADER_IMAGE_NOT_READY = 7; /** DataLoader instance can't run at the moment, but might recover later. * It's up to system to decide if the app is still usable. */ - const int DATA_LOADER_UNAVAILABLE = 7; + const int DATA_LOADER_UNAVAILABLE = 8; /** DataLoader reports that this instance is invalid and can never be restored. * Warning: this is a terminal status that data loader should use carefully and * the system should almost never use - e.g. only if all recovery attempts * fail and all retry limits are exceeded. */ - const int DATA_LOADER_UNRECOVERABLE = 8; + const int DATA_LOADER_UNRECOVERABLE = 9; /** There are no known issues with the data stream. */ const int STREAM_HEALTHY = 0; diff --git a/core/java/android/inputmethodservice/IInputMethodWrapper.java b/core/java/android/inputmethodservice/IInputMethodWrapper.java index 9198eb74d1f8..5cfcd667632b 100644 --- a/core/java/android/inputmethodservice/IInputMethodWrapper.java +++ b/core/java/android/inputmethodservice/IInputMethodWrapper.java @@ -171,7 +171,7 @@ class IInputMethodWrapper extends IInputMethod.Stub SomeArgs args = (SomeArgs) msg.obj; try { inputMethod.initializeInternal((IBinder) args.arg1, msg.arg1, - (IInputMethodPrivilegedOperations) args.arg2, (int) args.arg3); + (IInputMethodPrivilegedOperations) args.arg2); } finally { args.recycle(); } @@ -280,10 +280,9 @@ class IInputMethodWrapper extends IInputMethod.Stub @BinderThread @Override public void initializeInternal(IBinder token, int displayId, - IInputMethodPrivilegedOperations privOps, int configChanges) { + IInputMethodPrivilegedOperations privOps) { mCaller.executeOrSendMessage( - mCaller.obtainMessageIOOO(DO_INITIALIZE_INTERNAL, displayId, token, privOps, - configChanges)); + mCaller.obtainMessageIOO(DO_INITIALIZE_INTERNAL, displayId, token, privOps)); } @BinderThread diff --git a/core/java/android/inputmethodservice/InputMethodService.java b/core/java/android/inputmethodservice/InputMethodService.java index 40a0fc4e8339..7e2be01feb01 100644 --- a/core/java/android/inputmethodservice/InputMethodService.java +++ b/core/java/android/inputmethodservice/InputMethodService.java @@ -70,7 +70,6 @@ import android.compat.annotation.ChangeId; import android.compat.annotation.EnabledSince; import android.compat.annotation.UnsupportedAppUsage; import android.content.Context; -import android.content.pm.ActivityInfo; import android.content.pm.PackageManager; import android.content.res.Configuration; import android.content.res.Resources; @@ -132,7 +131,6 @@ import android.widget.TextView; import android.window.WindowMetricsHelper; import com.android.internal.annotations.GuardedBy; -import com.android.internal.annotations.VisibleForTesting; import com.android.internal.inputmethod.IInputContentUriToken; import com.android.internal.inputmethod.IInputMethodPrivilegedOperations; import com.android.internal.inputmethod.InputMethodPrivilegedOperations; @@ -515,8 +513,6 @@ public class InputMethodService extends AbstractInputMethodService { private boolean mIsAutomotive; private Handler mHandler; private boolean mImeSurfaceScheduledForRemoval; - private Configuration mLastKnownConfig; - private int mHandledConfigChanges; /** * An opaque {@link Binder} token of window requesting {@link InputMethodImpl#showSoftInput} @@ -592,13 +588,12 @@ public class InputMethodService extends AbstractInputMethodService { @MainThread @Override public final void initializeInternal(@NonNull IBinder token, int displayId, - IInputMethodPrivilegedOperations privilegedOperations, int configChanges) { + IInputMethodPrivilegedOperations privilegedOperations) { if (InputMethodPrivilegedOperationsRegistry.isRegistered(token)) { Log.w(TAG, "The token has already registered, ignore this initialization."); return; } Trace.traceBegin(TRACE_TAG_WINDOW_MANAGER, "IMS.initializeInternal"); - mHandledConfigChanges = configChanges; mPrivOps.set(privilegedOperations); InputMethodPrivilegedOperationsRegistry.put(token, mPrivOps); updateInputMethodDisplay(displayId); @@ -826,9 +821,6 @@ public class InputMethodService extends AbstractInputMethodService { setImeWindowStatus(mapToImeWindowStatus(), mBackDisposition); } final boolean isVisible = isInputViewShown(); - if (isVisible && getResources() != null) { - mLastKnownConfig = new Configuration(getResources().getConfiguration()); - } final boolean visibilityChanged = isVisible != wasVisible; if (resultReceiver != null) { resultReceiver.send(visibilityChanged @@ -1436,30 +1428,10 @@ public class InputMethodService extends AbstractInputMethodService { * state: {@link #onStartInput} if input is active, and * {@link #onCreateInputView} and {@link #onStartInputView} and related * appropriate functions if the UI is displayed. - * <p>Starting with {@link Build.VERSION_CODES#S}, IMEs can opt into handling configuration - * changes themselves instead of being restarted with - * {@link android.R.styleable#InputMethod_configChanges}. */ @Override public void onConfigurationChanged(Configuration newConfig) { super.onConfigurationChanged(newConfig); - if (shouldImeRestartForConfig(newConfig)) { - resetStateForNewConfiguration(); - } - } - - /** - * @return {@code true} if {@link InputMethodService} needs to restart to handle - * .{@link #onConfigurationChanged(Configuration)} - */ - @VisibleForTesting - boolean shouldImeRestartForConfig(@NonNull Configuration newConfig) { - if (mLastKnownConfig == null) { - return true; - } - // If the new config is the same as the config this Service is already running with, - // then don't bother calling resetStateForNewConfiguration. - int unhandledDiff = (mLastKnownConfig.diffPublicOnly(newConfig) & ~mHandledConfigChanges); - return unhandledDiff != 0; + resetStateForNewConfiguration(); } private void resetStateForNewConfiguration() { @@ -3209,17 +3181,7 @@ public class InputMethodService extends AbstractInputMethodService { requestHideSelf(InputMethodManager.HIDE_NOT_ALWAYS); } } - - @VisibleForTesting - void setLastKnownConfig(@NonNull Configuration config) { - mLastKnownConfig = config; - } - - @VisibleForTesting - void setHandledConfigChanges(int configChanges) { - mHandledConfigChanges = configChanges; - } - + void startExtractingText(boolean inputChanged) { final ExtractEditText eet = mExtractEditText; if (eet != null && getCurrentInputStarted() diff --git a/core/java/android/net/vcn/VcnManager.java b/core/java/android/net/vcn/VcnManager.java index 8ebf757760c3..062438c6e5db 100644 --- a/core/java/android/net/vcn/VcnManager.java +++ b/core/java/android/net/vcn/VcnManager.java @@ -73,7 +73,8 @@ import java.util.concurrent.Executor; public class VcnManager { @NonNull private static final String TAG = VcnManager.class.getSimpleName(); - private static final Map<VcnNetworkPolicyListener, VcnUnderlyingNetworkPolicyListenerBinder> + private static final Map< + VcnNetworkPolicyChangeListener, VcnUnderlyingNetworkPolicyListenerBinder> REGISTERED_POLICY_LISTENERS = new ConcurrentHashMap<>(); @NonNull private final Context mContext; @@ -93,13 +94,13 @@ public class VcnManager { } /** - * Get all currently registered VcnNetworkPolicyListeners for testing purposes. + * Get all currently registered VcnNetworkPolicyChangeListeners for testing purposes. * * @hide */ @VisibleForTesting(visibility = Visibility.PRIVATE) @NonNull - public static Map<VcnNetworkPolicyListener, VcnUnderlyingNetworkPolicyListenerBinder> + public static Map<VcnNetworkPolicyChangeListener, VcnUnderlyingNetworkPolicyListenerBinder> getAllPolicyListeners() { return Collections.unmodifiableMap(REGISTERED_POLICY_LISTENERS); } @@ -162,14 +163,14 @@ public class VcnManager { } // TODO(b/180537630): remove all VcnUnderlyingNetworkPolicyListener refs once Telephony is using - // the new VcnNetworkPolicyListener API + // the new VcnNetworkPolicyChangeListener API /** * VcnUnderlyingNetworkPolicyListener is the interface through which internal system components * can register to receive updates for VCN-underlying Network policies from the System Server. * * @hide */ - public interface VcnUnderlyingNetworkPolicyListener extends VcnNetworkPolicyListener {} + public interface VcnUnderlyingNetworkPolicyListener extends VcnNetworkPolicyChangeListener {} /** * Add a listener for VCN-underlying network policy updates. @@ -185,7 +186,7 @@ public class VcnManager { @RequiresPermission(android.Manifest.permission.NETWORK_FACTORY) public void addVcnUnderlyingNetworkPolicyListener( @NonNull Executor executor, @NonNull VcnUnderlyingNetworkPolicyListener listener) { - addVcnNetworkPolicyListener(executor, listener); + addVcnNetworkPolicyChangeListener(executor, listener); } /** @@ -198,7 +199,7 @@ public class VcnManager { */ public void removeVcnUnderlyingNetworkPolicyListener( @NonNull VcnUnderlyingNetworkPolicyListener listener) { - removeVcnNetworkPolicyListener(listener); + removeVcnNetworkPolicyChangeListener(listener); } /** @@ -233,20 +234,20 @@ public class VcnManager { } /** - * VcnNetworkPolicyListener is the interface through which internal system components (e.g. - * Network Factories) can register to receive updates for VCN-underlying Network policies from - * the System Server. + * VcnNetworkPolicyChangeListener is the interface through which internal system components + * (e.g. Network Factories) can register to receive updates for VCN-underlying Network policies + * from the System Server. * * <p>Any Network Factory that brings up Networks capable of being VCN-underlying Networks - * should register a VcnNetworkPolicyListener. VcnManager will then use this listener to notify - * the registrant when VCN Network policies change. Upon receiving this signal, the listener - * must check {@link VcnManager} for the current Network policy result for each of its Networks - * via {@link #applyVcnNetworkPolicy(NetworkCapabilities, LinkProperties)}. + * should register a VcnNetworkPolicyChangeListener. VcnManager will then use this listener to + * notify the registrant when VCN Network policies change. Upon receiving this signal, the + * listener must check {@link VcnManager} for the current Network policy result for each of its + * Networks via {@link #applyVcnNetworkPolicy(NetworkCapabilities, LinkProperties)}. * * @hide */ @SystemApi - public interface VcnNetworkPolicyListener { + public interface VcnNetworkPolicyChangeListener { /** * Notifies the implementation that the VCN's underlying Network policy has changed. * @@ -260,20 +261,21 @@ public class VcnManager { /** * Add a listener for VCN-underlying Network policy updates. * - * <p>A {@link VcnNetworkPolicyListener} is eligible to begin receiving callbacks once it is - * registered. No callbacks are guaranteed upon registration. + * <p>A {@link VcnNetworkPolicyChangeListener} is eligible to begin receiving callbacks once it + * is registered. No callbacks are guaranteed upon registration. * * @param executor the Executor that will be used for invoking all calls to the specified * Listener - * @param listener the VcnNetworkPolicyListener to be added + * @param listener the VcnNetworkPolicyChangeListener to be added * @throws SecurityException if the caller does not have permission NETWORK_FACTORY - * @throws IllegalStateException if the specified VcnNetworkPolicyListener is already registered + * @throws IllegalStateException if the specified VcnNetworkPolicyChangeListener is already + * registered * @hide */ @SystemApi @RequiresPermission(android.Manifest.permission.NETWORK_FACTORY) - public void addVcnNetworkPolicyListener( - @NonNull Executor executor, @NonNull VcnNetworkPolicyListener listener) { + public void addVcnNetworkPolicyChangeListener( + @NonNull Executor executor, @NonNull VcnNetworkPolicyChangeListener listener) { requireNonNull(executor, "executor must not be null"); requireNonNull(listener, "listener must not be null"); @@ -292,15 +294,18 @@ public class VcnManager { } /** - * Remove the specified VcnNetworkPolicyListener from VcnManager. + * Remove the specified VcnNetworkPolicyChangeListener from VcnManager. * * <p>If the specified listener is not currently registered, this is a no-op. * - * @param listener the VcnNetworkPolicyListener that will be removed + * @param listener the VcnNetworkPolicyChangeListener that will be removed + * @throws SecurityException if the caller does not have permission NETWORK_FACTORY * @hide */ @SystemApi - public void removeVcnNetworkPolicyListener(@NonNull VcnNetworkPolicyListener listener) { + @RequiresPermission(android.Manifest.permission.NETWORK_FACTORY) + public void removeVcnNetworkPolicyChangeListener( + @NonNull VcnNetworkPolicyChangeListener listener) { requireNonNull(listener, "listener must not be null"); VcnUnderlyingNetworkPolicyListenerBinder binder = @@ -320,8 +325,9 @@ public class VcnManager { * Applies the network policy for a {@link android.net.Network} with the given parameters. * * <p>Prior to a new NetworkAgent being registered, or upon notification that Carrier VCN policy - * may have changed via {@link VcnNetworkPolicyListener#onPolicyChanged()}, a Network Provider - * MUST poll for the updated Network policy based on that Network's capabilities and properties. + * may have changed via {@link VcnNetworkPolicyChangeListener#onPolicyChanged()}, a Network + * Provider MUST poll for the updated Network policy based on that Network's capabilities and + * properties. * * @param networkCapabilities the NetworkCapabilities to be used in determining the Network * policy result for this Network. @@ -532,17 +538,18 @@ public class VcnManager { } /** - * Binder wrapper for added VcnNetworkPolicyListeners to receive signals from System Server. + * Binder wrapper for added VcnNetworkPolicyChangeListeners to receive signals from System + * Server. * * @hide */ private static class VcnUnderlyingNetworkPolicyListenerBinder extends IVcnUnderlyingNetworkPolicyListener.Stub { @NonNull private final Executor mExecutor; - @NonNull private final VcnNetworkPolicyListener mListener; + @NonNull private final VcnNetworkPolicyChangeListener mListener; private VcnUnderlyingNetworkPolicyListenerBinder( - Executor executor, VcnNetworkPolicyListener listener) { + Executor executor, VcnNetworkPolicyChangeListener listener) { mExecutor = executor; mListener = listener; } diff --git a/core/java/android/os/BatteryStats.java b/core/java/android/os/BatteryStats.java index 66f7bd9d8dee..4c26e2f33fb2 100644 --- a/core/java/android/os/BatteryStats.java +++ b/core/java/android/os/BatteryStats.java @@ -995,6 +995,15 @@ public abstract class BatteryStats implements Parcelable { public abstract long getScreenOnMeasuredBatteryConsumptionUC(); /** + * Returns the battery consumption (in microcoulombs) of the uid's cpu usage, derived from + * on device power measurement data. + * Will return {@link #POWER_DATA_UNAVAILABLE} if data is unavailable. + * + * {@hide} + */ + public abstract long getCpuMeasuredBatteryConsumptionUC(); + + /** * Returns the battery consumption (in microcoulombs) used by this uid for each * {@link android.hardware.power.stats.EnergyConsumer.ordinal} of (custom) energy consumer * type {@link android.hardware.power.stats.EnergyConsumerType#OTHER}). @@ -2521,6 +2530,15 @@ public abstract class BatteryStats implements Parcelable { public abstract long getScreenDozeMeasuredBatteryConsumptionUC(); /** + * Returns the battery consumption (in microcoulombs) of the cpu, derived from on device power + * measurement data. + * Will return {@link #POWER_DATA_UNAVAILABLE} if data is unavailable. + * + * {@hide} + */ + public abstract long getCpuMeasuredBatteryConsumptionUC(); + + /** * Returns the battery consumption (in microcoulombs) that each * {@link android.hardware.power.stats.EnergyConsumer.ordinal} of (custom) energy consumer * type {@link android.hardware.power.stats.EnergyConsumerType#OTHER}) consumed. diff --git a/core/java/android/os/Vibrator.java b/core/java/android/os/Vibrator.java index b003d238c268..b90d438ffb93 100644 --- a/core/java/android/os/Vibrator.java +++ b/core/java/android/os/Vibrator.java @@ -208,6 +208,28 @@ public abstract class Vibrator { public abstract boolean hasAmplitudeControl(); /** + * Gets the resonant frequency of the vibrator. + * + * @return the resonant frequency of the vibrator, or {@link Float#NaN NaN} if it's unknown or + * this vibrator is a composite of multiple physical devices. + * @hide + */ + public float getResonantFrequency() { + return Float.NaN; + } + + /** + * Gets the <a href="https://en.wikipedia.org/wiki/Q_factor">Q factor</a> of the vibrator. + * + * @return the Q factor of the vibrator, or {@link Float#NaN NaN} if it's unknown or + * this vibrator is a composite of multiple physical devices. + * @hide + */ + public float getQFactor() { + return Float.NaN; + } + + /** * Configure an always-on haptics effect. * * @param alwaysOnId The board-specific always-on ID to configure. diff --git a/core/java/android/os/VibratorInfo.java b/core/java/android/os/VibratorInfo.java index 50d2de3da965..3121b952281e 100644 --- a/core/java/android/os/VibratorInfo.java +++ b/core/java/android/os/VibratorInfo.java @@ -42,21 +42,27 @@ public final class VibratorInfo implements Parcelable { private final SparseBooleanArray mSupportedEffects; @Nullable private final SparseBooleanArray mSupportedPrimitives; + private final float mResonantFrequency; + private final float mQFactor; VibratorInfo(Parcel in) { mId = in.readInt(); mCapabilities = in.readLong(); mSupportedEffects = in.readSparseBooleanArray(); mSupportedPrimitives = in.readSparseBooleanArray(); + mResonantFrequency = in.readFloat(); + mQFactor = in.readFloat(); } /** @hide */ public VibratorInfo(int id, long capabilities, int[] supportedEffects, - int[] supportedPrimitives) { + int[] supportedPrimitives, float resonantFrequency, float qFactor) { mId = id; mCapabilities = capabilities; mSupportedEffects = toSparseBooleanArray(supportedEffects); mSupportedPrimitives = toSparseBooleanArray(supportedPrimitives); + mResonantFrequency = resonantFrequency; + mQFactor = qFactor; } @Override @@ -65,6 +71,8 @@ public final class VibratorInfo implements Parcelable { dest.writeLong(mCapabilities); dest.writeSparseBooleanArray(mSupportedEffects); dest.writeSparseBooleanArray(mSupportedPrimitives); + dest.writeFloat(mResonantFrequency); + dest.writeFloat(mQFactor); } @Override @@ -83,12 +91,15 @@ public final class VibratorInfo implements Parcelable { VibratorInfo that = (VibratorInfo) o; return mId == that.mId && mCapabilities == that.mCapabilities && Objects.equals(mSupportedEffects, that.mSupportedEffects) - && Objects.equals(mSupportedPrimitives, that.mSupportedPrimitives); + && Objects.equals(mSupportedPrimitives, that.mSupportedPrimitives) + && Objects.equals(mResonantFrequency, that.mResonantFrequency) + && Objects.equals(mQFactor, that.mQFactor); } @Override public int hashCode() { - return Objects.hash(mId, mCapabilities, mSupportedEffects, mSupportedPrimitives); + return Objects.hash(mId, mCapabilities, mSupportedEffects, mSupportedPrimitives, + mResonantFrequency, mQFactor); } @Override @@ -99,6 +110,8 @@ public final class VibratorInfo implements Parcelable { + ", mCapabilities flags=" + Long.toBinaryString(mCapabilities) + ", mSupportedEffects=" + Arrays.toString(getSupportedEffectsNames()) + ", mSupportedPrimitives=" + Arrays.toString(getSupportedPrimitivesNames()) + + ", mResonantFrequency=" + mResonantFrequency + + ", mQFactor=" + mQFactor + '}'; } @@ -156,6 +169,26 @@ public final class VibratorInfo implements Parcelable { return (mCapabilities & capability) == capability; } + /** + * Gets the resonant frequency of the vibrator. + * + * @return the resonant frequency of the vibrator, or {@link Float#NaN NaN} if it's unknown or + * this vibrator is a composite of multiple physical devices. + */ + public float getResonantFrequency() { + return mResonantFrequency; + } + + /** + * Gets the <a href="https://en.wikipedia.org/wiki/Q_factor">Q factor</a> of the vibrator. + * + * @return the Q factor of the vibrator, or {@link Float#NaN NaN} if it's unknown or + * this vibrator is a composite of multiple physical devices. + */ + public float getQFactor() { + return mQFactor; + } + private String[] getCapabilitiesNames() { List<String> names = new ArrayList<>(); if (hasCapability(IVibrator.CAP_ON_CALLBACK)) { diff --git a/core/java/android/permission/PermissionUsageHelper.java b/core/java/android/permission/PermissionUsageHelper.java index 4c9e77c35135..7e3a0f30e75c 100644 --- a/core/java/android/permission/PermissionUsageHelper.java +++ b/core/java/android/permission/PermissionUsageHelper.java @@ -111,8 +111,7 @@ public class PermissionUsageHelper { private static boolean shouldShowLocationIndicator() { return DeviceConfig.getBoolean(DeviceConfig.NAMESPACE_PRIVACY, - PROPERTY_LOCATION_INDICATORS_ENABLED, false) - || shouldShowPermissionsHub(); + PROPERTY_LOCATION_INDICATORS_ENABLED, false); } private static long getRecentThreshold(Long now) { @@ -326,10 +325,10 @@ public class PermissionUsageHelper { } if (packageName.equals(SYSTEM_PKG) - || (!isUserSensitive(packageName, user, op) + || (!shouldShowPermissionsHub() + && !isUserSensitive(packageName, user, op) && !isLocationProvider(packageName, user) - && !isAppPredictor(packageName, user)) - && !isSpeechRecognizerUsage(op, packageName)) { + && !isSpeechRecognizerUsage(op, packageName))) { continue; } diff --git a/core/java/android/provider/Telephony.java b/core/java/android/provider/Telephony.java index 8a4812a42c8a..374de9ccb2f4 100644 --- a/core/java/android/provider/Telephony.java +++ b/core/java/android/provider/Telephony.java @@ -5310,5 +5310,12 @@ public final class Telephony { * @hide */ public static final String COLUMN_VOIMS_OPT_IN_STATUS = "voims_opt_in_status"; + + /** + * TelephonyProvider column name for device to device sharing status. + * + * @hide + */ + public static final String COLUMN_D2D_STATUS_SHARING = "d2d_sharing_status"; } } diff --git a/core/java/android/telephony/PhoneStateListener.java b/core/java/android/telephony/PhoneStateListener.java index bbe887f500a9..e9a79e70fd74 100644 --- a/core/java/android/telephony/PhoneStateListener.java +++ b/core/java/android/telephony/PhoneStateListener.java @@ -20,7 +20,6 @@ import android.Manifest; import android.annotation.NonNull; import android.annotation.RequiresPermission; import android.annotation.SystemApi; -import android.compat.annotation.ChangeId; import android.compat.annotation.UnsupportedAppUsage; import android.os.Binder; import android.os.Build; @@ -1577,7 +1576,7 @@ public class PhoneStateListener { // default implementation empty } - public void onAllowedNetworkTypesChanged(Map allowedNetworkTypesList) { + public void onAllowedNetworkTypesChanged(int reason, long allowedNetworkType) { // default implementation empty } } diff --git a/core/java/android/telephony/TelephonyCallback.java b/core/java/android/telephony/TelephonyCallback.java index 2cadda25a9d3..e3d3dec60151 100644 --- a/core/java/android/telephony/TelephonyCallback.java +++ b/core/java/android/telephony/TelephonyCallback.java @@ -546,9 +546,6 @@ public class TelephonyCallback { /** * Event for changes to allowed network list based on all active subscriptions. * - * <p>Requires permission {@link android.Manifest.permission#READ_PHONE_STATE} or the calling - * app has carrier privileges (see {@link TelephonyManager#hasCarrierPrivileges}). - * * @hide * @see AllowedNetworkTypesListener#onAllowedNetworkTypesChanged */ @@ -1265,30 +1262,34 @@ public class TelephonyCallback { public interface AllowedNetworkTypesListener { /** * Callback invoked when the current allowed network type list has changed on the - * registered subscription. + * registered subscription for a specified reason. * Note, the registered subscription is associated with {@link TelephonyManager} object - * on which - * {@link TelephonyManager#registerTelephonyCallback(Executor, TelephonyCallback)} + * on which {@link TelephonyManager#registerTelephonyCallback(Executor, TelephonyCallback)} * was called. * If this TelephonyManager object was created with * {@link TelephonyManager#createForSubscriptionId(int)}, then the callback applies to the * given subscription ID. Otherwise, this callback applies to * {@link SubscriptionManager#getDefaultSubscriptionId()}. * - * @param allowedNetworkTypesList Map associating all allowed network type reasons - * ({@link TelephonyManager#ALLOWED_NETWORK_TYPES_REASON_USER}, - * {@link TelephonyManager#ALLOWED_NETWORK_TYPES_REASON_POWER}, - * {@link TelephonyManager#ALLOWED_NETWORK_TYPES_REASON_CARRIER}, and - * {@link TelephonyManager#ALLOWED_NETWORK_TYPES_REASON_ENABLE_2G}) with reason's allowed - * network type values. + * @param reason an allowed network type reasons. + * @see TelephonyManager#ALLOWED_NETWORK_TYPES_REASON_USER + * @see TelephonyManager#ALLOWED_NETWORK_TYPES_REASON_POWER + * @see TelephonyManager#ALLOWED_NETWORK_TYPES_REASON_CARRIER + * @see TelephonyManager#ALLOWED_NETWORK_TYPES_REASON_ENABLE_2G + * + * @param allowedNetworkType an allowed network type bitmask value. (for example, + * the long bitmask value is {{@link TelephonyManager#NETWORK_TYPE_BITMASK_NR}| + * {@link TelephonyManager#NETWORK_TYPE_BITMASK_LTE}}) + * * For example: - * map{{TelephonyManager#ALLOWED_NETWORK_TYPES_REASON_USER, long type value}, - * {TelephonyManager#ALLOWED_NETWORK_TYPES_REASON_POWER, long type value}, - * {TelephonyManager#ALLOWED_NETWORK_TYPES_REASON_CARRIER, long type value}, - * {TelephonyManager#ALLOWED_NETWORK_TYPES_REASON_ENABLE_2G, long type value}} + * If the latest allowed network type is changed by user, then the system + * notifies the {@link TelephonyManager#ALLOWED_NETWORK_TYPES_REASON_USER} and + * long type value}. */ @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) - void onAllowedNetworkTypesChanged(@NonNull Map<Integer, Long> allowedNetworkTypesList); + void onAllowedNetworkTypesChanged( + @TelephonyManager.AllowedNetworkTypesReason int reason, + @TelephonyManager.NetworkTypeBitMask long allowedNetworkType); } /** @@ -1707,14 +1708,15 @@ public class TelephonyCallback { enabled, reason))); } - public void onAllowedNetworkTypesChanged(Map allowedNetworkTypesList) { + public void onAllowedNetworkTypesChanged(int reason, long allowedNetworkType) { AllowedNetworkTypesListener listener = (AllowedNetworkTypesListener) mTelephonyCallbackWeakRef.get(); if (listener == null) return; Binder.withCleanCallingIdentity( () -> mExecutor.execute( - () -> listener.onAllowedNetworkTypesChanged(allowedNetworkTypesList))); + () -> listener.onAllowedNetworkTypesChanged(reason, + allowedNetworkType))); } } } diff --git a/core/java/android/telephony/TelephonyRegistryManager.java b/core/java/android/telephony/TelephonyRegistryManager.java index 9cda4ae79335..3fa63d8c1a9c 100644 --- a/core/java/android/telephony/TelephonyRegistryManager.java +++ b/core/java/android/telephony/TelephonyRegistryManager.java @@ -825,16 +825,18 @@ public class TelephonyRegistryManager { } /** - * Notify emergency number list changed on certain subscription. - * - * @param slotIndex for which emergency number list changed. Can be derived from subId except - * when subId is invalid. - * @param subId for which emergency number list changed. + * Notify the allowed network types has changed for a specific subscription and the specific + * reason. + * @param slotIndex for which allowed network types changed. + * @param subId for which allowed network types changed. + * @param reason an allowed network type reasons. + * @param allowedNetworkType an allowed network type bitmask value. */ public void notifyAllowedNetworkTypesChanged(int slotIndex, int subId, - Map<Integer, Long> allowedNetworkTypeList) { + int reason, long allowedNetworkType) { try { - sRegistry.notifyAllowedNetworkTypesChanged(slotIndex, subId, allowedNetworkTypeList); + sRegistry.notifyAllowedNetworkTypesChanged(slotIndex, subId, reason, + allowedNetworkType); } catch (RemoteException ex) { // system process is dead } diff --git a/core/java/android/util/Slog.java b/core/java/android/util/Slog.java index 3880131324fc..f61ab2985163 100644 --- a/core/java/android/util/Slog.java +++ b/core/java/android/util/Slog.java @@ -16,14 +16,26 @@ package android.util; +import android.annotation.Nullable; import android.compat.annotation.UnsupportedAppUsage; import android.os.Build; +import com.android.internal.annotations.GuardedBy; + +import java.util.Formatter; +import java.util.Locale; + /** * @hide */ public final class Slog { + @GuardedBy("sMessageBuilder") + private static final StringBuilder sMessageBuilder = new StringBuilder(); + + @GuardedBy("sMessageBuilder") + private static final Formatter sFormatter = new Formatter(sMessageBuilder, Locale.ENGLISH); + private Slog() { } @@ -37,6 +49,15 @@ public final class Slog { msg + '\n' + Log.getStackTraceString(tr)); } + /** + * Logs a {@link Log.VERBOSE} message. + */ + public static void v(String tag, String format, @Nullable Object... args) { + if (!Log.isLoggable(tag, Log.VERBOSE)) return; + + v(tag, getMessage(format, args)); + } + @UnsupportedAppUsage public static int d(String tag, String msg) { return Log.println_native(Log.LOG_ID_SYSTEM, Log.DEBUG, tag, msg); @@ -48,6 +69,15 @@ public final class Slog { msg + '\n' + Log.getStackTraceString(tr)); } + /** + * Logs a {@link Log.DEBUG} message. + */ + public static void d(String tag, String format, @Nullable Object... args) { + if (!Log.isLoggable(tag, Log.DEBUG)) return; + + d(tag, getMessage(format, args)); + } + @UnsupportedAppUsage public static int i(String tag, String msg) { return Log.println_native(Log.LOG_ID_SYSTEM, Log.INFO, tag, msg); @@ -58,6 +88,15 @@ public final class Slog { msg + '\n' + Log.getStackTraceString(tr)); } + /** + * Logs a {@link Log.INFO} message. + */ + public static void i(String tag, String format, @Nullable Object... args) { + if (!Log.isLoggable(tag, Log.INFO)) return; + + i(tag, getMessage(format, args)); + } + @UnsupportedAppUsage public static int w(String tag, String msg) { return Log.println_native(Log.LOG_ID_SYSTEM, Log.WARN, tag, msg); @@ -73,6 +112,24 @@ public final class Slog { return Log.println_native(Log.LOG_ID_SYSTEM, Log.WARN, tag, Log.getStackTraceString(tr)); } + /** + * Logs a {@link Log.WARN} message. + */ + public static void w(String tag, String format, @Nullable Object... args) { + if (!Log.isLoggable(tag, Log.WARN)) return; + + w(tag, getMessage(format, args)); + } + + /** + * Logs a {@link Log.WARN} message with an exception + */ + public static void w(String tag, Exception exception, String format, @Nullable Object... args) { + if (!Log.isLoggable(tag, Log.WARN)) return; + + w(tag, getMessage(format, args), exception); + } + @UnsupportedAppUsage public static int e(String tag, String msg) { return Log.println_native(Log.LOG_ID_SYSTEM, Log.ERROR, tag, msg); @@ -85,6 +142,24 @@ public final class Slog { } /** + * Logs a {@link Log.ERROR} message. + */ + public static void e(String tag, String format, @Nullable Object... args) { + if (!Log.isLoggable(tag, Log.ERROR)) return; + + e(tag, getMessage(format, args)); + } + + /** + * Logs a {@link Log.ERROR} message with an exception + */ + public static void e(String tag, Exception exception, String format, @Nullable Object... args) { + if (!Log.isLoggable(tag, Log.ERROR)) return; + + e(tag, getMessage(format, args), exception); + } + + /** * Like {@link Log#wtf(String, String)}, but will never cause the caller to crash, and * will always be handled asynchronously. Primarily for use by coding running within * the system process. @@ -95,6 +170,21 @@ public final class Slog { } /** + * Logs a {@code wtf} message. + */ + public static void wtf(String tag, String format, @Nullable Object... args) { + wtf(tag, getMessage(format, args)); + } + + /** + * Logs a {@code wtf} message with an exception. + */ + public static void wtf(String tag, Exception exception, String format, + @Nullable Object... args) { + wtf(tag, getMessage(format, args), exception); + } + + /** * Like {@link #wtf(String, String)}, but does not output anything to the log. */ public static void wtfQuiet(String tag, String msg) { @@ -134,5 +224,13 @@ public final class Slog { public static int println(int priority, String tag, String msg) { return Log.println_native(Log.LOG_ID_SYSTEM, priority, tag, msg); } -} + private static String getMessage(String format, @Nullable Object... args) { + synchronized (sMessageBuilder) { + sFormatter.format(format, args); + String message = sMessageBuilder.toString(); + sMessageBuilder.setLength(0); + return message; + } + } +} diff --git a/core/java/android/view/KeyCharacterMap.java b/core/java/android/view/KeyCharacterMap.java index 02a97888cffd..aa1acc1217df 100644 --- a/core/java/android/view/KeyCharacterMap.java +++ b/core/java/android/view/KeyCharacterMap.java @@ -16,6 +16,7 @@ package android.view; +import android.annotation.Nullable; import android.compat.annotation.UnsupportedAppUsage; import android.hardware.input.InputManager; import android.os.Build; @@ -25,6 +26,8 @@ import android.text.method.MetaKeyKeyListener; import android.util.AndroidRuntimeException; import android.util.SparseIntArray; +import com.android.internal.annotations.VisibleForTesting; + import java.text.Normalizer; /** @@ -297,6 +300,8 @@ public class KeyCharacterMap implements Parcelable { private static native char nativeGetDisplayLabel(long ptr, int keyCode); private static native int nativeGetKeyboardType(long ptr); private static native KeyEvent[] nativeGetEvents(long ptr, char[] chars); + private static native KeyCharacterMap nativeObtainEmptyKeyCharacterMap(int deviceId); + private static native boolean nativeEquals(long ptr1, long ptr2); private KeyCharacterMap(Parcel in) { if (in == null) { @@ -323,6 +328,18 @@ public class KeyCharacterMap implements Parcelable { } /** + * Obtain empty key character map + * @param deviceId The input device ID + * @return The KeyCharacterMap object + * @hide + */ + @VisibleForTesting + @Nullable + public static KeyCharacterMap obtainEmptyMap(int deviceId) { + return nativeObtainEmptyKeyCharacterMap(deviceId); + } + + /** * Loads the key character maps for the keyboard with the specified device id. * * @param deviceId The device id of the keyboard. @@ -729,6 +746,18 @@ public class KeyCharacterMap implements Parcelable { return 0; } + @Override + public boolean equals(Object obj) { + if (obj == null || !(obj instanceof KeyCharacterMap)) { + return false; + } + KeyCharacterMap peer = (KeyCharacterMap) obj; + if (mPtr == 0 || peer.mPtr == 0) { + return mPtr == peer.mPtr; + } + return nativeEquals(mPtr, peer.mPtr); + } + /** * Thrown by {@link KeyCharacterMap#load} when a key character map could not be loaded. */ diff --git a/core/java/android/view/inputmethod/InputMethod.java b/core/java/android/view/inputmethod/InputMethod.java index 6ade5e622eab..de4554b9e624 100644 --- a/core/java/android/view/inputmethod/InputMethod.java +++ b/core/java/android/view/inputmethod/InputMethod.java @@ -105,7 +105,7 @@ public interface InputMethod { */ @MainThread default void initializeInternal(IBinder token, int displayId, - IInputMethodPrivilegedOperations privilegedOperations, int configChanges) { + IInputMethodPrivilegedOperations privilegedOperations) { updateInputMethodDisplay(displayId); attachToken(token); } diff --git a/core/java/android/view/inputmethod/InputMethodInfo.java b/core/java/android/view/inputmethod/InputMethodInfo.java index 25712f8bf9b8..5d876a6f62d3 100644 --- a/core/java/android/view/inputmethod/InputMethodInfo.java +++ b/core/java/android/view/inputmethod/InputMethodInfo.java @@ -18,23 +18,19 @@ package android.view.inputmethod; import android.annotation.NonNull; import android.annotation.Nullable; -import android.annotation.TestApi; import android.compat.annotation.UnsupportedAppUsage; import android.content.ComponentName; import android.content.Context; -import android.content.pm.ActivityInfo; import android.content.pm.ApplicationInfo; import android.content.pm.PackageManager; import android.content.pm.PackageManager.NameNotFoundException; import android.content.pm.ResolveInfo; import android.content.pm.ServiceInfo; -import android.content.res.Configuration; import android.content.res.Resources; import android.content.res.Resources.NotFoundException; import android.content.res.TypedArray; import android.content.res.XmlResourceParser; import android.graphics.drawable.Drawable; -import android.inputmethodservice.InputMethodService; import android.os.Parcel; import android.os.Parcelable; import android.util.AttributeSet; @@ -64,7 +60,6 @@ import java.util.List; * @attr ref android.R.styleable#InputMethod_isDefault * @attr ref android.R.styleable#InputMethod_supportsSwitchingToNextInputMethod * @attr ref android.R.styleable#InputMethod_supportsInlineSuggestions - * @attr ref android.R.styleable#InputMethod_configChanges */ public final class InputMethodInfo implements Parcelable { static final String TAG = "InputMethodInfo"; @@ -123,12 +118,6 @@ public final class InputMethodInfo implements Parcelable { private final boolean mInlineSuggestionsEnabled; /** - * The flag for configurations IME assumes the responsibility for handling in - * {@link InputMethodService#onConfigurationChanged(Configuration)}}. - */ - private final int mHandledConfigChanges; - - /** * @param service the {@link ResolveInfo} corresponds in which the IME is implemented. * @return a unique ID to be returned by {@link #getId()}. We have used * {@link ComponentName#flattenToShortString()} for this purpose (and it is already @@ -214,8 +203,6 @@ public final class InputMethodInfo implements Parcelable { false); inlineSuggestionsEnabled = sa.getBoolean( com.android.internal.R.styleable.InputMethod_supportsInlineSuggestions, false); - mHandledConfigChanges = sa.getInt( - com.android.internal.R.styleable.InputMethod_configChanges, 0); sa.recycle(); final int depth = parser.getDepth(); @@ -300,7 +287,6 @@ public final class InputMethodInfo implements Parcelable { mIsVrOnly = source.readBoolean(); mService = ResolveInfo.CREATOR.createFromParcel(source); mSubtypes = new InputMethodSubtypeArray(source); - mHandledConfigChanges = source.readInt(); mForceDefault = false; } @@ -312,22 +298,7 @@ public final class InputMethodInfo implements Parcelable { this(buildFakeResolveInfo(packageName, className, label), false /* isAuxIme */, settingsActivity, null /* subtypes */, 0 /* isDefaultResId */, false /* forceDefault */, true /* supportsSwitchingToNextInputMethod */, - false /* inlineSuggestionsEnabled */, false /* isVrOnly */, - 0 /* handledConfigChanges */); - } - - /** - * Temporary API for creating a built-in input method for test. - * @hide - */ - @TestApi - public InputMethodInfo(@NonNull String packageName, @NonNull String className, - @NonNull CharSequence label, @NonNull String settingsActivity, - int handledConfigChanges) { - this(buildFakeResolveInfo(packageName, className, label), false /* isAuxIme */, - settingsActivity, null /* subtypes */, 0 /* isDefaultResId */, - false /* forceDefault */, true /* supportsSwitchingToNextInputMethod */, - false /* inlineSuggestionsEnabled */, false /* isVrOnly */, handledConfigChanges); + false /* inlineSuggestionsEnabled */, false /* isVrOnly */); } /** @@ -339,7 +310,7 @@ public final class InputMethodInfo implements Parcelable { boolean forceDefault) { this(ri, isAuxIme, settingsActivity, subtypes, isDefaultResId, forceDefault, true /* supportsSwitchingToNextInputMethod */, false /* inlineSuggestionsEnabled */, - false /* isVrOnly */, 0 /* handledconfigChanges */); + false /* isVrOnly */); } /** @@ -350,8 +321,7 @@ public final class InputMethodInfo implements Parcelable { List<InputMethodSubtype> subtypes, int isDefaultResId, boolean forceDefault, boolean supportsSwitchingToNextInputMethod, boolean isVrOnly) { this(ri, isAuxIme, settingsActivity, subtypes, isDefaultResId, forceDefault, - supportsSwitchingToNextInputMethod, false /* inlineSuggestionsEnabled */, isVrOnly, - 0 /* handledConfigChanges */); + supportsSwitchingToNextInputMethod, false /* inlineSuggestionsEnabled */, isVrOnly); } /** @@ -361,7 +331,7 @@ public final class InputMethodInfo implements Parcelable { public InputMethodInfo(ResolveInfo ri, boolean isAuxIme, String settingsActivity, List<InputMethodSubtype> subtypes, int isDefaultResId, boolean forceDefault, boolean supportsSwitchingToNextInputMethod, boolean inlineSuggestionsEnabled, - boolean isVrOnly, int handledConfigChanges) { + boolean isVrOnly) { final ServiceInfo si = ri.serviceInfo; mService = ri; mId = new ComponentName(si.packageName, si.name).flattenToShortString(); @@ -373,7 +343,6 @@ public final class InputMethodInfo implements Parcelable { mSupportsSwitchingToNextInputMethod = supportsSwitchingToNextInputMethod; mInlineSuggestionsEnabled = inlineSuggestionsEnabled; mIsVrOnly = isVrOnly; - mHandledConfigChanges = handledConfigChanges; } private static ResolveInfo buildFakeResolveInfo(String packageName, String className, @@ -520,17 +489,6 @@ public final class InputMethodInfo implements Parcelable { } } - /** - * Returns the bit mask of kinds of configuration changes that this IME - * can handle itself (without being restarted by the system). - * - * @attr ref android.R.styleable#InputMethod_configChanges - */ - @ActivityInfo.Config - public int getConfigChanges() { - return mHandledConfigChanges; - } - public void dump(Printer pw, String prefix) { pw.println(prefix + "mId=" + mId + " mSettingsActivityName=" + mSettingsActivityName @@ -621,7 +579,6 @@ public final class InputMethodInfo implements Parcelable { dest.writeBoolean(mIsVrOnly); mService.writeToParcel(dest, flags); mSubtypes.writeToParcel(dest); - dest.writeInt(mHandledConfigChanges); } /** diff --git a/core/java/com/android/internal/graphics/palette/WSMeansQuantizer.java b/core/java/com/android/internal/graphics/palette/WSMeansQuantizer.java index b4f216ba87fa..1d865c2513cf 100644 --- a/core/java/com/android/internal/graphics/palette/WSMeansQuantizer.java +++ b/core/java/com/android/internal/graphics/palette/WSMeansQuantizer.java @@ -75,7 +75,7 @@ public class WSMeansQuantizer implements Quantizer { // Note: they don't _have_ to be ignored, for example, we could instead turn them // opaque. Traditionally, including outside Android, quantizers ignore transparent // pixels, so that strategy was chosen. - int alpha = (pixel >> 24); + int alpha = (pixel >> 24) & 0xff; if (alpha < 255) { continue; } diff --git a/core/java/com/android/internal/os/BatteryStatsImpl.java b/core/java/com/android/internal/os/BatteryStatsImpl.java index 9ecb0ad09bc4..11466f4bc042 100644 --- a/core/java/com/android/internal/os/BatteryStatsImpl.java +++ b/core/java/com/android/internal/os/BatteryStatsImpl.java @@ -6976,6 +6976,11 @@ public class BatteryStatsImpl extends BatteryStats { return getPowerBucketConsumptionUC(MeasuredEnergyStats.POWER_BUCKET_SCREEN_DOZE); } + @Override + public long getCpuMeasuredBatteryConsumptionUC() { + return getPowerBucketConsumptionUC(MeasuredEnergyStats.POWER_BUCKET_CPU); + } + /** * Returns the consumption (in microcoulombs) that the given standard power bucket consumed. * Will return {@link #POWER_DATA_UNAVAILABLE} if data is unavailable @@ -8482,6 +8487,11 @@ public class BatteryStatsImpl extends BatteryStats { return getMeasuredBatteryConsumptionUC(MeasuredEnergyStats.POWER_BUCKET_SCREEN_ON); } + @Override + public long getCpuMeasuredBatteryConsumptionUC() { + return getMeasuredBatteryConsumptionUC(MeasuredEnergyStats.POWER_BUCKET_CPU); + } + void initNetworkActivityLocked() { detachIfNotNull(mNetworkByteActivityCounters); mNetworkByteActivityCounters = new LongSamplingCounter[NUM_NETWORK_ACTIVITY_TYPES]; diff --git a/core/java/com/android/internal/os/CpuPowerCalculator.java b/core/java/com/android/internal/os/CpuPowerCalculator.java index 97f727ba72c5..b15543a26b4c 100644 --- a/core/java/com/android/internal/os/CpuPowerCalculator.java +++ b/core/java/com/android/internal/os/CpuPowerCalculator.java @@ -85,12 +85,14 @@ public class CpuPowerCalculator extends PowerCalculator { builder.getUidBatteryConsumerBuilders(); for (int i = uidBatteryConsumerBuilders.size() - 1; i >= 0; i--) { final UidBatteryConsumer.Builder app = uidBatteryConsumerBuilders.valueAt(i); - calculateApp(app, app.getBatteryStatsUid(), result); + calculateApp(app, app.getBatteryStatsUid(), query, result); } } - private void calculateApp(UidBatteryConsumer.Builder app, BatteryStats.Uid u, Result result) { - calculatePowerAndDuration(u, BatteryStats.STATS_SINCE_CHARGED, result); + private void calculateApp(UidBatteryConsumer.Builder app, BatteryStats.Uid u, + BatteryUsageStatsQuery query, Result result) { + calculatePowerAndDuration(u, BatteryStats.STATS_SINCE_CHARGED, + query.shouldForceUsePowerProfileModel(), result); app.setConsumedPower(BatteryConsumer.POWER_COMPONENT_CPU, result.powerMah) .setUsageDurationMillis(BatteryConsumer.TIME_COMPONENT_CPU, result.durationMs) @@ -112,7 +114,7 @@ public class CpuPowerCalculator extends PowerCalculator { } private void calculateApp(BatterySipper app, BatteryStats.Uid u, int statsType, Result result) { - calculatePowerAndDuration(u, statsType, result); + calculatePowerAndDuration(u, statsType, false, result); app.cpuPowerMah = result.powerMah; app.cpuTimeMs = result.durationMs; @@ -120,46 +122,16 @@ public class CpuPowerCalculator extends PowerCalculator { app.packageWithHighestDrain = result.packageWithHighestDrain; } - private void calculatePowerAndDuration(BatteryStats.Uid u, int statsType, Result result) { + private void calculatePowerAndDuration(BatteryStats.Uid u, int statsType, + boolean forceUsePowerProfileModel, Result result) { long durationMs = (u.getUserCpuTimeUs(statsType) + u.getSystemCpuTimeUs(statsType)) / 1000; - // Constant battery drain when CPU is active - double powerMah = calculateActiveCpuPowerMah(u.getCpuActiveTime()); - - // Additional per-cluster battery drain - long[] cpuClusterTimes = u.getCpuClusterTimes(); - if (cpuClusterTimes != null) { - if (cpuClusterTimes.length == mNumCpuClusters) { - for (int cluster = 0; cluster < mNumCpuClusters; cluster++) { - double power = calculatePerCpuClusterPowerMah(cluster, - cpuClusterTimes[cluster]); - powerMah += power; - if (DEBUG) { - Log.d(TAG, "UID " + u.getUid() + ": CPU cluster #" + cluster - + " clusterTimeMs=" + cpuClusterTimes[cluster] - + " power=" + formatCharge(power)); - } - } - } else { - Log.w(TAG, "UID " + u.getUid() + " CPU cluster # mismatch: Power Profile # " - + mNumCpuClusters + " actual # " + cpuClusterTimes.length); - } - } - - // Additional per-frequency battery drain - for (int cluster = 0; cluster < mNumCpuClusters; cluster++) { - final int speedsForCluster = mPerCpuFreqPowerEstimators[cluster].length; - for (int speed = 0; speed < speedsForCluster; speed++) { - final long timeUs = u.getTimeAtCpuSpeed(cluster, speed, statsType); - final double power = calculatePerCpuFreqPowerMah(cluster, speed, - timeUs / 1000); - if (DEBUG) { - Log.d(TAG, "UID " + u.getUid() + ": CPU cluster #" + cluster + " step #" - + speed + " timeUs=" + timeUs + " power=" - + formatCharge(power)); - } - powerMah += power; - } + final double powerMah; + final long consumptionUC = u.getCpuMeasuredBatteryConsumptionUC(); + if (forceUsePowerProfileModel || consumptionUC == BatteryStats.POWER_DATA_UNAVAILABLE) { + powerMah = calculateUidModeledPowerMah(u, statsType); + } else { + powerMah = uCtoMah(consumptionUC); } if (DEBUG && (durationMs != 0 || powerMah != 0)) { @@ -208,6 +180,48 @@ public class CpuPowerCalculator extends PowerCalculator { result.packageWithHighestDrain = packageWithHighestDrain; } + private double calculateUidModeledPowerMah(BatteryStats.Uid u, int statsType) { + // Constant battery drain when CPU is active + double powerMah = calculateActiveCpuPowerMah(u.getCpuActiveTime()); + + // Additional per-cluster battery drain + long[] cpuClusterTimes = u.getCpuClusterTimes(); + if (cpuClusterTimes != null) { + if (cpuClusterTimes.length == mNumCpuClusters) { + for (int cluster = 0; cluster < mNumCpuClusters; cluster++) { + double power = calculatePerCpuClusterPowerMah(cluster, + cpuClusterTimes[cluster]); + powerMah += power; + if (DEBUG) { + Log.d(TAG, "UID " + u.getUid() + ": CPU cluster #" + cluster + + " clusterTimeMs=" + cpuClusterTimes[cluster] + + " power=" + formatCharge(power)); + } + } + } else { + Log.w(TAG, "UID " + u.getUid() + " CPU cluster # mismatch: Power Profile # " + + mNumCpuClusters + " actual # " + cpuClusterTimes.length); + } + } + + // Additional per-frequency battery drain + for (int cluster = 0; cluster < mNumCpuClusters; cluster++) { + final int speedsForCluster = mPerCpuFreqPowerEstimators[cluster].length; + for (int speed = 0; speed < speedsForCluster; speed++) { + final long timeUs = u.getTimeAtCpuSpeed(cluster, speed, statsType); + final double power = calculatePerCpuFreqPowerMah(cluster, speed, + timeUs / 1000); + if (DEBUG) { + Log.d(TAG, "UID " + u.getUid() + ": CPU cluster #" + cluster + " step #" + + speed + " timeUs=" + timeUs + " power=" + + formatCharge(power)); + } + powerMah += power; + } + } + return powerMah; + } + /** * Calculates active CPU power consumption. * diff --git a/core/java/com/android/internal/telephony/IPhoneStateListener.aidl b/core/java/com/android/internal/telephony/IPhoneStateListener.aidl index 85114e59cc2d..b57b4b959334 100644 --- a/core/java/com/android/internal/telephony/IPhoneStateListener.aidl +++ b/core/java/com/android/internal/telephony/IPhoneStateListener.aidl @@ -72,5 +72,5 @@ oneway interface IPhoneStateListener { void onBarringInfoChanged(in BarringInfo barringInfo); void onPhysicalChannelConfigChanged(in List<PhysicalChannelConfig> configs); void onDataEnabledChanged(boolean enabled, int reason); - void onAllowedNetworkTypesChanged(in Map allowedNetworkTypeList); + void onAllowedNetworkTypesChanged(in int reason, in long allowedNetworkType); } diff --git a/core/java/com/android/internal/telephony/ITelephonyRegistry.aidl b/core/java/com/android/internal/telephony/ITelephonyRegistry.aidl index 95e0a3b524c5..83691ee64103 100644 --- a/core/java/com/android/internal/telephony/ITelephonyRegistry.aidl +++ b/core/java/com/android/internal/telephony/ITelephonyRegistry.aidl @@ -95,5 +95,5 @@ interface ITelephonyRegistry { void notifyPhysicalChannelConfigForSubscriber(in int subId, in List<PhysicalChannelConfig> configs); void notifyDataEnabled(in int phoneId, int subId, boolean enabled, int reason); - void notifyAllowedNetworkTypesChanged(in int phoneId, in int subId, in Map allowedNetworkTypeList); + void notifyAllowedNetworkTypesChanged(in int phoneId, in int subId, in int reason, in long allowedNetworkType); } diff --git a/core/java/com/android/internal/view/IInputMethod.aidl b/core/java/com/android/internal/view/IInputMethod.aidl index 8d82e33dc29f..c33637353984 100644 --- a/core/java/com/android/internal/view/IInputMethod.aidl +++ b/core/java/com/android/internal/view/IInputMethod.aidl @@ -35,8 +35,7 @@ import com.android.internal.view.InlineSuggestionsRequestInfo; * {@hide} */ oneway interface IInputMethod { - void initializeInternal(IBinder token, int displayId, IInputMethodPrivilegedOperations privOps, - int configChanges); + void initializeInternal(IBinder token, int displayId, IInputMethodPrivilegedOperations privOps); void onCreateInlineSuggestionsRequest(in InlineSuggestionsRequestInfo requestInfo, in IInlineSuggestionsRequestCallback cb); diff --git a/core/jni/AndroidRuntime.cpp b/core/jni/AndroidRuntime.cpp index 3bc0ef4ee3a0..94ac183517a2 100644 --- a/core/jni/AndroidRuntime.cpp +++ b/core/jni/AndroidRuntime.cpp @@ -637,6 +637,12 @@ int AndroidRuntime::startVm(JavaVM** pJavaVM, JNIEnv** pEnv, bool zygote, bool p char saveResolvedClassesDelayMsOptsBuf[ sizeof("-Xps-save-resolved-classes-delay-ms:")-1 + PROPERTY_VALUE_MAX]; char madviseRandomOptsBuf[sizeof("-XX:MadviseRandomAccess:")-1 + PROPERTY_VALUE_MAX]; + char madviseWillNeedFileSizeVdex[ + sizeof("-XMadviseWillNeedVdexFileSize:")-1 + PROPERTY_VALUE_MAX]; + char madviseWillNeedFileSizeOdex[ + sizeof("-XMadviseWillNeedOdexFileSize:")-1 + PROPERTY_VALUE_MAX]; + char madviseWillNeedFileSizeArt[ + sizeof("-XMadviseWillNeedArtFileSize:")-1 + PROPERTY_VALUE_MAX]; char gctypeOptsBuf[sizeof("-Xgc:")-1 + PROPERTY_VALUE_MAX]; char backgroundgcOptsBuf[sizeof("-XX:BackgroundGC=")-1 + PROPERTY_VALUE_MAX]; char heaptargetutilizationOptsBuf[sizeof("-XX:HeapTargetUtilization=")-1 + PROPERTY_VALUE_MAX]; @@ -845,6 +851,22 @@ int AndroidRuntime::startVm(JavaVM** pJavaVM, JNIEnv** pEnv, bool zygote, bool p parseRuntimeOption("dalvik.vm.madvise-random", madviseRandomOptsBuf, "-XX:MadviseRandomAccess:"); /* + * Use default platform configuration as limits for madvising, + * when no properties are specified. + */ + parseRuntimeOption("dalvik.vm.madvise.vdexfile.size", + madviseWillNeedFileSizeVdex, + "-XMadviseWillNeedVdexFileSize:"); + + parseRuntimeOption("dalvik.vm.madvise.odexfile.size", + madviseWillNeedFileSizeOdex, + "-XMadviseWillNeedOdexFileSize:"); + + parseRuntimeOption("dalvik.vm.madvise.artfile.size", + madviseWillNeedFileSizeArt, + "-XMadviseWillNeedArtFileSize:"); + + /* * Profile related options. */ parseRuntimeOption("dalvik.vm.hot-startup-method-samples", hotstartupsamplesOptsBuf, diff --git a/core/jni/android_util_Binder.cpp b/core/jni/android_util_Binder.cpp index f7b3f309ed12..2e4be145d54d 100644 --- a/core/jni/android_util_Binder.cpp +++ b/core/jni/android_util_Binder.cpp @@ -1509,7 +1509,9 @@ static jboolean android_os_BinderProxy_unlinkToDeath(JNIEnv* env, jobject obj, res = JNI_TRUE; } else { jniThrowException(env, "java/util/NoSuchElementException", - "Death link does not exist"); + base::StringPrintf("Death link does not exist (%s)", + statusToString(err).c_str()) + .c_str()); } } diff --git a/core/jni/android_view_KeyCharacterMap.cpp b/core/jni/android_view_KeyCharacterMap.cpp index ebc507a8381e..469e577829d8 100644 --- a/core/jni/android_view_KeyCharacterMap.cpp +++ b/core/jni/android_view_KeyCharacterMap.cpp @@ -16,9 +16,10 @@ #include <android_runtime/AndroidRuntime.h> -#include <input/KeyCharacterMap.h> -#include <input/Input.h> #include <binder/Parcel.h> +#include <input/Input.h> +#include <input/InputDevice.h> +#include <input/KeyCharacterMap.h> #include <jni.h> #include <nativehelper/JNIHelp.h> @@ -75,6 +76,10 @@ jobject android_view_KeyCharacterMap_create(JNIEnv* env, int32_t deviceId, reinterpret_cast<jlong>(nativeMap)); } +static jobject nativeObtainEmptyKeyCharacterMap(JNIEnv* env, jobject /* clazz */, jint deviceId) { + return android_view_KeyCharacterMap_create(env, deviceId, nullptr); +} + static jlong nativeReadFromParcel(JNIEnv *env, jobject clazz, jobject parcelObj) { Parcel* parcel = parcelForJavaObject(env, parcelObj); if (!parcel) { @@ -224,33 +229,37 @@ static jobjectArray nativeGetEvents(JNIEnv *env, jobject clazz, jlong ptr, return result; } +static jboolean nativeEquals(JNIEnv* env, jobject clazz, jlong ptr1, jlong ptr2) { + const std::shared_ptr<KeyCharacterMap>& map1 = + (reinterpret_cast<NativeKeyCharacterMap*>(ptr1))->getMap(); + const std::shared_ptr<KeyCharacterMap>& map2 = + (reinterpret_cast<NativeKeyCharacterMap*>(ptr2))->getMap(); + if (map1 == nullptr || map2 == nullptr) { + return map1 == map2; + } + return static_cast<jboolean>(*map1 == *map2); +} /* * JNI registration. */ static const JNINativeMethod g_methods[] = { - /* name, signature, funcPtr */ - { "nativeReadFromParcel", "(Landroid/os/Parcel;)J", - (void*)nativeReadFromParcel }, - { "nativeWriteToParcel", "(JLandroid/os/Parcel;)V", - (void*)nativeWriteToParcel }, - { "nativeDispose", "(J)V", - (void*)nativeDispose }, - { "nativeGetCharacter", "(JII)C", - (void*)nativeGetCharacter }, - { "nativeGetFallbackAction", "(JIILandroid/view/KeyCharacterMap$FallbackAction;)Z", - (void*)nativeGetFallbackAction }, - { "nativeGetNumber", "(JI)C", - (void*)nativeGetNumber }, - { "nativeGetMatch", "(JI[CI)C", - (void*)nativeGetMatch }, - { "nativeGetDisplayLabel", "(JI)C", - (void*)nativeGetDisplayLabel }, - { "nativeGetKeyboardType", "(J)I", - (void*)nativeGetKeyboardType }, - { "nativeGetEvents", "(J[C)[Landroid/view/KeyEvent;", - (void*)nativeGetEvents }, + /* name, signature, funcPtr */ + {"nativeReadFromParcel", "(Landroid/os/Parcel;)J", (void*)nativeReadFromParcel}, + {"nativeWriteToParcel", "(JLandroid/os/Parcel;)V", (void*)nativeWriteToParcel}, + {"nativeDispose", "(J)V", (void*)nativeDispose}, + {"nativeGetCharacter", "(JII)C", (void*)nativeGetCharacter}, + {"nativeGetFallbackAction", "(JIILandroid/view/KeyCharacterMap$FallbackAction;)Z", + (void*)nativeGetFallbackAction}, + {"nativeGetNumber", "(JI)C", (void*)nativeGetNumber}, + {"nativeGetMatch", "(JI[CI)C", (void*)nativeGetMatch}, + {"nativeGetDisplayLabel", "(JI)C", (void*)nativeGetDisplayLabel}, + {"nativeGetKeyboardType", "(J)I", (void*)nativeGetKeyboardType}, + {"nativeGetEvents", "(J[C)[Landroid/view/KeyEvent;", (void*)nativeGetEvents}, + {"nativeObtainEmptyKeyCharacterMap", "(I)Landroid/view/KeyCharacterMap;", + (void*)nativeObtainEmptyKeyCharacterMap}, + {"nativeEquals", "(JJ)Z", (void*)nativeEquals}, }; int register_android_view_KeyCharacterMap(JNIEnv* env) diff --git a/core/res/AndroidManifest.xml b/core/res/AndroidManifest.xml index 99ad6d100e55..f92276171b26 100644 --- a/core/res/AndroidManifest.xml +++ b/core/res/AndroidManifest.xml @@ -5419,6 +5419,8 @@ intents}. <p>Protection level: normal --> <permission android:name="android.permission.USE_FULL_SCREEN_INTENT" + android:label="@string/permlab_fullScreenIntent" + android:description="@string/permdesc_fullScreenIntent" android:protectionLevel="normal" /> <!-- @SystemApi Allows requesting the framework broadcast the diff --git a/core/res/res/values/attrs.xml b/core/res/res/values/attrs.xml index 5412db623c85..6ebd8786b5f1 100644 --- a/core/res/res/values/attrs.xml +++ b/core/res/res/values/attrs.xml @@ -3564,16 +3564,6 @@ <attr name="__removed2" format="boolean" /> <!-- Specifies whether the IME supports showing inline suggestions. --> <attr name="supportsInlineSuggestions" format="boolean" /> - <!-- Specify one or more configuration changes that the IME will handle itself. If not - specified, the IME will be restarted if any of these configuration changes happen in - the system. Otherwise, the IME will remain running and its - {@link android.inputmethodservice.InputMethodService#onConfigurationChanged} - method is called with the new configuration. - <p>Note that all of these configuration changes can impact the - resource values seen by the application, so you will generally need - to re-retrieve all resources (including view layouts, drawables, etc) - to correctly handle any configuration change.--> - <attr name="configChanges" /> </declare-styleable> <!-- This is the subtype of InputMethod. Subtype can describe locales (for example, en_US and diff --git a/core/res/res/values/strings.xml b/core/res/res/values/strings.xml index 387c065175be..8d92c66764d7 100644 --- a/core/res/res/values/strings.xml +++ b/core/res/res/values/strings.xml @@ -889,6 +889,11 @@ <!-- Description of an application permission, listed so the user can choose whether they want to allow the application to do this. --> <string name="permdesc_expandStatusBar">Allows the app to expand or collapse the status bar.</string> + <!-- Title of an application permission, listed so the user can choose whether they want to allow the application to do this. --> + <string name="permlab_fullScreenIntent">display notifications as full screen activities on a locked device</string> + <!-- Description of an application permission, listed so the user can choose whether they want to allow the application to do this. --> + <string name="permdesc_fullScreenIntent">Allows the app to display notifications as full screen activities on a locked device</string> + <!-- Title of an application permission, listed so the user can install application shortcuts in their Launcher --> <string name="permlab_install_shortcut">install shortcuts</string> diff --git a/core/tests/coretests/src/android/inputmethodservice/InputMethodServiceTest.java b/core/tests/coretests/src/android/inputmethodservice/InputMethodServiceTest.java deleted file mode 100644 index 4863cfe588ba..000000000000 --- a/core/tests/coretests/src/android/inputmethodservice/InputMethodServiceTest.java +++ /dev/null @@ -1,83 +0,0 @@ -/* - * Copyright (C) 2021 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package android.inputmethodservice; - -import static android.content.res.Configuration.KEYBOARD_12KEY; -import static android.content.res.Configuration.NAVIGATION_NONAV; - -import static androidx.test.platform.app.InstrumentationRegistry.getInstrumentation; - - -import static junit.framework.Assert.assertFalse; - -import static org.junit.Assert.assertTrue; - -import android.content.Context; -import android.content.pm.ActivityInfo; -import android.content.res.Configuration; -import android.os.Build; - -import androidx.test.filters.SmallTest; -import androidx.test.rule.ServiceTestRule; -import androidx.test.runner.AndroidJUnit4; - -import org.junit.Before; -import org.junit.Rule; -import org.junit.Test; -import org.junit.runner.RunWith; - -import java.util.concurrent.TimeoutException; - -@SmallTest -@RunWith(AndroidJUnit4.class) -public class InputMethodServiceTest { - private InputMethodService mService; - private Context mContext; - @Rule - public final ServiceTestRule serviceRule = new ServiceTestRule(); - - @Before - public void setUp() throws TimeoutException { - mContext = getInstrumentation().getContext(); - mService = new InputMethodService(); - } - - @Test - public void testShouldImeRestartForConfig() throws Exception { - // Make sure we preserve Pre-S behavior i.e. Service restarts. - mContext.getApplicationInfo().targetSdkVersion = Build.VERSION_CODES.R; - Configuration config = mContext.getResources().getConfiguration(); - mService.setLastKnownConfig(config); - assertTrue("IME should restart for Pre-S", - mService.shouldImeRestartForConfig(config)); - - // IME shouldn't restart on targetSdk S+ (with no config changes). - mContext.getApplicationInfo().targetSdkVersion = Build.VERSION_CODES.S; - assertFalse("IME shouldn't restart for S+", - mService.shouldImeRestartForConfig(config)); - - // Screen density changed but IME doesn't handle congfigChanges - config.densityDpi = 99; - assertTrue("IME should restart for unhandled configChanges", - mService.shouldImeRestartForConfig(config)); - - // opt-in IME to handle config changes. - mService.setHandledConfigChanges(ActivityInfo.CONFIG_DENSITY); - assertFalse("IME shouldn't restart for S+ since it handles configChanges", - mService.shouldImeRestartForConfig(config)); - } -} diff --git a/core/tests/coretests/src/android/os/VibratorInfoTest.java b/core/tests/coretests/src/android/os/VibratorInfoTest.java index c06405affc1b..09c36dd261bd 100644 --- a/core/tests/coretests/src/android/os/VibratorInfoTest.java +++ b/core/tests/coretests/src/android/os/VibratorInfoTest.java @@ -16,9 +16,10 @@ package android.os; -import static junit.framework.Assert.assertEquals; -import static junit.framework.Assert.assertFalse; -import static junit.framework.Assert.assertTrue; +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertNotEquals; +import static org.junit.Assert.assertTrue; import android.hardware.vibrator.IVibrator; import android.platform.test.annotations.Presubmit; @@ -33,72 +34,128 @@ public class VibratorInfoTest { @Test public void testHasAmplitudeControl() { - assertFalse(createInfo(/* capabilities= */ 0).hasAmplitudeControl()); - assertTrue(createInfo(IVibrator.CAP_COMPOSE_EFFECTS - | IVibrator.CAP_AMPLITUDE_CONTROL).hasAmplitudeControl()); + VibratorInfo noCapabilities = new InfoBuilder().build(); + assertFalse(noCapabilities.hasAmplitudeControl()); + VibratorInfo composeAndAmplitudeControl = new InfoBuilder() + .setCapabilities(IVibrator.CAP_COMPOSE_EFFECTS + | IVibrator.CAP_AMPLITUDE_CONTROL) + .build(); + assertTrue(composeAndAmplitudeControl.hasAmplitudeControl()); } @Test public void testHasCapabilities() { - assertTrue(createInfo(IVibrator.CAP_COMPOSE_EFFECTS) - .hasCapability(IVibrator.CAP_COMPOSE_EFFECTS)); - assertFalse(createInfo(IVibrator.CAP_COMPOSE_EFFECTS) - .hasCapability(IVibrator.CAP_AMPLITUDE_CONTROL)); + VibratorInfo info = new InfoBuilder() + .setCapabilities(IVibrator.CAP_COMPOSE_EFFECTS) + .build(); + assertTrue(info.hasCapability(IVibrator.CAP_COMPOSE_EFFECTS)); + assertFalse(info.hasCapability(IVibrator.CAP_AMPLITUDE_CONTROL)); } @Test public void testIsEffectSupported() { - VibratorInfo info = new VibratorInfo(/* id= */ 0, /* capabilities= */0, - new int[]{VibrationEffect.EFFECT_CLICK}, null); + VibratorInfo noEffects = new InfoBuilder().build(); + VibratorInfo canClick = new InfoBuilder() + .setSupportedEffects(VibrationEffect.EFFECT_CLICK) + .build(); assertEquals(Vibrator.VIBRATION_EFFECT_SUPPORT_UNKNOWN, - createInfo(/* capabilities= */ 0).isEffectSupported(VibrationEffect.EFFECT_CLICK)); + noEffects.isEffectSupported(VibrationEffect.EFFECT_CLICK)); assertEquals(Vibrator.VIBRATION_EFFECT_SUPPORT_YES, - info.isEffectSupported(VibrationEffect.EFFECT_CLICK)); + canClick.isEffectSupported(VibrationEffect.EFFECT_CLICK)); assertEquals(Vibrator.VIBRATION_EFFECT_SUPPORT_NO, - info.isEffectSupported(VibrationEffect.EFFECT_TICK)); + canClick.isEffectSupported(VibrationEffect.EFFECT_TICK)); } @Test public void testIsPrimitiveSupported() { - VibratorInfo info = new VibratorInfo(/* id= */ 0, IVibrator.CAP_COMPOSE_EFFECTS, - null, new int[]{VibrationEffect.Composition.PRIMITIVE_CLICK}); + VibratorInfo info = new InfoBuilder() + .setCapabilities(IVibrator.CAP_COMPOSE_EFFECTS) + .setSupportedPrimitives(VibrationEffect.Composition.PRIMITIVE_CLICK) + .build(); assertTrue(info.isPrimitiveSupported(VibrationEffect.Composition.PRIMITIVE_CLICK)); assertFalse(info.isPrimitiveSupported(VibrationEffect.Composition.PRIMITIVE_TICK)); // Returns false when there is no compose capability. - info = new VibratorInfo(/* id= */ 0, /* capabilities= */ 0, - null, new int[]{VibrationEffect.Composition.PRIMITIVE_CLICK}); + info = new InfoBuilder() + .setSupportedPrimitives(VibrationEffect.Composition.PRIMITIVE_CLICK) + .build(); assertFalse(info.isPrimitiveSupported(VibrationEffect.Composition.PRIMITIVE_CLICK)); } @Test public void testEquals() { - VibratorInfo empty = new VibratorInfo(1, 0, null, null); - VibratorInfo complete = new VibratorInfo(1, IVibrator.CAP_AMPLITUDE_CONTROL, - new int[]{VibrationEffect.EFFECT_CLICK}, - new int[]{VibrationEffect.Composition.PRIMITIVE_CLICK}); + InfoBuilder completeBuilder = new InfoBuilder() + .setId(1) + .setCapabilities(IVibrator.CAP_AMPLITUDE_CONTROL) + .setSupportedEffects(VibrationEffect.EFFECT_CLICK) + .setSupportedPrimitives(VibrationEffect.Composition.PRIMITIVE_CLICK) + .setQFactor(2f) + .setResonantFrequency(150f); + VibratorInfo complete = completeBuilder.build(); assertEquals(complete, complete); - assertEquals(complete, new VibratorInfo(1, IVibrator.CAP_AMPLITUDE_CONTROL, - new int[]{VibrationEffect.EFFECT_CLICK}, - new int[]{VibrationEffect.Composition.PRIMITIVE_CLICK})); - - assertFalse(empty.equals(new VibratorInfo(1, 0, new int[]{}, new int[]{}))); - assertFalse(complete.equals(new VibratorInfo(1, IVibrator.CAP_COMPOSE_EFFECTS, - new int[]{VibrationEffect.EFFECT_CLICK}, - new int[]{VibrationEffect.Composition.PRIMITIVE_CLICK}))); - assertFalse(complete.equals(new VibratorInfo(1, IVibrator.CAP_AMPLITUDE_CONTROL, - new int[]{}, new int[]{}))); - assertFalse(complete.equals(new VibratorInfo(1, IVibrator.CAP_AMPLITUDE_CONTROL, - null, new int[]{VibrationEffect.Composition.PRIMITIVE_CLICK}))); - assertFalse(complete.equals(new VibratorInfo(1, IVibrator.CAP_AMPLITUDE_CONTROL, - new int[]{VibrationEffect.EFFECT_CLICK}, null))); + assertEquals(complete, completeBuilder.build()); + + VibratorInfo completeWithComposeControl = completeBuilder + .setCapabilities(IVibrator.CAP_COMPOSE_EFFECTS) + .build(); + assertNotEquals(complete, completeWithComposeControl); + + VibratorInfo completeWithNoEffects = completeBuilder + .setSupportedEffects() + .setSupportedPrimitives() + .build(); + assertNotEquals(complete, completeWithNoEffects); + + VibratorInfo completeWithUnknownEffects = completeBuilder + .setSupportedEffects(null) + .build(); + assertNotEquals(complete, completeWithNoEffects); + + VibratorInfo completeWithUnknownPrimitives = completeBuilder + .setSupportedPrimitives(null) + .build(); + assertNotEquals(complete, completeWithUnknownPrimitives); + + VibratorInfo completeWithDifferentF0 = completeBuilder + .setResonantFrequency(complete.getResonantFrequency() + 3f) + .build(); + assertNotEquals(complete, completeWithDifferentF0); + + VibratorInfo completeWithUnknownF0 = completeBuilder + .setResonantFrequency(Float.NaN) + .build(); + assertNotEquals(complete, completeWithUnknownF0); + + VibratorInfo completeWithUnknownQFactor = completeBuilder + .setQFactor(Float.NaN) + .build(); + assertNotEquals(complete, completeWithUnknownQFactor); + + VibratorInfo completeWithDifferentQFactor = completeBuilder + .setQFactor(complete.getQFactor() + 3f) + .build(); + assertNotEquals(complete, completeWithDifferentQFactor); + + VibratorInfo empty = new InfoBuilder().setId(1).build(); + VibratorInfo emptyWithKnownSupport = new InfoBuilder() + .setId(1) + .setSupportedEffects() + .setSupportedPrimitives() + .build(); + assertNotEquals(empty, emptyWithKnownSupport); } @Test - public void testSerialization() { - VibratorInfo original = new VibratorInfo(1, IVibrator.CAP_COMPOSE_EFFECTS, - new int[]{VibrationEffect.EFFECT_CLICK}, null); + public void testParceling() { + VibratorInfo original = new InfoBuilder() + .setId(1) + .setCapabilities(IVibrator.CAP_COMPOSE_EFFECTS) + .setSupportedEffects(VibrationEffect.EFFECT_CLICK) + .setSupportedPrimitives(null) + .setResonantFrequency(1.3f) + .setQFactor(Float.NaN) + .build(); Parcel parcel = Parcel.obtain(); original.writeToParcel(parcel, 0); @@ -107,7 +164,47 @@ public class VibratorInfoTest { assertEquals(original, restored); } - private static VibratorInfo createInfo(long capabilities) { - return new VibratorInfo(/* id= */ 0, capabilities, null, null); + private static class InfoBuilder { + private int mId = 0; + private int mCapabilities = 0; + private int[] mSupportedEffects = null; + private int[] mSupportedPrimitives = null; + private float mResonantFrequency = Float.NaN; + private float mQFactor = Float.NaN; + + public InfoBuilder setId(int id) { + mId = id; + return this; + } + + public InfoBuilder setCapabilities(int capabilities) { + mCapabilities = capabilities; + return this; + } + + public InfoBuilder setSupportedEffects(int... supportedEffects) { + mSupportedEffects = supportedEffects; + return this; + } + + public InfoBuilder setSupportedPrimitives(int... supportedPrimitives) { + mSupportedPrimitives = supportedPrimitives; + return this; + } + + public InfoBuilder setResonantFrequency(float resonantFrequency) { + mResonantFrequency = resonantFrequency; + return this; + } + + public InfoBuilder setQFactor(float qFactor) { + mQFactor = qFactor; + return this; + } + + public VibratorInfo build() { + return new VibratorInfo(mId, mCapabilities, mSupportedEffects, mSupportedPrimitives, + mResonantFrequency, mQFactor); + } } } diff --git a/core/tests/coretests/src/com/android/internal/os/CpuPowerCalculatorTest.java b/core/tests/coretests/src/com/android/internal/os/CpuPowerCalculatorTest.java index 70888905d7c8..10ff3a47a7d9 100644 --- a/core/tests/coretests/src/com/android/internal/os/CpuPowerCalculatorTest.java +++ b/core/tests/coretests/src/com/android/internal/os/CpuPowerCalculatorTest.java @@ -19,18 +19,22 @@ package com.android.internal.os; import static com.google.common.truth.Truth.assertThat; import static org.mockito.ArgumentMatchers.any; +import static org.mockito.ArgumentMatchers.anyBoolean; import static org.mockito.ArgumentMatchers.anyInt; import static org.mockito.Mockito.doAnswer; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.when; import android.os.BatteryConsumer; +import android.os.BatteryUsageStatsQuery; import android.os.Process; import android.os.UidBatteryConsumer; import androidx.test.filters.SmallTest; import androidx.test.runner.AndroidJUnit4; +import com.android.internal.power.MeasuredEnergyStats; + import org.junit.Before; import org.junit.Rule; import org.junit.Test; @@ -81,6 +85,10 @@ public class CpuPowerCalculatorTest { public void setUp() { MockitoAnnotations.initMocks(this); + final boolean[] supportedPowerBuckets = + new boolean[MeasuredEnergyStats.NUMBER_STANDARD_POWER_BUCKETS]; + supportedPowerBuckets[MeasuredEnergyStats.POWER_BUCKET_CPU] = true; + mStatsRule.getBatteryStats() .setUserInfoProvider(mMockUserInfoProvider) .setKernelCpuSpeedReaders(mMockKernelCpuSpeedReaders) @@ -88,7 +96,8 @@ public class CpuPowerCalculatorTest { .setKernelCpuUidClusterTimeReader(mMockKernelCpuUidClusterTimeReader) .setKernelCpuUidUserSysTimeReader(mMockKernelCpuUidUserSysTimeReader) .setKernelCpuUidActiveTimeReader(mMockKerneCpuUidActiveTimeReader) - .setSystemServerCpuThreadReader(mMockSystemServerCpuThreadReader); + .setSystemServerCpuThreadReader(mMockSystemServerCpuThreadReader) + .initMeasuredEnergyStatsLocked(supportedPowerBuckets, 0); } @Test @@ -103,28 +112,28 @@ public class CpuPowerCalculatorTest { // User/System CPU time doAnswer(invocation -> { - final KernelCpuUidTimeReader.Callback<long[]> callback = invocation.getArgument(0); + final KernelCpuUidTimeReader.Callback<long[]> callback = invocation.getArgument(1); // User/system time in microseconds callback.onUidCpuTime(APP_UID1, new long[]{1111000, 2222000}); callback.onUidCpuTime(APP_UID2, new long[]{3333000, 4444000}); return null; - }).when(mMockKernelCpuUidUserSysTimeReader).readDelta(any()); + }).when(mMockKernelCpuUidUserSysTimeReader).readDelta(anyBoolean(), any()); // Active CPU time doAnswer(invocation -> { - final KernelCpuUidTimeReader.Callback<Long> callback = invocation.getArgument(0); + final KernelCpuUidTimeReader.Callback<Long> callback = invocation.getArgument(1); callback.onUidCpuTime(APP_UID1, 1111L); callback.onUidCpuTime(APP_UID2, 3333L); return null; - }).when(mMockKerneCpuUidActiveTimeReader).readDelta(any()); + }).when(mMockKerneCpuUidActiveTimeReader).readDelta(anyBoolean(), any()); // Per-cluster CPU time doAnswer(invocation -> { - final KernelCpuUidTimeReader.Callback<long[]> callback = invocation.getArgument(0); + final KernelCpuUidTimeReader.Callback<long[]> callback = invocation.getArgument(1); callback.onUidCpuTime(APP_UID1, new long[]{1111, 2222}); callback.onUidCpuTime(APP_UID2, new long[]{3333, 4444}); return null; - }).when(mMockKernelCpuUidClusterTimeReader).readDelta(any()); + }).when(mMockKernelCpuUidClusterTimeReader).readDelta(anyBoolean(), any()); mStatsRule.getBatteryStats().updateCpuTimeLocked(true, true, null); @@ -134,7 +143,8 @@ public class CpuPowerCalculatorTest { CpuPowerCalculator calculator = new CpuPowerCalculator(mStatsRule.getPowerProfile()); - mStatsRule.apply(calculator); + mStatsRule.apply(new BatteryUsageStatsQuery.Builder().powerProfileModeledOnly().build(), + calculator); UidBatteryConsumer uidConsumer1 = mStatsRule.getUidBatteryConsumer(APP_UID1); assertThat(uidConsumer1.getUsageDurationMillis(BatteryConsumer.TIME_COMPONENT_CPU)) @@ -150,4 +160,64 @@ public class CpuPowerCalculatorTest { .isWithin(PRECISION).of(2.672322); assertThat(uidConsumer2.getPackageWithHighestDrain()).isNull(); } + + @Test + public void testMeasuredEnergyBasedModel() { + when(mMockUserInfoProvider.exists(anyInt())).thenReturn(true); + + when(mMockKernelCpuSpeedReaders[0].readDelta()).thenReturn(new long[]{1000, 2000}); + when(mMockKernelCpuSpeedReaders[1].readDelta()).thenReturn(new long[]{3000, 4000}); + + when(mMockCpuUidFreqTimeReader.perClusterTimesAvailable()).thenReturn(false); + + // User/System CPU time + doAnswer(invocation -> { + final KernelCpuUidTimeReader.Callback<long[]> callback = invocation.getArgument(1); + // User/system time in microseconds + callback.onUidCpuTime(APP_UID1, new long[]{1111000, 2222000}); + callback.onUidCpuTime(APP_UID2, new long[]{3333000, 4444000}); + return null; + }).when(mMockKernelCpuUidUserSysTimeReader).readDelta(anyBoolean(), any()); + + // Active CPU time + doAnswer(invocation -> { + final KernelCpuUidTimeReader.Callback<Long> callback = invocation.getArgument(1); + callback.onUidCpuTime(APP_UID1, 1111L); + callback.onUidCpuTime(APP_UID2, 3333L); + return null; + }).when(mMockKerneCpuUidActiveTimeReader).readDelta(anyBoolean(), any()); + + // Per-cluster CPU time + doAnswer(invocation -> { + final KernelCpuUidTimeReader.Callback<long[]> callback = invocation.getArgument(1); + callback.onUidCpuTime(APP_UID1, new long[]{1111, 2222}); + callback.onUidCpuTime(APP_UID2, new long[]{3333, 4444}); + return null; + }).when(mMockKernelCpuUidClusterTimeReader).readDelta(anyBoolean(), any()); + + final long[] clusterChargesUC = new long[]{13577531, 24688642}; + mStatsRule.getBatteryStats().updateCpuTimeLocked(true, true, clusterChargesUC); + + mStatsRule.getUidStats(APP_UID1).getProcessStatsLocked("foo").addCpuTimeLocked(4321, 1234); + mStatsRule.getUidStats(APP_UID1).getProcessStatsLocked("bar").addCpuTimeLocked(5432, 2345); + + CpuPowerCalculator calculator = + new CpuPowerCalculator(mStatsRule.getPowerProfile()); + + mStatsRule.apply(calculator); + + UidBatteryConsumer uidConsumer1 = mStatsRule.getUidBatteryConsumer(APP_UID1); + assertThat(uidConsumer1.getUsageDurationMillis(BatteryConsumer.TIME_COMPONENT_CPU)) + .isEqualTo(3333); + assertThat(uidConsumer1.getConsumedPower(BatteryConsumer.POWER_COMPONENT_CPU)) + .isWithin(PRECISION).of(3.18877); + assertThat(uidConsumer1.getPackageWithHighestDrain()).isEqualTo("bar"); + + UidBatteryConsumer uidConsumer2 = mStatsRule.getUidBatteryConsumer(APP_UID2); + assertThat(uidConsumer2.getUsageDurationMillis(BatteryConsumer.TIME_COMPONENT_CPU)) + .isEqualTo(7777); + assertThat(uidConsumer2.getConsumedPower(BatteryConsumer.POWER_COMPONENT_CPU)) + .isWithin(PRECISION).of(7.44072); + assertThat(uidConsumer2.getPackageWithHighestDrain()).isNull(); + } } diff --git a/data/etc/platform.xml b/data/etc/platform.xml index 77a38a9bb1a0..b3a180d70fe2 100644 --- a/data/etc/platform.xml +++ b/data/etc/platform.xml @@ -154,6 +154,7 @@ <assign-permission name="android.permission.GET_PROCESS_STATE_AND_OOM_SCORE" uid="media" /> <assign-permission name="android.permission.PACKAGE_USAGE_STATS" uid="media" /> <assign-permission name="android.permission.REGISTER_MEDIA_RESOURCE_OBSERVER" uid="media" /> + <assign-permission name="android.permission.REGISTER_STATS_PULL_ATOM" uid="media" /> <assign-permission name="android.permission.INTERNET" uid="media" /> diff --git a/keystore/java/android/security/AndroidKeyStoreMaintenance.java b/keystore/java/android/security/AndroidKeyStoreMaintenance.java index 55015696ff47..35b1c169f283 100644 --- a/keystore/java/android/security/AndroidKeyStoreMaintenance.java +++ b/keystore/java/android/security/AndroidKeyStoreMaintenance.java @@ -121,4 +121,22 @@ public class AndroidKeyStoreMaintenance { return SYSTEM_ERROR; } } + + /** + * Queries user state from Keystore 2.0. + * + * @param userId - Android user id of the user. + * @return UserState enum variant as integer if successful or an error + */ + public static int getState(int userId) { + try { + return getService().getState(userId); + } catch (ServiceSpecificException e) { + Log.e(TAG, "getState failed", e); + return e.errorCode; + } catch (Exception e) { + Log.e(TAG, "Can not connect to keystore", e); + return SYSTEM_ERROR; + } + } } diff --git a/keystore/java/android/security/KeyStore.java b/keystore/java/android/security/KeyStore.java index 93658e69eac8..937f01ce3767 100644 --- a/keystore/java/android/security/KeyStore.java +++ b/keystore/java/android/security/KeyStore.java @@ -43,6 +43,7 @@ import android.security.keystore.KeyPermanentlyInvalidatedException; import android.security.keystore.KeyProperties; import android.security.keystore.KeystoreResponse; import android.security.keystore.UserNotAuthenticatedException; +import android.security.maintenance.UserState; import android.system.keystore2.Domain; import android.util.Log; @@ -196,6 +197,19 @@ public class KeyStore { public State state(int userId) { final int ret; try { + if (android.security.keystore2.AndroidKeyStoreProvider.isInstalled()) { + int userState = AndroidKeyStoreMaintenance.getState(userId); + switch (userState) { + case UserState.UNINITIALIZED: + return KeyStore.State.UNINITIALIZED; + case UserState.LSKF_UNLOCKED: + return KeyStore.State.UNLOCKED; + case UserState.LSKF_LOCKED: + return KeyStore.State.LOCKED; + default: + throw new AssertionError(KeyStore.VALUE_CORRUPTED); + } + } ret = mBinder.getState(userId); } catch (RemoteException e) { Log.w(TAG, "Cannot connect to keystore", e); diff --git a/libs/WindowManager/Shell/Android.bp b/libs/WindowManager/Shell/Android.bp index 1b5dc8bdbcaa..3f03302de474 100644 --- a/libs/WindowManager/Shell/Android.bp +++ b/libs/WindowManager/Shell/Android.bp @@ -38,6 +38,14 @@ filegroup { path: "src", } +filegroup { + name: "wm_shell-aidls", + srcs: [ + "src/**/*.aidl", + ], + path: "src", +} + // TODO(b/168581922) protologtool do not support kotlin(*.kt) filegroup { name: "wm_shell-sources-kt", @@ -98,7 +106,7 @@ android_library { ":wm_shell_protolog_src", // TODO(b/168581922) protologtool do not support kotlin(*.kt) ":wm_shell-sources-kt", - "src/**/I*.aidl", + ":wm_shell-aidls", ], resource_dirs: [ "res", diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/ShellCommandHandlerImpl.java b/libs/WindowManager/Shell/src/com/android/wm/shell/ShellCommandHandlerImpl.java index eaed24d6195a..d451f4a0661b 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/ShellCommandHandlerImpl.java +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/ShellCommandHandlerImpl.java @@ -47,21 +47,7 @@ public final class ShellCommandHandlerImpl { private final ShellExecutor mMainExecutor; private final HandlerImpl mImpl = new HandlerImpl(); - public static ShellCommandHandler create( - ShellTaskOrganizer shellTaskOrganizer, - Optional<LegacySplitScreenController> legacySplitScreenOptional, - Optional<SplitScreenController> splitScreenOptional, - Optional<Pip> pipOptional, - Optional<OneHandedController> oneHandedOptional, - Optional<HideDisplayCutoutController> hideDisplayCutout, - Optional<AppPairsController> appPairsOptional, - ShellExecutor mainExecutor) { - return new ShellCommandHandlerImpl(shellTaskOrganizer, legacySplitScreenOptional, - splitScreenOptional, pipOptional, oneHandedOptional, hideDisplayCutout, - appPairsOptional, mainExecutor).mImpl; - } - - private ShellCommandHandlerImpl( + public ShellCommandHandlerImpl( ShellTaskOrganizer shellTaskOrganizer, Optional<LegacySplitScreenController> legacySplitScreenOptional, Optional<SplitScreenController> splitScreenOptional, @@ -80,6 +66,10 @@ public final class ShellCommandHandlerImpl { mMainExecutor = mainExecutor; } + public ShellCommandHandler asShellCommandHandler() { + return mImpl; + } + /** Dumps WM Shell internal state. */ private void dump(PrintWriter pw) { mShellTaskOrganizer.dump(pw, ""); diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/ShellInitImpl.java b/libs/WindowManager/Shell/src/com/android/wm/shell/ShellInitImpl.java index 85bd24c1c2bf..6f4550c2a89e 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/ShellInitImpl.java +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/ShellInitImpl.java @@ -26,7 +26,7 @@ import com.android.wm.shell.draganddrop.DragAndDropController; import com.android.wm.shell.legacysplitscreen.LegacySplitScreenController; import com.android.wm.shell.pip.phone.PipTouchHandler; import com.android.wm.shell.splitscreen.SplitScreenController; -import com.android.wm.shell.startingsurface.StartingSurface; +import com.android.wm.shell.startingsurface.StartingWindowController; import com.android.wm.shell.transition.Transitions; import java.util.Optional; @@ -47,44 +47,20 @@ public class ShellInitImpl { private final FullscreenTaskListener mFullscreenTaskListener; private final ShellExecutor mMainExecutor; private final Transitions mTransitions; - private final Optional<StartingSurface> mStartingSurfaceOptional; + private final StartingWindowController mStartingWindow; private final InitImpl mImpl = new InitImpl(); - public static ShellInit create(DisplayImeController displayImeController, + public ShellInitImpl(DisplayImeController displayImeController, DragAndDropController dragAndDropController, ShellTaskOrganizer shellTaskOrganizer, Optional<LegacySplitScreenController> legacySplitScreenOptional, Optional<SplitScreenController> splitScreenOptional, Optional<AppPairsController> appPairsOptional, - Optional<StartingSurface> startingSurfaceOptional, - Optional<PipTouchHandler> pipTouchHandlerOptional, - FullscreenTaskListener fullscreenTaskListener, - Transitions transitions, - ShellExecutor mainExecutor) { - return new ShellInitImpl(displayImeController, - dragAndDropController, - shellTaskOrganizer, - legacySplitScreenOptional, - splitScreenOptional, - appPairsOptional, - startingSurfaceOptional, - pipTouchHandlerOptional, - fullscreenTaskListener, - transitions, - mainExecutor).mImpl; - } - - private ShellInitImpl(DisplayImeController displayImeController, - DragAndDropController dragAndDropController, - ShellTaskOrganizer shellTaskOrganizer, - Optional<LegacySplitScreenController> legacySplitScreenOptional, - Optional<SplitScreenController> splitScreenOptional, - Optional<AppPairsController> appPairsOptional, - Optional<StartingSurface> startingSurfaceOptional, Optional<PipTouchHandler> pipTouchHandlerOptional, FullscreenTaskListener fullscreenTaskListener, Transitions transitions, + StartingWindowController startingWindow, ShellExecutor mainExecutor) { mDisplayImeController = displayImeController; mDragAndDropController = dragAndDropController; @@ -96,17 +72,21 @@ public class ShellInitImpl { mPipTouchHandlerOptional = pipTouchHandlerOptional; mTransitions = transitions; mMainExecutor = mainExecutor; - mStartingSurfaceOptional = startingSurfaceOptional; + mStartingWindow = startingWindow; + } + + public ShellInit asShellInit() { + return mImpl; } private void init() { // Start listening for display changes mDisplayImeController.startMonitorDisplays(); + // Setup the shell organizer mShellTaskOrganizer.addListenerForType( mFullscreenTaskListener, TASK_LISTENER_TYPE_FULLSCREEN); - mStartingSurfaceOptional.ifPresent(mShellTaskOrganizer::initStartingSurface); - // Register the shell organizer + mShellTaskOrganizer.initStartingWindow(mStartingWindow); mShellTaskOrganizer.registerOrganizer(); mAppPairsOptional.ifPresent(AppPairsController::onOrganizerRegistered); diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/ShellTaskOrganizer.java b/libs/WindowManager/Shell/src/com/android/wm/shell/ShellTaskOrganizer.java index fcb53cd890b7..94d13eab4299 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/ShellTaskOrganizer.java +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/ShellTaskOrganizer.java @@ -48,7 +48,7 @@ import com.android.internal.annotations.VisibleForTesting; import com.android.internal.protolog.common.ProtoLog; import com.android.wm.shell.common.ShellExecutor; import com.android.wm.shell.sizecompatui.SizeCompatUIController; -import com.android.wm.shell.startingsurface.StartingSurface; +import com.android.wm.shell.startingsurface.StartingWindowController; import java.io.PrintWriter; import java.util.ArrayList; @@ -133,7 +133,7 @@ public class ShellTaskOrganizer extends TaskOrganizer { private final ArraySet<LocusIdListener> mLocusIdListeners = new ArraySet<>(); private final Object mLock = new Object(); - private StartingSurface mStartingSurface; + private StartingWindowController mStartingWindow; /** * In charge of showing size compat UI. Can be {@code null} if device doesn't support size @@ -184,8 +184,8 @@ public class ShellTaskOrganizer extends TaskOrganizer { /** * @hide */ - public void initStartingSurface(StartingSurface startingSurface) { - mStartingSurface = startingSurface; + public void initStartingWindow(StartingWindowController startingWindow) { + mStartingWindow = startingWindow; } /** @@ -302,23 +302,23 @@ public class ShellTaskOrganizer extends TaskOrganizer { @Override public void addStartingWindow(StartingWindowInfo info, IBinder appToken) { - if (mStartingSurface != null) { - mStartingSurface.addStartingWindow(info, appToken); + if (mStartingWindow != null) { + mStartingWindow.addStartingWindow(info, appToken); } } @Override public void removeStartingWindow(int taskId, SurfaceControl leash, Rect frame, boolean playRevealAnimation) { - if (mStartingSurface != null) { - mStartingSurface.removeStartingWindow(taskId, leash, frame, playRevealAnimation); + if (mStartingWindow != null) { + mStartingWindow.removeStartingWindow(taskId, leash, frame, playRevealAnimation); } } @Override public void copySplashScreenView(int taskId) { - if (mStartingSurface != null) { - mStartingSurface.copySplashScreenView(taskId); + if (mStartingWindow != null) { + mStartingWindow.copySplashScreenView(taskId); } } diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/common/ExecutorUtils.java b/libs/WindowManager/Shell/src/com/android/wm/shell/common/ExecutorUtils.java new file mode 100644 index 000000000000..b29058b1f204 --- /dev/null +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/common/ExecutorUtils.java @@ -0,0 +1,64 @@ +/* + * Copyright (C) 2021 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.wm.shell.common; + +import android.Manifest; +import android.util.Slog; + +import java.util.function.Consumer; + +/** + * Helpers for working with executors + */ +public class ExecutorUtils { + + /** + * Checks that the caller has the MANAGE_ACTIVITY_TASKS permission and executes the given + * callback. + */ + public static <T> void executeRemoteCallWithTaskPermission(RemoteCallable<T> controllerInstance, + String log, Consumer<T> callback) { + executeRemoteCallWithTaskPermission(controllerInstance, log, callback, + false /* blocking */); + } + + /** + * Checks that the caller has the MANAGE_ACTIVITY_TASKS permission and executes the given + * callback. + */ + public static <T> void executeRemoteCallWithTaskPermission(RemoteCallable<T> controllerInstance, + String log, Consumer<T> callback, boolean blocking) { + if (controllerInstance == null) return; + + final RemoteCallable<T> controller = controllerInstance; + controllerInstance.getContext().enforceCallingPermission( + Manifest.permission.MANAGE_ACTIVITY_TASKS, log); + if (blocking) { + try { + controllerInstance.getRemoteCallExecutor().executeBlocking(() -> { + callback.accept((T) controller); + }); + } catch (InterruptedException e) { + Slog.e("ExecutorUtils", "Remote call failed", e); + } + } else { + controllerInstance.getRemoteCallExecutor().execute(() -> { + callback.accept((T) controller); + }); + } + } +} diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/common/RemoteCallable.java b/libs/WindowManager/Shell/src/com/android/wm/shell/common/RemoteCallable.java new file mode 100644 index 000000000000..30f535ba940c --- /dev/null +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/common/RemoteCallable.java @@ -0,0 +1,34 @@ +/* + * Copyright (C) 2021 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.wm.shell.common; + +import android.content.Context; + +/** + * An interface for controllers that can receive remote calls. + */ +public interface RemoteCallable<T> { + /** + * Returns a context used for permission checking. + */ + Context getContext(); + + /** + * Returns the executor to post the handler callback to. + */ + ShellExecutor getRemoteCallExecutor(); +}
\ No newline at end of file diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/draganddrop/DragAndDropPolicy.java b/libs/WindowManager/Shell/src/com/android/wm/shell/draganddrop/DragAndDropPolicy.java index aab2334f8255..9a09ca43d1d7 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/draganddrop/DragAndDropPolicy.java +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/draganddrop/DragAndDropPolicy.java @@ -235,7 +235,7 @@ public class DragAndDropPolicy { mStarter.startShortcut(packageName, id, stage, position, opts, user); } else { mStarter.startIntent(intent.getParcelableExtra(EXTRA_PENDING_INTENT), - mContext, null, stage, position, opts); + null, stage, position, opts); } } @@ -295,7 +295,7 @@ public class DragAndDropPolicy { @Nullable Bundle options); void startShortcut(String packageName, String shortcutId, @StageType int stage, @StagePosition int position, @Nullable Bundle options, UserHandle user); - void startIntent(PendingIntent intent, Context context, Intent fillInIntent, + void startIntent(PendingIntent intent, Intent fillInIntent, @StageType int stage, @StagePosition int position, @Nullable Bundle options); void enterSplitScreen(int taskId, boolean leftOrTop); @@ -337,9 +337,8 @@ public class DragAndDropPolicy { } @Override - public void startIntent(PendingIntent intent, Context context, - @Nullable Intent fillInIntent, int stage, int position, - @Nullable Bundle options) { + public void startIntent(PendingIntent intent, @Nullable Intent fillInIntent, int stage, + int position, @Nullable Bundle options) { try { intent.send(mContext, 0, fillInIntent, null, null, null, options); } catch (PendingIntent.CanceledException e) { diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/onehanded/IOneHanded.aidl b/libs/WindowManager/Shell/src/com/android/wm/shell/onehanded/IOneHanded.aidl new file mode 100644 index 000000000000..008b5087d7da --- /dev/null +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/onehanded/IOneHanded.aidl @@ -0,0 +1,33 @@ +/* + * Copyright (C) 2021 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.wm.shell.onehanded; + +/** + * Interface that is exposed to remote callers to manipulate the OneHanded feature. + */ +interface IOneHanded { + + /** + * Enters one handed mode. + */ + oneway void startOneHanded() = 1; + + /** + * Exits one handed mode. + */ + oneway void stopOneHanded() = 2; +} diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/onehanded/OneHanded.java b/libs/WindowManager/Shell/src/com/android/wm/shell/onehanded/OneHanded.java index 4f31c370108d..a7e9a0135de0 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/onehanded/OneHanded.java +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/onehanded/OneHanded.java @@ -26,6 +26,14 @@ import com.android.wm.shell.onehanded.OneHandedGestureHandler.OneHandedGestureEv */ @ExternalThread public interface OneHanded { + + /** + * Returns a binder that can be passed to an external process to manipulate OneHanded. + */ + default IOneHanded createExternalInterface() { + return null; + } + /** * Return one handed settings enabled or not. */ diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/onehanded/OneHandedController.java b/libs/WindowManager/Shell/src/com/android/wm/shell/onehanded/OneHandedController.java index 5fc7c987899f..8022c1b6e047 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/onehanded/OneHandedController.java +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/onehanded/OneHandedController.java @@ -18,6 +18,10 @@ package com.android.wm.shell.onehanded; import static android.os.UserHandle.USER_CURRENT; +import static com.android.wm.shell.common.ExecutorUtils.executeRemoteCallWithTaskPermission; + +import android.Manifest; +import android.annotation.BinderThread; import android.content.ComponentName; import android.content.Context; import android.content.om.IOverlayManager; @@ -43,6 +47,8 @@ import com.android.internal.logging.UiEventLogger; import com.android.wm.shell.R; import com.android.wm.shell.common.DisplayChangeController; import com.android.wm.shell.common.DisplayController; +import com.android.wm.shell.common.ExecutorUtils; +import com.android.wm.shell.common.RemoteCallable; import com.android.wm.shell.common.ShellExecutor; import com.android.wm.shell.common.TaskStackListenerCallback; import com.android.wm.shell.common.TaskStackListenerImpl; @@ -54,7 +60,7 @@ import java.io.PrintWriter; /** * Manages and manipulates the one handed states, transitions, and gesture for phones. */ -public class OneHandedController { +public class OneHandedController implements RemoteCallable<OneHandedController> { private static final String TAG = "OneHandedController"; private static final String ONE_HANDED_MODE_OFFSET_PERCENTAGE = @@ -239,6 +245,16 @@ public class OneHandedController { return mImpl; } + @Override + public Context getContext() { + return mContext; + } + + @Override + public ShellExecutor getRemoteCallExecutor() { + return mMainExecutor; + } + /** * Set one handed enabled or disabled when user update settings */ @@ -567,8 +583,22 @@ public class OneHandedController { } } + /** + * The interface for calls from outside the Shell, within the host process. + */ @ExternalThread private class OneHandedImpl implements OneHanded { + private IOneHandedImpl mIOneHanded; + + @Override + public IOneHanded createExternalInterface() { + if (mIOneHanded != null) { + mIOneHanded.invalidate(); + } + mIOneHanded = new IOneHandedImpl(OneHandedController.this); + return mIOneHanded; + } + @Override public boolean isOneHandedEnabled() { // This is volatile so return directly @@ -637,4 +667,39 @@ public class OneHandedController { }); } } + + /** + * The interface for calls from outside the host process. + */ + @BinderThread + private static class IOneHandedImpl extends IOneHanded.Stub { + private OneHandedController mController; + + IOneHandedImpl(OneHandedController controller) { + mController = controller; + } + + /** + * Invalidates this instance, preventing future calls from updating the controller. + */ + void invalidate() { + mController = null; + } + + @Override + public void startOneHanded() { + executeRemoteCallWithTaskPermission(mController, "startOneHanded", + (controller) -> { + controller.startOneHanded(); + }); + } + + @Override + public void stopOneHanded() { + executeRemoteCallWithTaskPermission(mController, "stopOneHanded", + (controller) -> { + controller.stopOneHanded(); + }); + } + } } diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/IPip.aidl b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/IPip.aidl new file mode 100644 index 000000000000..a6ffa6e44584 --- /dev/null +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/IPip.aidl @@ -0,0 +1,63 @@ +/* + * Copyright (C) 2021 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.wm.shell.pip; + +import android.app.PictureInPictureParams; +import android.content.ComponentName; +import android.content.pm.ActivityInfo; +import android.graphics.Rect; + +import com.android.wm.shell.pip.IPipAnimationListener; + +/** + * Interface that is exposed to remote callers to manipulate the Pip feature. + */ +interface IPip { + + /** + * Notifies that Activity is about to be swiped to home with entering PiP transition and + * queries the destination bounds for PiP depends on Launcher's rotation and shelf height. + * + * @param componentName ComponentName represents the Activity + * @param activityInfo ActivityInfo tied to the Activity + * @param pictureInPictureParams PictureInPictureParams tied to the Activity + * @param launcherRotation Launcher rotation to calculate the PiP destination bounds + * @param shelfHeight Shelf height of launcher to calculate the PiP destination bounds + * @return destination bounds the PiP window should land into + */ + Rect startSwipePipToHome(in ComponentName componentName, in ActivityInfo activityInfo, + in PictureInPictureParams pictureInPictureParams, + int launcherRotation, int shelfHeight) = 1; + + /** + * Notifies the swiping Activity to PiP onto home transition is finished + * + * @param componentName ComponentName represents the Activity + * @param destinationBounds the destination bounds the PiP window lands into + */ + oneway void stopSwipePipToHome(in ComponentName componentName, in Rect destinationBounds) = 2; + + /** + * Sets listener to get pinned stack animation callbacks. + */ + oneway void setPinnedStackAnimationListener(IPipAnimationListener listener) = 3; + + /** + * Sets the shelf height and visibility. + */ + oneway void setShelfHeight(boolean visible, int shelfHeight) = 4; +} diff --git a/packages/SystemUI/shared/src/com/android/systemui/shared/recents/IPinnedStackAnimationListener.aidl b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/IPipAnimationListener.aidl index 97aa512ea7df..2569b780c1bb 100644 --- a/packages/SystemUI/shared/src/com/android/systemui/shared/recents/IPinnedStackAnimationListener.aidl +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/IPipAnimationListener.aidl @@ -14,15 +14,14 @@ * limitations under the License. */ -package com.android.systemui.shared.recents; +package com.android.wm.shell.pip; /** - * Listener interface that Launcher attaches to SystemUI to get - * pinned stack animation callbacks. + * Listener interface that Launcher attaches to SystemUI to get Pip animation callbacks. */ -oneway interface IPinnedStackAnimationListener { +oneway interface IPipAnimationListener { /** - * Notifies the pinned stack animation is started. + * Notifies the listener that the Pip animation is started. */ - void onPinnedStackAnimationStarted(); + void onPipAnimationStarted(); } diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/Pip.java b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/Pip.java index d14c3e3c0dd4..6d4773bdeb1f 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/Pip.java +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/Pip.java @@ -16,15 +16,10 @@ package com.android.wm.shell.pip; -import android.annotation.Nullable; -import android.app.PictureInPictureParams; -import android.content.ComponentName; -import android.content.pm.ActivityInfo; import android.content.res.Configuration; import android.graphics.Rect; import com.android.wm.shell.common.annotations.ExternalThread; -import com.android.wm.shell.pip.phone.PipTouchHandler; import java.io.PrintWriter; import java.util.function.Consumer; @@ -34,6 +29,14 @@ import java.util.function.Consumer; */ @ExternalThread public interface Pip { + + /** + * Returns a binder that can be passed to an external process to manipulate PIP. + */ + default IPip createExternalInterface() { + return null; + } + /** * Expand PIP, it's possible that specific request to activate the window via Alt-tab. */ @@ -109,30 +112,6 @@ public interface Pip { default void showPictureInPictureMenu() {} /** - * Called by Launcher when swiping an auto-pip enabled Activity to home starts - * @param componentName {@link ComponentName} represents the Activity entering PiP - * @param activityInfo {@link ActivityInfo} tied to the Activity - * @param pictureInPictureParams {@link PictureInPictureParams} tied to the Activity - * @param launcherRotation Rotation Launcher is in - * @param shelfHeight Shelf height when landing PiP window onto Launcher - * @return Destination bounds of PiP window based on the parameters passed in - */ - default Rect startSwipePipToHome(ComponentName componentName, ActivityInfo activityInfo, - PictureInPictureParams pictureInPictureParams, - int launcherRotation, int shelfHeight) { - return null; - } - - /** - * Called by Launcher when swiping an auto-pip enable Activity to home finishes - * @param componentName {@link ComponentName} represents the Activity entering PiP - * @param destinationBounds Destination bounds of PiP window - */ - default void stopSwipePipToHome(ComponentName componentName, Rect destinationBounds) { - return; - } - - /** * Called by NavigationBar in order to listen in for PiP bounds change. This is mostly used * for times where the PiP bounds could conflict with SystemUI elements, such as a stashed * PiP and the Back-from-Edge gesture. diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PipController.java b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PipController.java index 9a584c67f97c..501b90ea6828 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PipController.java +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PipController.java @@ -21,8 +21,10 @@ import static android.app.WindowConfiguration.WINDOWING_MODE_PINNED; import static android.content.pm.PackageManager.FEATURE_PICTURE_IN_PICTURE; import static android.view.WindowManager.INPUT_CONSUMER_PIP; +import static com.android.wm.shell.common.ExecutorUtils.executeRemoteCallWithTaskPermission; import static com.android.wm.shell.pip.PipAnimationController.isOutPipDirection; +import android.Manifest; import android.app.ActivityManager; import android.app.ActivityTaskManager; import android.app.PictureInPictureParams; @@ -33,6 +35,7 @@ import android.content.pm.ActivityInfo; import android.content.pm.ParceledListSlice; import android.content.res.Configuration; import android.graphics.Rect; +import android.os.IBinder; import android.os.RemoteException; import android.os.UserHandle; import android.os.UserManager; @@ -44,6 +47,7 @@ import android.view.DisplayInfo; import android.view.WindowManagerGlobal; import android.window.WindowContainerTransaction; +import androidx.annotation.BinderThread; import androidx.annotation.NonNull; import androidx.annotation.Nullable; @@ -51,9 +55,13 @@ import com.android.wm.shell.WindowManagerShellWrapper; import com.android.wm.shell.common.DisplayChangeController; import com.android.wm.shell.common.DisplayController; import com.android.wm.shell.common.DisplayLayout; +import com.android.wm.shell.common.ExecutorUtils; +import com.android.wm.shell.common.RemoteCallable; import com.android.wm.shell.common.ShellExecutor; import com.android.wm.shell.common.TaskStackListenerCallback; import com.android.wm.shell.common.TaskStackListenerImpl; +import com.android.wm.shell.pip.IPip; +import com.android.wm.shell.pip.IPipAnimationListener; import com.android.wm.shell.pip.PinnedStackListenerForwarder; import com.android.wm.shell.pip.Pip; import com.android.wm.shell.pip.PipBoundsAlgorithm; @@ -71,7 +79,8 @@ import java.util.function.Consumer; /** * Manages the picture-in-picture (PIP) UI and states for Phones. */ -public class PipController implements PipTransitionController.PipTransitionCallback { +public class PipController implements PipTransitionController.PipTransitionCallback, + RemoteCallable<PipController> { private static final String TAG = "PipController"; private Context mContext; @@ -85,12 +94,12 @@ public class PipController implements PipTransitionController.PipTransitionCallb private PipBoundsState mPipBoundsState; private PipTouchHandler mTouchHandler; private PipTransitionController mPipTransitionController; - protected final PipImpl mImpl = new PipImpl(); + protected final PipImpl mImpl; private final Rect mTmpInsetBounds = new Rect(); private boolean mIsInFixedRotation; - private Consumer<Boolean> mPinnedStackAnimationRecentsCallback; + private IPipAnimationListener mPinnedStackAnimationRecentsCallback; protected PhonePipMenuController mMenuController; protected PipTaskOrganizer mPipTaskOrganizer; @@ -264,6 +273,7 @@ public class PipController implements PipTransitionController.PipTransitionCallb } mContext = context; + mImpl = new PipImpl(); mWindowManagerShellWrapper = windowManagerShellWrapper; mDisplayController = displayController; mPipBoundsAlgorithm = pipBoundsAlgorithm; @@ -366,6 +376,16 @@ public class PipController implements PipTransitionController.PipTransitionCallb }); } + @Override + public Context getContext() { + return mContext; + } + + @Override + public ShellExecutor getRemoteCallExecutor() { + return mMainExecutor; + } + private void onConfigurationChanged(Configuration newConfig) { mPipBoundsAlgorithm.onConfigurationChanged(mContext); mTouchHandler.onConfigurationChanged(); @@ -474,7 +494,7 @@ public class PipController implements PipTransitionController.PipTransitionCallb mPipTaskOrganizer.setOneShotAnimationType(animationType); } - private void setPinnedStackAnimationListener(Consumer<Boolean> callback) { + private void setPinnedStackAnimationListener(IPipAnimationListener callback) { mPinnedStackAnimationRecentsCallback = callback; } @@ -512,7 +532,11 @@ public class PipController implements PipTransitionController.PipTransitionCallb // Disable touches while the animation is running mTouchHandler.setTouchEnabled(false); if (mPinnedStackAnimationRecentsCallback != null) { - mPinnedStackAnimationRecentsCallback.accept(true); + try { + mPinnedStackAnimationRecentsCallback.onPipAnimationStarted(); + } catch (RemoteException e) { + Log.e(TAG, "Failed to call onPinnedStackAnimationStarted()", e); + } } } @@ -638,7 +662,21 @@ public class PipController implements PipTransitionController.PipTransitionCallb mPipInputConsumer.dump(pw, innerPrefix); } + /** + * The interface for calls from outside the Shell, within the host process. + */ private class PipImpl implements Pip { + private IPipImpl mIPip; + + @Override + public IPip createExternalInterface() { + if (mIPip != null) { + mIPip.invalidate(); + } + mIPip = new IPipImpl(PipController.this); + return mIPip; + } + @Override public void hidePipMenu(Runnable onStartCallback, Runnable onEndCallback) { mMainExecutor.execute(() -> { @@ -696,13 +734,6 @@ public class PipController implements PipTransitionController.PipTransitionCallb } @Override - public void setPinnedStackAnimationListener(Consumer<Boolean> callback) { - mMainExecutor.execute(() -> { - PipController.this.setPinnedStackAnimationListener(callback); - }); - } - - @Override public void setPinnedStackAnimationType(int animationType) { mMainExecutor.execute(() -> { PipController.this.setPinnedStackAnimationType(animationType); @@ -724,37 +755,99 @@ public class PipController implements PipTransitionController.PipTransitionCallb } @Override - public Rect startSwipePipToHome(ComponentName componentName, ActivityInfo activityInfo, - PictureInPictureParams pictureInPictureParams, int launcherRotation, - int shelfHeight) { - Rect[] result = new Rect[1]; + public void dump(PrintWriter pw) { try { mMainExecutor.executeBlocking(() -> { - result[0] = PipController.this.startSwipePipToHome(componentName, activityInfo, - pictureInPictureParams, launcherRotation, shelfHeight); + PipController.this.dump(pw); }); } catch (InterruptedException e) { - Slog.e(TAG, "Failed to start swipe pip to home"); + Slog.e(TAG, "Failed to dump PipController in 2s"); } + } + } + + /** + * The interface for calls from outside the host process. + */ + @BinderThread + private static class IPipImpl extends IPip.Stub { + private PipController mController; + private IPipAnimationListener mListener; + private final IBinder.DeathRecipient mListenerDeathRecipient = + new IBinder.DeathRecipient() { + @Override + @BinderThread + public void binderDied() { + final PipController controller = mController; + controller.getRemoteCallExecutor().execute(() -> { + mListener = null; + controller.setPinnedStackAnimationListener(null); + }); + } + }; + + IPipImpl(PipController controller) { + mController = controller; + } + + /** + * Invalidates this instance, preventing future calls from updating the controller. + */ + void invalidate() { + mController = null; + } + + @Override + public Rect startSwipePipToHome(ComponentName componentName, ActivityInfo activityInfo, + PictureInPictureParams pictureInPictureParams, int launcherRotation, + int shelfHeight) { + Rect[] result = new Rect[1]; + executeRemoteCallWithTaskPermission(mController, "startSwipePipToHome", + (controller) -> { + result[0] = controller.startSwipePipToHome(componentName, activityInfo, + pictureInPictureParams, launcherRotation, shelfHeight); + }, true /* blocking */); return result[0]; } @Override public void stopSwipePipToHome(ComponentName componentName, Rect destinationBounds) { - mMainExecutor.execute(() -> { - PipController.this.stopSwipePipToHome(componentName, destinationBounds); - }); + executeRemoteCallWithTaskPermission(mController, "stopSwipePipToHome", + (controller) -> { + controller.stopSwipePipToHome(componentName, destinationBounds); + }); } @Override - public void dump(PrintWriter pw) { - try { - mMainExecutor.executeBlocking(() -> { - PipController.this.dump(pw); - }); - } catch (InterruptedException e) { - Slog.e(TAG, "Failed to dump PipController in 2s"); - } + public void setShelfHeight(boolean visible, int height) { + executeRemoteCallWithTaskPermission(mController, "setShelfHeight", + (controller) -> { + controller.setShelfHeight(visible, height); + }); + } + + @Override + public void setPinnedStackAnimationListener(IPipAnimationListener listener) { + executeRemoteCallWithTaskPermission(mController, "setPinnedStackAnimationListener", + (controller) -> { + if (mListener != null) { + // Reset the old death recipient + mListener.asBinder().unlinkToDeath(mListenerDeathRecipient, + 0 /* flags */); + } + if (listener != null) { + // Register the death recipient for the new listener to clear the listener + try { + listener.asBinder().linkToDeath(mListenerDeathRecipient, + 0 /* flags */); + } catch (RemoteException e) { + Slog.e(TAG, "Failed to link to death"); + return; + } + } + mListener = listener; + controller.setPinnedStackAnimationListener(listener); + }); } } } diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/ISplitScreen.aidl b/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/ISplitScreen.aidl new file mode 100644 index 000000000000..0c46eaba18ae --- /dev/null +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/ISplitScreen.aidl @@ -0,0 +1,77 @@ +/* + * Copyright (C) 2021 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.wm.shell.splitscreen; + +import android.app.PendingIntent; +import android.content.Intent; +import android.os.Bundle; +import android.os.UserHandle; + +import com.android.wm.shell.splitscreen.ISplitScreenListener; + +/** + * Interface that is exposed to remote callers to manipulate the splitscreen feature. + */ +interface ISplitScreen { + + /** + * Registers a split screen listener. + */ + oneway void registerSplitScreenListener(in ISplitScreenListener listener) = 1; + + /** + * Unregisters a split screen listener. + */ + oneway void unregisterSplitScreenListener(in ISplitScreenListener listener) = 2; + + /** + * Hides the side-stage if it is currently visible. + */ + oneway void setSideStageVisibility(boolean visible) = 3; + + /** + * Removes a task from the side stage. + */ + oneway void removeFromSideStage(int taskId) = 4; + + /** + * Removes the split-screen stages. + */ + oneway void exitSplitScreen() = 5; + + /** + * @param exitSplitScreenOnHide if to exit split-screen if both stages are not visible. + */ + oneway void exitSplitScreenOnHide(boolean exitSplitScreenOnHide) = 6; + + /** + * Starts a task in a stage. + */ + oneway void startTask(int taskId, int stage, int position, in Bundle options) = 7; + + /** + * Starts a shortcut in a stage. + */ + oneway void startShortcut(String packageName, String shortcutId, int stage, int position, + in Bundle options, in UserHandle user) = 8; + + /** + * Starts an activity in a stage. + */ + oneway void startIntent(in PendingIntent intent, in Intent fillInIntent, int stage, + int position, in Bundle options) = 9; +} diff --git a/packages/SystemUI/shared/src/com/android/systemui/shared/recents/ISplitScreenListener.aidl b/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/ISplitScreenListener.aidl index 54242bece2b6..faab4c2009cf 100644 --- a/packages/SystemUI/shared/src/com/android/systemui/shared/recents/ISplitScreenListener.aidl +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/ISplitScreenListener.aidl @@ -14,12 +14,20 @@ * limitations under the License. */ -package com.android.systemui.shared.recents; +package com.android.wm.shell.splitscreen; /** * Listener interface that Launcher attaches to SystemUI to get split-screen callbacks. */ oneway interface ISplitScreenListener { + + /** + * Called when the stage position changes. + */ void onStagePositionChanged(int stage, int position); + + /** + * Called when a task changes stages. + */ void onTaskStageChanged(int taskId, int stage, boolean visible); -} +}
\ No newline at end of file diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/SplitScreen.java b/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/SplitScreen.java index 25a84bd46484..340b55d7f446 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/SplitScreen.java +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/SplitScreen.java @@ -35,7 +35,7 @@ import com.android.wm.shell.draganddrop.DragAndDropPolicy; * TODO: Figure out which of these are actually needed outside of the Shell */ @ExternalThread -public interface SplitScreen extends DragAndDropPolicy.Starter { +public interface SplitScreen { /** * Stage position isn't specified normally meaning to use what ever it is currently set to. */ @@ -89,35 +89,10 @@ public interface SplitScreen extends DragAndDropPolicy.Starter { void onTaskStageChanged(int taskId, @StageType int stage, boolean visible); } - /** @return {@code true} if split-screen is currently visible. */ - boolean isSplitScreenVisible(); - /** Moves a task in the side-stage of split-screen. */ - boolean moveToSideStage(int taskId, @StagePosition int sideStagePosition); - /** Moves a task in the side-stage of split-screen. */ - boolean moveToSideStage(ActivityManager.RunningTaskInfo task, - @StagePosition int sideStagePosition); - /** Removes a task from the side-stage of split-screen. */ - boolean removeFromSideStage(int taskId); - /** Sets the position of the side-stage. */ - void setSideStagePosition(@StagePosition int sideStagePosition); - /** Hides the side-stage if it is currently visible. */ - void setSideStageVisibility(boolean visible); - - /** Removes the split-screen stages. */ - void exitSplitScreen(); - /** @param exitSplitScreenOnHide if to exit split-screen if both stages are not visible. */ - void exitSplitScreenOnHide(boolean exitSplitScreenOnHide); - /** Gets the stage bounds. */ - void getStageBounds(Rect outTopOrLeftBounds, Rect outBottomOrRightBounds); - - void registerSplitScreenListener(SplitScreenListener listener); - void unregisterSplitScreenListener(SplitScreenListener listener); - - void startTask(int taskId, - @StageType int stage, @StagePosition int position, @Nullable Bundle options); - void startShortcut(String packageName, String shortcutId, @StageType int stage, - @StagePosition int position, @Nullable Bundle options, UserHandle user); - void startIntent(PendingIntent intent, Context context, - @Nullable Intent fillInIntent, @StageType int stage, - @StagePosition int position, @Nullable Bundle options); + /** + * Returns a binder that can be passed to an external process to manipulate SplitScreen. + */ + default ISplitScreen createExternalInterface() { + return null; + } } diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/SplitScreenController.java b/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/SplitScreenController.java index bb6f6f259a1e..d4362efe462d 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/SplitScreenController.java +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/SplitScreenController.java @@ -18,6 +18,7 @@ package com.android.wm.shell.splitscreen; import static android.view.Display.DEFAULT_DISPLAY; +import static com.android.wm.shell.common.ExecutorUtils.executeRemoteCallWithTaskPermission; import static com.android.wm.shell.splitscreen.SplitScreen.STAGE_POSITION_BOTTOM_OR_RIGHT; import static com.android.wm.shell.splitscreen.SplitScreen.STAGE_POSITION_TOP_OR_LEFT; import static com.android.wm.shell.splitscreen.SplitScreen.STAGE_POSITION_UNDEFINED; @@ -34,19 +35,24 @@ import android.content.Intent; import android.content.pm.LauncherApps; import android.graphics.Rect; import android.os.Bundle; +import android.os.IBinder; import android.os.RemoteException; import android.os.UserHandle; import android.util.Slog; +import androidx.annotation.BinderThread; import androidx.annotation.NonNull; import androidx.annotation.Nullable; import com.android.wm.shell.RootTaskDisplayAreaOrganizer; import com.android.wm.shell.ShellTaskOrganizer; import com.android.wm.shell.common.DisplayImeController; +import com.android.wm.shell.common.RemoteCallable; import com.android.wm.shell.common.ShellExecutor; import com.android.wm.shell.common.SyncTransactionQueue; +import com.android.wm.shell.common.annotations.ExternalThread; import com.android.wm.shell.draganddrop.DragAndDropPolicy; +import com.android.wm.shell.splitscreen.ISplitScreenListener; import java.io.PrintWriter; @@ -55,7 +61,8 @@ import java.io.PrintWriter; * {@link SplitScreen}. * @see StageCoordinator */ -public class SplitScreenController implements DragAndDropPolicy.Starter { +public class SplitScreenController implements DragAndDropPolicy.Starter, + RemoteCallable<SplitScreenController> { private static final String TAG = SplitScreenController.class.getSimpleName(); private final ShellTaskOrganizer mTaskOrganizer; @@ -84,6 +91,16 @@ public class SplitScreenController implements DragAndDropPolicy.Starter { return mImpl; } + @Override + public Context getContext() { + return mContext; + } + + @Override + public ShellExecutor getRemoteCallExecutor() { + return mMainExecutor; + } + public void onOrganizerRegistered() { if (mStageCoordinator == null) { // TODO: Multi-display @@ -172,13 +189,13 @@ public class SplitScreenController implements DragAndDropPolicy.Starter { } } - public void startIntent(PendingIntent intent, Context context, - Intent fillInIntent, @SplitScreen.StageType int stage, - @SplitScreen.StagePosition int position, @Nullable Bundle options) { + public void startIntent(PendingIntent intent, Intent fillInIntent, + @SplitScreen.StageType int stage, @SplitScreen.StagePosition int position, + @Nullable Bundle options) { options = resolveStartStage(stage, position, options); try { - intent.send(context, 0, fillInIntent, null, null, null, options); + intent.send(mContext, 0, fillInIntent, null, null, null, options); } catch (PendingIntent.CanceledException e) { Slog.e(TAG, "Failed to launch activity", e); } @@ -242,121 +259,170 @@ public class SplitScreenController implements DragAndDropPolicy.Starter { } } + /** + * The interface for calls from outside the Shell, within the host process. + */ + @ExternalThread private class SplitScreenImpl implements SplitScreen { - @Override - public boolean isSplitScreenVisible() { - return mMainExecutor.executeBlockingForResult(() -> { - return SplitScreenController.this.isSplitScreenVisible(); - }, Boolean.class); - } + private ISplitScreenImpl mISplitScreen; @Override - public boolean moveToSideStage(int taskId, int sideStagePosition) { - return mMainExecutor.executeBlockingForResult(() -> { - return SplitScreenController.this.moveToSideStage(taskId, sideStagePosition); - }, Boolean.class); + public ISplitScreen createExternalInterface() { + if (mISplitScreen != null) { + mISplitScreen.invalidate(); + } + mISplitScreen = new ISplitScreenImpl(SplitScreenController.this); + return mISplitScreen; } + } - @Override - public boolean moveToSideStage(ActivityManager.RunningTaskInfo task, - int sideStagePosition) { - return mMainExecutor.executeBlockingForResult(() -> { - return SplitScreenController.this.moveToSideStage(task, sideStagePosition); - }, Boolean.class); - } + /** + * The interface for calls from outside the host process. + */ + @BinderThread + private static class ISplitScreenImpl extends ISplitScreen.Stub { + private SplitScreenController mController; + private ISplitScreenListener mListener; + private final SplitScreen.SplitScreenListener mSplitScreenListener = + new SplitScreen.SplitScreenListener() { + @Override + public void onStagePositionChanged(int stage, int position) { + try { + if (mListener != null) { + mListener.onStagePositionChanged(stage, position); + } + } catch (RemoteException e) { + Slog.e(TAG, "onStagePositionChanged", e); + } + } - @Override - public boolean removeFromSideStage(int taskId) { - return mMainExecutor.executeBlockingForResult(() -> { - return SplitScreenController.this.removeFromSideStage(taskId); - }, Boolean.class); + @Override + public void onTaskStageChanged(int taskId, int stage, boolean visible) { + try { + if (mListener != null) { + mListener.onTaskStageChanged(taskId, stage, visible); + } + } catch (RemoteException e) { + Slog.e(TAG, "onTaskStageChanged", e); + } + } + }; + private final IBinder.DeathRecipient mListenerDeathRecipient = + new IBinder.DeathRecipient() { + @Override + @BinderThread + public void binderDied() { + final SplitScreenController controller = mController; + controller.getRemoteCallExecutor().execute(() -> { + mListener = null; + controller.unregisterSplitScreenListener(mSplitScreenListener); + }); + } + }; + + public ISplitScreenImpl(SplitScreenController controller) { + mController = controller; } - @Override - public void setSideStagePosition(int sideStagePosition) { - mMainExecutor.execute(() -> { - SplitScreenController.this.setSideStagePosition(sideStagePosition); - }); + /** + * Invalidates this instance, preventing future calls from updating the controller. + */ + void invalidate() { + mController = null; } @Override - public void setSideStageVisibility(boolean visible) { - mMainExecutor.execute(() -> { - SplitScreenController.this.setSideStageVisibility(visible); - }); + public void registerSplitScreenListener(ISplitScreenListener listener) { + executeRemoteCallWithTaskPermission(mController, "registerSplitScreenListener", + (controller) -> { + if (mListener != null) { + mListener.asBinder().unlinkToDeath(mListenerDeathRecipient, + 0 /* flags */); + } + if (listener != null) { + try { + listener.asBinder().linkToDeath(mListenerDeathRecipient, + 0 /* flags */); + } catch (RemoteException e) { + Slog.e(TAG, "Failed to link to death"); + return; + } + } + mListener = listener; + controller.registerSplitScreenListener(mSplitScreenListener); + }); } @Override - public void enterSplitScreen(int taskId, boolean leftOrTop) { - mMainExecutor.execute(() -> { - SplitScreenController.this.enterSplitScreen(taskId, leftOrTop); - }); + public void unregisterSplitScreenListener(ISplitScreenListener listener) { + executeRemoteCallWithTaskPermission(mController, "unregisterSplitScreenListener", + (controller) -> { + if (mListener != null) { + mListener.asBinder().unlinkToDeath(mListenerDeathRecipient, + 0 /* flags */); + } + mListener = null; + controller.unregisterSplitScreenListener(mSplitScreenListener); + }); } @Override public void exitSplitScreen() { - mMainExecutor.execute(() -> { - SplitScreenController.this.exitSplitScreen(); - }); + executeRemoteCallWithTaskPermission(mController, "exitSplitScreen", + (controller) -> { + controller.exitSplitScreen(); + }); } @Override public void exitSplitScreenOnHide(boolean exitSplitScreenOnHide) { - mMainExecutor.execute(() -> { - SplitScreenController.this.exitSplitScreenOnHide(exitSplitScreenOnHide); - }); + executeRemoteCallWithTaskPermission(mController, "exitSplitScreenOnHide", + (controller) -> { + controller.exitSplitScreenOnHide(exitSplitScreenOnHide); + }); } @Override - public void getStageBounds(Rect outTopOrLeftBounds, Rect outBottomOrRightBounds) { - try { - mMainExecutor.executeBlocking(() -> { - SplitScreenController.this.getStageBounds(outTopOrLeftBounds, - outBottomOrRightBounds); - }); - } catch (InterruptedException e) { - Slog.e(TAG, "Failed to get stage bounds in 2s"); - } - } - - @Override - public void registerSplitScreenListener(SplitScreenListener listener) { - mMainExecutor.execute(() -> { - SplitScreenController.this.registerSplitScreenListener(listener); - }); + public void setSideStageVisibility(boolean visible) { + executeRemoteCallWithTaskPermission(mController, "setSideStageVisibility", + (controller) -> { + controller.setSideStageVisibility(visible); + }); } @Override - public void unregisterSplitScreenListener(SplitScreenListener listener) { - mMainExecutor.execute(() -> { - SplitScreenController.this.unregisterSplitScreenListener(listener); - }); + public void removeFromSideStage(int taskId) { + executeRemoteCallWithTaskPermission(mController, "removeFromSideStage", + (controller) -> { + controller.removeFromSideStage(taskId); + }); } @Override public void startTask(int taskId, int stage, int position, @Nullable Bundle options) { - mMainExecutor.execute(() -> { - SplitScreenController.this.startTask(taskId, stage, position, options); - }); + executeRemoteCallWithTaskPermission(mController, "startTask", + (controller) -> { + controller.startTask(taskId, stage, position, options); + }); } @Override public void startShortcut(String packageName, String shortcutId, int stage, int position, @Nullable Bundle options, UserHandle user) { - mMainExecutor.execute(() -> { - SplitScreenController.this.startShortcut(packageName, shortcutId, stage, position, - options, user); - }); + executeRemoteCallWithTaskPermission(mController, "startShortcut", + (controller) -> { + controller.startShortcut(packageName, shortcutId, stage, position, + options, user); + }); } @Override - public void startIntent(PendingIntent intent, Context context, Intent fillInIntent, - int stage, int position, @Nullable Bundle options) { - mMainExecutor.execute(() -> { - SplitScreenController.this.startIntent(intent, context, fillInIntent, stage, - position, options); - }); + public void startIntent(PendingIntent intent, Intent fillInIntent, int stage, int position, + @Nullable Bundle options) { + executeRemoteCallWithTaskPermission(mController, "startIntent", + (controller) -> { + controller.startIntent(intent, fillInIntent, stage, position, options); + }); } } - } diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/startingsurface/IStartingWindow.aidl b/libs/WindowManager/Shell/src/com/android/wm/shell/startingsurface/IStartingWindow.aidl new file mode 100644 index 000000000000..546c406ef453 --- /dev/null +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/startingsurface/IStartingWindow.aidl @@ -0,0 +1,29 @@ +/* + * Copyright (C) 2021 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.wm.shell.startingsurface; + +import com.android.wm.shell.startingsurface.IStartingWindowListener; + +/** + * Interface that is exposed to remote callers to manipulate starting windows. + */ +interface IStartingWindow { + /** + * Sets listener to get task launching callbacks. + */ + oneway void setStartingWindowListener(IStartingWindowListener listener) = 43; +} diff --git a/packages/SystemUI/shared/src/com/android/systemui/shared/recents/IStartingWindowListener.aidl b/libs/WindowManager/Shell/src/com/android/wm/shell/startingsurface/IStartingWindowListener.aidl index eb3e60cec5c5..f562c8fc4f85 100644 --- a/packages/SystemUI/shared/src/com/android/systemui/shared/recents/IStartingWindowListener.aidl +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/startingsurface/IStartingWindowListener.aidl @@ -1,5 +1,5 @@ /* - * Copyright (C) 2020 The Android Open Source Project + * Copyright (C) 2021 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -14,7 +14,7 @@ * limitations under the License. */ -package com.android.systemui.shared.recents; +package com.android.wm.shell.startingsurface; /** * Listener interface that Launcher attaches to SystemUI to get diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/startingsurface/StartingSurface.java b/libs/WindowManager/Shell/src/com/android/wm/shell/startingsurface/StartingSurface.java index f258286f2d17..079d68973852 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/startingsurface/StartingSurface.java +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/startingsurface/StartingSurface.java @@ -16,35 +16,15 @@ package com.android.wm.shell.startingsurface; -import android.graphics.Rect; -import android.os.IBinder; -import android.view.SurfaceControl; -import android.window.StartingWindowInfo; - -import java.util.function.BiConsumer; /** * Interface to engage starting window feature. */ public interface StartingSurface { - /** - * Called when a task need a starting window. - */ - void addStartingWindow(StartingWindowInfo windowInfo, IBinder appToken); - /** - * Called when the content of a task is ready to show, starting window can be removed. - */ - void removeStartingWindow(int taskId, SurfaceControl leash, Rect frame, - boolean playRevealAnimation); - /** - * Called when the Task wants to copy the splash screen. - * @param taskId - */ - void copySplashScreenView(int taskId); /** - * Registers the starting window listener. - * - * @param listener The callback when need a starting window. + * Returns a binder that can be passed to an external process to manipulate starting windows. */ - void setStartingWindowListener(BiConsumer<Integer, Integer> listener); + default IStartingWindow createExternalInterface() { + return null; + } } diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/startingsurface/StartingWindowController.java b/libs/WindowManager/Shell/src/com/android/wm/shell/startingsurface/StartingWindowController.java index a694e525a761..b6ca86989690 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/startingsurface/StartingWindowController.java +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/startingsurface/StartingWindowController.java @@ -25,6 +25,8 @@ import static android.window.StartingWindowInfo.TYPE_PARAMETER_NEW_TASK; import static android.window.StartingWindowInfo.TYPE_PARAMETER_PROCESS_RUNNING; import static android.window.StartingWindowInfo.TYPE_PARAMETER_TASK_SWITCH; +import static com.android.wm.shell.common.ExecutorUtils.executeRemoteCallWithTaskPermission; + import android.app.ActivityManager.RunningTaskInfo; import android.app.ActivityTaskManager; import android.content.Context; @@ -37,6 +39,9 @@ import android.window.StartingWindowInfo; import android.window.TaskOrganizer; import android.window.TaskSnapshot; +import androidx.annotation.BinderThread; + +import com.android.wm.shell.common.RemoteCallable; import com.android.wm.shell.common.ShellExecutor; import com.android.wm.shell.common.TransactionPool; @@ -58,7 +63,7 @@ import java.util.function.BiConsumer; * constructor to keep everything synchronized. * @hide */ -public class StartingWindowController { +public class StartingWindowController implements RemoteCallable<StartingWindowController> { private static final String TAG = StartingWindowController.class.getSimpleName(); static final boolean DEBUG_SPLASH_SCREEN = false; static final boolean DEBUG_TASK_SNAPSHOT = false; @@ -68,17 +73,17 @@ public class StartingWindowController { private BiConsumer<Integer, Integer> mTaskLaunchingCallback; private final StartingSurfaceImpl mImpl = new StartingSurfaceImpl(); + private final Context mContext; private final ShellExecutor mSplashScreenExecutor; // For Car Launcher public StartingWindowController(Context context, ShellExecutor splashScreenExecutor) { - mStartingSurfaceDrawer = new StartingSurfaceDrawer(context, splashScreenExecutor, - new TransactionPool()); - mSplashScreenExecutor = splashScreenExecutor; + this(context, splashScreenExecutor, new TransactionPool()); } public StartingWindowController(Context context, ShellExecutor splashScreenExecutor, TransactionPool pool) { + mContext = context; mStartingSurfaceDrawer = new StartingSurfaceDrawer(context, splashScreenExecutor, pool); mSplashScreenExecutor = splashScreenExecutor; } @@ -90,6 +95,16 @@ public class StartingWindowController { return mImpl; } + @Override + public Context getContext() { + return mContext; + } + + @Override + public ShellExecutor getRemoteCallExecutor() { + return mSplashScreenExecutor; + } + private static class StartingTypeChecker { TaskSnapshot mSnapshot; @@ -188,59 +203,121 @@ public class StartingWindowController { /** * Called when a task need a starting window. */ - void addStartingWindow(StartingWindowInfo windowInfo, IBinder appToken) { - final int suggestionType = mStartingTypeChecker.estimateStartingWindowType(windowInfo); - final RunningTaskInfo runningTaskInfo = windowInfo.taskInfo; - if (mTaskLaunchingCallback != null) { - mTaskLaunchingCallback.accept(runningTaskInfo.taskId, suggestionType); - } - if (suggestionType == STARTING_WINDOW_TYPE_SPLASH_SCREEN) { - mStartingSurfaceDrawer.addSplashScreenStartingWindow(windowInfo, appToken); - } else if (suggestionType == STARTING_WINDOW_TYPE_SNAPSHOT) { - final TaskSnapshot snapshot = mStartingTypeChecker.mSnapshot; - mStartingSurfaceDrawer.makeTaskSnapshotWindow(windowInfo, appToken, snapshot); - } - // If prefer don't show, then don't show! + public void addStartingWindow(StartingWindowInfo windowInfo, IBinder appToken) { + mSplashScreenExecutor.execute(() -> { + final int suggestionType = mStartingTypeChecker.estimateStartingWindowType(windowInfo); + final RunningTaskInfo runningTaskInfo = windowInfo.taskInfo; + if (mTaskLaunchingCallback != null) { + mTaskLaunchingCallback.accept(runningTaskInfo.taskId, suggestionType); + } + if (suggestionType == STARTING_WINDOW_TYPE_SPLASH_SCREEN) { + mStartingSurfaceDrawer.addSplashScreenStartingWindow(windowInfo, appToken); + } else if (suggestionType == STARTING_WINDOW_TYPE_SNAPSHOT) { + final TaskSnapshot snapshot = mStartingTypeChecker.mSnapshot; + mStartingSurfaceDrawer.makeTaskSnapshotWindow(windowInfo, appToken, snapshot); + } + // If prefer don't show, then don't show! + }); } - void copySplashScreenView(int taskId) { - mStartingSurfaceDrawer.copySplashScreenView(taskId); + public void copySplashScreenView(int taskId) { + mSplashScreenExecutor.execute(() -> { + mStartingSurfaceDrawer.copySplashScreenView(taskId); + }); } /** * Called when the content of a task is ready to show, starting window can be removed. */ - void removeStartingWindow(int taskId, SurfaceControl leash, Rect frame, + public void removeStartingWindow(int taskId, SurfaceControl leash, Rect frame, boolean playRevealAnimation) { - mStartingSurfaceDrawer.removeStartingWindow(taskId, leash, frame, playRevealAnimation); + mSplashScreenExecutor.execute(() -> { + mStartingSurfaceDrawer.removeStartingWindow(taskId, leash, frame, playRevealAnimation); + }); } + /** + * The interface for calls from outside the Shell, within the host process. + */ private class StartingSurfaceImpl implements StartingSurface { + private IStartingWindowImpl mIStartingWindow; @Override - public void addStartingWindow(StartingWindowInfo windowInfo, IBinder appToken) { - mSplashScreenExecutor.execute(() -> - StartingWindowController.this.addStartingWindow(windowInfo, appToken)); + public IStartingWindowImpl createExternalInterface() { + if (mIStartingWindow != null) { + mIStartingWindow.invalidate(); + } + mIStartingWindow = new IStartingWindowImpl(StartingWindowController.this); + return mIStartingWindow; } + } - @Override - public void removeStartingWindow(int taskId, SurfaceControl leash, Rect frame, - boolean playRevealAnimation) { - mSplashScreenExecutor.execute(() -> - StartingWindowController.this.removeStartingWindow(taskId, leash, frame, - playRevealAnimation)); + /** + * The interface for calls from outside the host process. + */ + @BinderThread + private static class IStartingWindowImpl extends IStartingWindow.Stub { + private StartingWindowController mController; + private IStartingWindowListener mListener; + private final BiConsumer<Integer, Integer> mStartingWindowListener = + this::notifyIStartingWindowListener; + private final IBinder.DeathRecipient mListenerDeathRecipient = + new IBinder.DeathRecipient() { + @Override + @BinderThread + public void binderDied() { + final StartingWindowController controller = mController; + controller.getRemoteCallExecutor().execute(() -> { + mListener = null; + controller.setStartingWindowListener(null); + }); + } + }; + + public IStartingWindowImpl(StartingWindowController controller) { + mController = controller; } - @Override - public void copySplashScreenView(int taskId) { - mSplashScreenExecutor.execute(() -> - StartingWindowController.this.copySplashScreenView(taskId)); + /** + * Invalidates this instance, preventing future calls from updating the controller. + */ + void invalidate() { + mController = null; } @Override - public void setStartingWindowListener(BiConsumer<Integer, Integer> listener) { - mSplashScreenExecutor.execute(() -> - StartingWindowController.this.setStartingWindowListener(listener)); + public void setStartingWindowListener(IStartingWindowListener listener) { + executeRemoteCallWithTaskPermission(mController, "setStartingWindowListener", + (controller) -> { + if (mListener != null) { + // Reset the old death recipient + mListener.asBinder().unlinkToDeath(mListenerDeathRecipient, + 0 /* flags */); + } + if (listener != null) { + try { + listener.asBinder().linkToDeath(mListenerDeathRecipient, + 0 /* flags */); + } catch (RemoteException e) { + Slog.e(TAG, "Failed to link to death"); + return; + } + } + mListener = listener; + controller.setStartingWindowListener(mStartingWindowListener); + }); + } + + private void notifyIStartingWindowListener(int taskId, int supportedType) { + if (mListener == null) { + return; + } + + try { + mListener.onTaskLaunching(taskId, supportedType); + } catch (RemoteException e) { + Slog.e(TAG, "Failed to notify task launching", e); + } } } } diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/transition/IShellTransitions.aidl b/libs/WindowManager/Shell/src/com/android/wm/shell/transition/IShellTransitions.aidl new file mode 100644 index 000000000000..dffc700a3690 --- /dev/null +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/transition/IShellTransitions.aidl @@ -0,0 +1,37 @@ +/* + * Copyright (C) 2021 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.wm.shell.transition; + +import android.window.IRemoteTransition; +import android.window.TransitionFilter; + +/** + * Interface that is exposed to remote callers to manipulate the transitions feature. + */ +interface IShellTransitions { + + /** + * Registers a remote transition handler. + */ + oneway void registerRemote(in TransitionFilter filter, + in IRemoteTransition remoteTransition) = 1; + + /** + * Unregisters a remote transition handler. + */ + oneway void unregisterRemote(in IRemoteTransition remoteTransition) = 2; +} diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/transition/RemoteTransitionHandler.java b/libs/WindowManager/Shell/src/com/android/wm/shell/transition/RemoteTransitionHandler.java index ac93a17b4014..9667f4b6a8c5 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/transition/RemoteTransitionHandler.java +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/transition/RemoteTransitionHandler.java @@ -16,6 +16,8 @@ package com.android.wm.shell.transition; +import static com.android.wm.shell.common.ExecutorUtils.executeRemoteCallWithTaskPermission; + import android.annotation.NonNull; import android.annotation.Nullable; import android.os.IBinder; @@ -23,6 +25,7 @@ import android.os.RemoteException; import android.util.ArrayMap; import android.util.Log; import android.util.Pair; +import android.util.Slog; import android.view.SurfaceControl; import android.window.IRemoteTransition; import android.window.IRemoteTransitionFinishedCallback; @@ -31,6 +34,8 @@ import android.window.TransitionInfo; import android.window.TransitionRequestInfo; import android.window.WindowContainerTransaction; +import androidx.annotation.BinderThread; + import com.android.internal.protolog.common.ProtoLog; import com.android.wm.shell.common.ShellExecutor; import com.android.wm.shell.protolog.ShellProtoLogGroup; @@ -42,6 +47,8 @@ import java.util.ArrayList; * if the request includes a specific remote. */ public class RemoteTransitionHandler implements Transitions.TransitionHandler { + private static final String TAG = "RemoteTransitionHandler"; + private final ShellExecutor mMainExecutor; /** Includes remotes explicitly requested by, eg, ActivityOptions */ @@ -51,15 +58,33 @@ public class RemoteTransitionHandler implements Transitions.TransitionHandler { private final ArrayList<Pair<TransitionFilter, IRemoteTransition>> mFilters = new ArrayList<>(); + private final IBinder.DeathRecipient mTransitionDeathRecipient = + new IBinder.DeathRecipient() { + @Override + @BinderThread + public void binderDied() { + mMainExecutor.execute(() -> { + mFilters.clear(); + }); + } + }; + RemoteTransitionHandler(@NonNull ShellExecutor mainExecutor) { mMainExecutor = mainExecutor; } void addFiltered(TransitionFilter filter, IRemoteTransition remote) { + try { + remote.asBinder().linkToDeath(mTransitionDeathRecipient, 0 /* flags */); + } catch (RemoteException e) { + Slog.e(TAG, "Failed to link to death"); + return; + } mFilters.add(new Pair<>(filter, remote)); } void removeFiltered(IRemoteTransition remote) { + remote.asBinder().unlinkToDeath(mTransitionDeathRecipient, 0 /* flags */); for (int i = mFilters.size() - 1; i >= 0; --i) { if (mFilters.get(i).second == remote) { mFilters.remove(i); diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/transition/RemoteTransitions.java b/libs/WindowManager/Shell/src/com/android/wm/shell/transition/ShellTransitions.java index 85bbf74d56b9..bc42c6e2f12c 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/transition/RemoteTransitions.java +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/transition/ShellTransitions.java @@ -26,7 +26,15 @@ import com.android.wm.shell.common.annotations.ExternalThread; * Interface to manage remote transitions. */ @ExternalThread -public interface RemoteTransitions { +public interface ShellTransitions { + + /** + * Returns a binder that can be passed to an external process to manipulate remote transitions. + */ + default IShellTransitions createExternalInterface() { + return null; + } + /** * Registers a remote transition. */ diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/transition/Transitions.java b/libs/WindowManager/Shell/src/com/android/wm/shell/transition/Transitions.java index 677db10d07a7..ca1b53d4d46b 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/transition/Transitions.java +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/transition/Transitions.java @@ -23,6 +23,8 @@ import static android.view.WindowManager.TRANSIT_TO_BACK; import static android.view.WindowManager.TRANSIT_TO_FRONT; import static android.window.TransitionInfo.FLAG_STARTING_WINDOW_TRANSFER_RECIPIENT; +import static com.android.wm.shell.common.ExecutorUtils.executeRemoteCallWithTaskPermission; + import android.annotation.NonNull; import android.annotation.Nullable; import android.content.ContentResolver; @@ -51,6 +53,7 @@ import com.android.internal.R; import com.android.internal.annotations.VisibleForTesting; import com.android.internal.protolog.common.ProtoLog; import com.android.wm.shell.ShellTaskOrganizer; +import com.android.wm.shell.common.RemoteCallable; import com.android.wm.shell.common.ShellExecutor; import com.android.wm.shell.common.TransactionPool; import com.android.wm.shell.common.annotations.ExternalThread; @@ -60,7 +63,7 @@ import java.util.ArrayList; import java.util.Arrays; /** Plays transition animations */ -public class Transitions { +public class Transitions implements RemoteCallable<Transitions> { static final String TAG = "ShellTransitions"; /** Set to {@code true} to enable shell transitions. */ @@ -73,7 +76,7 @@ public class Transitions { private final ShellExecutor mAnimExecutor; private final TransitionPlayerImpl mPlayerImpl; private final RemoteTransitionHandler mRemoteTransitionHandler; - private final RemoteTransitionImpl mImpl = new RemoteTransitionImpl(); + private final ShellTransitionImpl mImpl = new ShellTransitionImpl(); /** List of possible handlers. Ordered by specificity (eg. tapped back to front). */ private final ArrayList<TransitionHandler> mHandlers = new ArrayList<>(); @@ -87,10 +90,6 @@ public class Transitions { /** Keeps track of currently tracked transitions and all the animations associated with each */ private final ArrayMap<IBinder, ActiveTransition> mActiveTransitions = new ArrayMap<>(); - public static RemoteTransitions asRemoteTransitions(Transitions transitions) { - return transitions.mImpl; - } - public Transitions(@NonNull WindowOrganizer organizer, @NonNull TransactionPool pool, @NonNull Context context, @NonNull ShellExecutor mainExecutor, @NonNull ShellExecutor animExecutor) { @@ -126,6 +125,20 @@ public class Transitions { mRemoteTransitionHandler = null; } + public ShellTransitions asRemoteTransitions() { + return mImpl; + } + + @Override + public Context getContext() { + return mContext; + } + + @Override + public ShellExecutor getRemoteCallExecutor() { + return mMainExecutor; + } + private void dispatchAnimScaleSetting(float scale) { for (int i = mHandlers.size() - 1; i >= 0; --i) { mHandlers.get(i).setAnimScaleSetting(scale); @@ -134,8 +147,8 @@ public class Transitions { /** Create an empty/non-registering transitions object for system-ui tests. */ @VisibleForTesting - public static RemoteTransitions createEmptyForTesting() { - return new RemoteTransitions() { + public static ShellTransitions createEmptyForTesting() { + return new ShellTransitions() { @Override public void registerRemote(@androidx.annotation.NonNull TransitionFilter filter, @androidx.annotation.NonNull IRemoteTransition remoteTransition) { @@ -426,24 +439,74 @@ public class Transitions { } } + /** + * The interface for calls from outside the Shell, within the host process. + */ @ExternalThread - private class RemoteTransitionImpl implements RemoteTransitions { + private class ShellTransitionImpl implements ShellTransitions { + private IShellTransitionsImpl mIShellTransitions; + + @Override + public IShellTransitions createExternalInterface() { + if (mIShellTransitions != null) { + mIShellTransitions.invalidate(); + } + mIShellTransitions = new IShellTransitionsImpl(Transitions.this); + return mIShellTransitions; + } + @Override public void registerRemote(@NonNull TransitionFilter filter, @NonNull IRemoteTransition remoteTransition) { mMainExecutor.execute(() -> { - Transitions.this.registerRemote(filter, remoteTransition); + mRemoteTransitionHandler.addFiltered(filter, remoteTransition); }); } @Override public void unregisterRemote(@NonNull IRemoteTransition remoteTransition) { mMainExecutor.execute(() -> { - Transitions.this.unregisterRemote(remoteTransition); + mRemoteTransitionHandler.removeFiltered(remoteTransition); }); } } + /** + * The interface for calls from outside the host process. + */ + @BinderThread + private static class IShellTransitionsImpl extends IShellTransitions.Stub { + private Transitions mTransitions; + + IShellTransitionsImpl(Transitions transitions) { + mTransitions = transitions; + } + + /** + * Invalidates this instance, preventing future calls from updating the controller. + */ + void invalidate() { + mTransitions = null; + } + + @Override + public void registerRemote(@NonNull TransitionFilter filter, + @NonNull IRemoteTransition remoteTransition) { + executeRemoteCallWithTaskPermission(mTransitions, "registerRemote", + (transitions) -> { + transitions.mRemoteTransitionHandler.addFiltered(filter, remoteTransition); + }); + } + + @Override + public void unregisterRemote(@NonNull IRemoteTransition remoteTransition) { + executeRemoteCallWithTaskPermission(mTransitions, "unregisterRemote", + (transitions) -> { + transitions.mRemoteTransitionHandler.removeFiltered(remoteTransition); + }); + } + } + private class SettingsObserver extends ContentObserver { SettingsObserver() { diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/draganddrop/DragAndDropPolicyTest.java b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/draganddrop/DragAndDropPolicyTest.java index c1c4c6dd08d7..2f2bbba11646 100644 --- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/draganddrop/DragAndDropPolicyTest.java +++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/draganddrop/DragAndDropPolicyTest.java @@ -205,7 +205,7 @@ public class DragAndDropPolicyTest { mPolicy.getTargets(mInsets), TYPE_FULLSCREEN); mPolicy.handleDrop(filterTargetByType(targets, TYPE_FULLSCREEN), mActivityClipData); - verify(mSplitScreenStarter).startIntent(any(), any(), any(), + verify(mSplitScreenStarter).startIntent(any(), any(), eq(STAGE_TYPE_UNDEFINED), eq(STAGE_POSITION_UNDEFINED), any()); } @@ -217,12 +217,12 @@ public class DragAndDropPolicyTest { mPolicy.getTargets(mInsets), TYPE_FULLSCREEN, TYPE_SPLIT_LEFT, TYPE_SPLIT_RIGHT); mPolicy.handleDrop(filterTargetByType(targets, TYPE_FULLSCREEN), mActivityClipData); - verify(mSplitScreenStarter).startIntent(any(), any(), any(), + verify(mSplitScreenStarter).startIntent(any(), any(), eq(STAGE_TYPE_UNDEFINED), eq(STAGE_POSITION_UNDEFINED), any()); reset(mSplitScreenStarter); mPolicy.handleDrop(filterTargetByType(targets, TYPE_SPLIT_RIGHT), mActivityClipData); - verify(mSplitScreenStarter).startIntent(any(), any(), any(), + verify(mSplitScreenStarter).startIntent(any(), any(), eq(STAGE_TYPE_SIDE), eq(STAGE_POSITION_BOTTOM_OR_RIGHT), any()); } @@ -234,12 +234,12 @@ public class DragAndDropPolicyTest { mPolicy.getTargets(mInsets), TYPE_FULLSCREEN, TYPE_SPLIT_TOP, TYPE_SPLIT_BOTTOM); mPolicy.handleDrop(filterTargetByType(targets, TYPE_FULLSCREEN), mActivityClipData); - verify(mSplitScreenStarter).startIntent(any(), any(), any(), + verify(mSplitScreenStarter).startIntent(any(), any(), eq(STAGE_TYPE_UNDEFINED), eq(STAGE_POSITION_UNDEFINED), any()); reset(mSplitScreenStarter); mPolicy.handleDrop(filterTargetByType(targets, TYPE_SPLIT_BOTTOM), mActivityClipData); - verify(mSplitScreenStarter).startIntent(any(), any(), any(), + verify(mSplitScreenStarter).startIntent(any(), any(), eq(STAGE_TYPE_SIDE), eq(STAGE_POSITION_BOTTOM_OR_RIGHT), any()); } @@ -251,7 +251,7 @@ public class DragAndDropPolicyTest { mPolicy.getTargets(mInsets), TYPE_FULLSCREEN, TYPE_SPLIT_LEFT, TYPE_SPLIT_RIGHT); mPolicy.handleDrop(filterTargetByType(targets, TYPE_FULLSCREEN), mActivityClipData); - verify(mSplitScreenStarter).startIntent(any(), any(), any(), + verify(mSplitScreenStarter).startIntent(any(), any(), eq(STAGE_TYPE_UNDEFINED), eq(STAGE_POSITION_UNDEFINED), any()); } @@ -263,7 +263,7 @@ public class DragAndDropPolicyTest { mPolicy.getTargets(mInsets), TYPE_FULLSCREEN, TYPE_SPLIT_LEFT, TYPE_SPLIT_RIGHT); mPolicy.handleDrop(filterTargetByType(targets, TYPE_FULLSCREEN), mActivityClipData); - verify(mSplitScreenStarter).startIntent(any(), any(), any(), + verify(mSplitScreenStarter).startIntent(any(), any(), eq(STAGE_TYPE_UNDEFINED), eq(STAGE_POSITION_UNDEFINED), any()); } @@ -276,13 +276,13 @@ public class DragAndDropPolicyTest { mPolicy.getTargets(mInsets), TYPE_FULLSCREEN, TYPE_SPLIT_LEFT, TYPE_SPLIT_RIGHT); mPolicy.handleDrop(filterTargetByType(targets, TYPE_FULLSCREEN), mActivityClipData); - verify(mSplitScreenStarter).startIntent(any(), any(), any(), + verify(mSplitScreenStarter).startIntent(any(), any(), eq(STAGE_TYPE_UNDEFINED), eq(STAGE_POSITION_UNDEFINED), any()); reset(mSplitScreenStarter); // TODO(b/169894807): Just verify starting for the non-docked task until we have app pairs mPolicy.handleDrop(filterTargetByType(targets, TYPE_SPLIT_RIGHT), mActivityClipData); - verify(mSplitScreenStarter).startIntent(any(), any(), any(), + verify(mSplitScreenStarter).startIntent(any(), any(), eq(STAGE_TYPE_SIDE), eq(STAGE_POSITION_BOTTOM_OR_RIGHT), any()); } @@ -295,13 +295,13 @@ public class DragAndDropPolicyTest { mPolicy.getTargets(mInsets), TYPE_FULLSCREEN, TYPE_SPLIT_TOP, TYPE_SPLIT_BOTTOM); mPolicy.handleDrop(filterTargetByType(targets, TYPE_FULLSCREEN), mActivityClipData); - verify(mSplitScreenStarter).startIntent(any(), any(), any(), + verify(mSplitScreenStarter).startIntent(any(), any(), eq(STAGE_TYPE_UNDEFINED), eq(STAGE_POSITION_UNDEFINED), any()); reset(mSplitScreenStarter); // TODO(b/169894807): Just verify starting for the non-docked task until we have app pairs mPolicy.handleDrop(filterTargetByType(targets, TYPE_SPLIT_BOTTOM), mActivityClipData); - verify(mSplitScreenStarter).startIntent(any(), any(), any(), + verify(mSplitScreenStarter).startIntent(any(), any(), eq(STAGE_TYPE_SIDE), eq(STAGE_POSITION_BOTTOM_OR_RIGHT), any()); } diff --git a/libs/androidfw/AssetManager2.cpp b/libs/androidfw/AssetManager2.cpp index c0ef7be8b673..7e45f952d389 100644 --- a/libs/androidfw/AssetManager2.cpp +++ b/libs/androidfw/AssetManager2.cpp @@ -226,8 +226,6 @@ void AssetManager2::BuildDynamicRefTable() { } void AssetManager2::DumpToLog() const { - base::ScopedLogSeverity _log(base::INFO); - LOG(INFO) << base::StringPrintf("AssetManager2(this=%p)", this); std::string list; @@ -1721,7 +1719,6 @@ base::expected<std::monostate, IOError> Theme::SetTo(const Theme& o) { } void Theme::Dump() const { - base::ScopedLogSeverity _log(base::INFO); LOG(INFO) << base::StringPrintf("Theme(this=%p, AssetManager2=%p)", this, asset_manager_); for (int p = 0; p < packages_.size(); p++) { diff --git a/media/jni/soundpool/Sound.cpp b/media/jni/soundpool/Sound.cpp index f8b4bdb1f4d5..50e0d336f981 100644 --- a/media/jni/soundpool/Sound.cpp +++ b/media/jni/soundpool/Sound.cpp @@ -99,8 +99,8 @@ static status_t decode(int fd, int64_t offset, int64_t length, __func__); break; } - int sampleSize = AMediaExtractor_readSampleData(ex.get(), buf, bufsize); - ALOGV("%s: read %d", __func__, sampleSize); + ssize_t sampleSize = AMediaExtractor_readSampleData(ex.get(), buf, bufsize); + ALOGV("%s: read %zd", __func__, sampleSize); if (sampleSize < 0) { sampleSize = 0; sawInputEOS = true; @@ -124,8 +124,8 @@ static status_t decode(int fd, int64_t offset, int64_t length, } AMediaCodecBufferInfo info; - const int status = AMediaCodec_dequeueOutputBuffer(codec.get(), &info, 1); - ALOGV("%s: dequeueoutput returned: %d", __func__, status); + const ssize_t status = AMediaCodec_dequeueOutputBuffer(codec.get(), &info, 1); + ALOGV("%s: dequeueoutput returned: %zd", __func__, status); if (status >= 0) { if (info.flags & AMEDIACODEC_BUFFER_FLAG_END_OF_STREAM) { ALOGV("%s: output EOS", __func__); @@ -167,10 +167,10 @@ static status_t decode(int fd, int64_t offset, int64_t length, } else if (status == AMEDIACODEC_INFO_TRY_AGAIN_LATER) { ALOGV("%s: no output buffer right now", __func__); } else if (status <= AMEDIA_ERROR_BASE) { - ALOGE("%s: decode error: %d", __func__, status); + ALOGE("%s: decode error: %zd", __func__, status); break; } else { - ALOGV("%s: unexpected info code: %d", __func__, status); + ALOGV("%s: unexpected info code: %zd", __func__, status); } } diff --git a/media/jni/soundpool/Stream.cpp b/media/jni/soundpool/Stream.cpp index abb0f1208bc2..95fe000bd2c2 100644 --- a/media/jni/soundpool/Stream.cpp +++ b/media/jni/soundpool/Stream.cpp @@ -320,7 +320,8 @@ void Stream::play_l(const std::shared_ptr<Sound>& sound, int32_t nextStreamID, // audio track while the new one is being started and avoids processing them with // wrong audio audio buffer size (mAudioBufferSize) auto toggle = mToggle ^ 1; - void* userData = (void*)((uintptr_t)this | toggle); + // NOLINTNEXTLINE(performance-no-int-to-ptr) + void* userData = reinterpret_cast<void*>((uintptr_t)this | toggle); audio_channel_mask_t soundChannelMask = sound->getChannelMask(); // When sound contains a valid channel mask, use it as is. // Otherwise, use stream count to calculate channel mask. @@ -391,6 +392,7 @@ exit: void Stream::staticCallback(int event, void* user, void* info) { const auto userAsInt = (uintptr_t)user; + // NOLINTNEXTLINE(performance-no-int-to-ptr) auto stream = reinterpret_cast<Stream*>(userAsInt & ~1); stream->callback(event, info, int(userAsInt & 1), 0 /* tries */); } diff --git a/media/jni/soundpool/StreamManager.cpp b/media/jni/soundpool/StreamManager.cpp index 502ee00b583e..8b84bf3eb8d8 100644 --- a/media/jni/soundpool/StreamManager.cpp +++ b/media/jni/soundpool/StreamManager.cpp @@ -330,7 +330,7 @@ ssize_t StreamManager::removeFromQueues_l( // streams on mProcessingStreams are undergoing processing by the StreamManager thread // and do not participate in normal stream migration. - return found; + return (ssize_t)found; } void StreamManager::addToRestartQueue_l(Stream *stream) { diff --git a/media/jni/soundpool/android_media_SoundPool.cpp b/media/jni/soundpool/android_media_SoundPool.cpp index 357cc63bd41e..a66d99fbd9f4 100644 --- a/media/jni/soundpool/android_media_SoundPool.cpp +++ b/media/jni/soundpool/android_media_SoundPool.cpp @@ -34,7 +34,8 @@ static struct fields_t { jclass mSoundPoolClass; } fields; static inline SoundPool* MusterSoundPool(JNIEnv *env, jobject thiz) { - return (SoundPool*)env->GetLongField(thiz, fields.mNativeContext); + // NOLINTNEXTLINE(performance-no-int-to-ptr) + return reinterpret_cast<SoundPool*>(env->GetLongField(thiz, fields.mNativeContext)); } static const char* const kAudioAttributesClassPathName = "android/media/AudioAttributes"; struct audio_attributes_fields_t { diff --git a/packages/SystemUI/shared/Android.bp b/packages/SystemUI/shared/Android.bp index 09e9675a3277..f98a959346d3 100644 --- a/packages/SystemUI/shared/Android.bp +++ b/packages/SystemUI/shared/Android.bp @@ -41,6 +41,7 @@ android_library { srcs: [ "src/**/*.java", "src/**/I*.aidl", + ":wm_shell-aidls", ], static_libs: [ diff --git a/packages/SystemUI/shared/src/com/android/systemui/shared/recents/ISystemUiProxy.aidl b/packages/SystemUI/shared/src/com/android/systemui/shared/recents/ISystemUiProxy.aidl index 49e86f55bb9e..2103de2ae85c 100644 --- a/packages/SystemUI/shared/src/com/android/systemui/shared/recents/ISystemUiProxy.aidl +++ b/packages/SystemUI/shared/src/com/android/systemui/shared/recents/ISystemUiProxy.aidl @@ -16,11 +16,6 @@ package com.android.systemui.shared.recents; -import android.app.PendingIntent; -import android.app.PictureInPictureParams; -import android.content.ComponentName; -import android.content.Intent; -import android.content.pm.ActivityInfo; import android.graphics.Bitmap; import android.graphics.Insets; import android.graphics.Rect; @@ -28,26 +23,15 @@ import android.os.Bundle; import android.os.UserHandle; import android.view.MotionEvent; -import com.android.systemui.shared.recents.IPinnedStackAnimationListener; -import com.android.systemui.shared.recents.ISplitScreenListener; -import com.android.systemui.shared.recents.IStartingWindowListener; import com.android.systemui.shared.recents.model.Task; import com.android.systemui.shared.system.RemoteTransitionCompat; /** * Temporary callbacks into SystemUI. - * Next id = 44 */ interface ISystemUiProxy { /** - * Proxies SurfaceControl.screenshotToBuffer(). - * @Removed - * GraphicBufferCompat screenshot(in Rect sourceCrop, int width, int height, int minLayer, - * int maxLayer, boolean useIdentityTransform, int rotation) = 0; - */ - - /** * Begins screen pinning on the provided {@param taskId}. */ void startScreenPinning(int taskId) = 1; @@ -121,11 +105,6 @@ interface ISystemUiProxy { void stopScreenPinning() = 17; /** - * Sets the shelf height and visibility. - */ - void setShelfHeight(boolean visible, int shelfHeight) = 20; - - /** * Handle the provided image as if it was a screenshot. * * Deprecated, use handleImageBundleAsScreenshot with image bundle and UserTask @@ -145,27 +124,12 @@ interface ISystemUiProxy { void notifySwipeToHomeFinished() = 23; /** - * Sets listener to get pinned stack animation callbacks. - */ - void setPinnedStackAnimationListener(IPinnedStackAnimationListener listener) = 24; - - /** * Notifies that quickstep will switch to a new task * @param rotation indicates which Surface.Rotation the gesture was started in */ void onQuickSwitchToNewTask(int rotation) = 25; /** - * Start the one-handed mode. - */ - void startOneHandedMode() = 26; - - /** - * Stop the one-handed mode. - */ - void stopOneHandedMode() = 27; - - /** * Handle the provided image as if it was a screenshot. */ void handleImageBundleAsScreenshot(in Bundle screenImageBundle, in Rect locationInScreen, @@ -176,88 +140,5 @@ interface ISystemUiProxy { */ void expandNotificationPanel() = 29; - /** - * Notifies that Activity is about to be swiped to home with entering PiP transition and - * queries the destination bounds for PiP depends on Launcher's rotation and shelf height. - * - * @param componentName ComponentName represents the Activity - * @param activityInfo ActivityInfo tied to the Activity - * @param pictureInPictureParams PictureInPictureParams tied to the Activity - * @param launcherRotation Launcher rotation to calculate the PiP destination bounds - * @param shelfHeight Shelf height of launcher to calculate the PiP destination bounds - * @return destination bounds the PiP window should land into - */ - Rect startSwipePipToHome(in ComponentName componentName, in ActivityInfo activityInfo, - in PictureInPictureParams pictureInPictureParams, - int launcherRotation, int shelfHeight) = 30; - - /** - * Notifies the swiping Activity to PiP onto home transition is finished - * - * @param componentName ComponentName represents the Activity - * @param destinationBounds the destination bounds the PiP window lands into - */ - void stopSwipePipToHome(in ComponentName componentName, in Rect destinationBounds) = 31; - - /** - * Registers a RemoteTransitionCompat that will handle transitions. This parameter bundles an - * IRemoteTransition and a filter that must pass for it. - */ - void registerRemoteTransition(in RemoteTransitionCompat remoteTransition) = 32; - - /** Unegisters a RemoteTransitionCompat that will handle transitions. */ - void unregisterRemoteTransition(in RemoteTransitionCompat remoteTransition) = 33; - -// SplitScreen APIs...copied from SplitScreen.java - /** - * Stage position isn't specified normally meaning to use what ever it is currently set to. - */ - //int STAGE_POSITION_UNDEFINED = -1; - /** - * Specifies that a stage is positioned at the top half of the screen if - * in portrait mode or at the left half of the screen if in landscape mode. - */ - //int STAGE_POSITION_TOP_OR_LEFT = 0; - /** - * Specifies that a stage is positioned at the bottom half of the screen if - * in portrait mode or at the right half of the screen if in landscape mode. - */ - //int STAGE_POSITION_BOTTOM_OR_RIGHT = 1; - - /** - * Stage type isn't specified normally meaning to use what ever the default is. - * E.g. exit split-screen and launch the app in fullscreen. - */ - //int STAGE_TYPE_UNDEFINED = -1; - /** - * The main stage type. - * @see MainStage - */ - //int STAGE_TYPE_MAIN = 0; - /** - * The side stage type. - * @see SideStage - */ - //int STAGE_TYPE_SIDE = 1; - - void registerSplitScreenListener(in ISplitScreenListener listener) = 34; - void unregisterSplitScreenListener(in ISplitScreenListener listener) = 35; - - /** Hides the side-stage if it is currently visible. */ - void setSideStageVisibility(in boolean visible) = 36; - /** Removes the split-screen stages. */ - void exitSplitScreen() = 37; - /** @param exitSplitScreenOnHide if to exit split-screen if both stages are not visible. */ - void exitSplitScreenOnHide(boolean exitSplitScreenOnHide) = 38; - void startTask(in int taskId, in int stage, in int position, in Bundle options) = 39; - void startShortcut(in String packageName, in String shortcutId, in int stage, in int position, - in Bundle options, in UserHandle user) = 40; - void startIntent( - in PendingIntent intent, in Intent fillInIntent, in int stage, in int position, - in Bundle options) = 41; - void removeFromSideStage(in int taskId) = 42; - /** - * Sets listener to get task launching callbacks. - */ - void setStartingWindowListener(IStartingWindowListener listener) = 43; + // Next id = 44 } diff --git a/packages/SystemUI/shared/src/com/android/systemui/shared/system/QuickStepContract.java b/packages/SystemUI/shared/src/com/android/systemui/shared/system/QuickStepContract.java index 937c1df10315..41840afc4995 100644 --- a/packages/SystemUI/shared/src/com/android/systemui/shared/system/QuickStepContract.java +++ b/packages/SystemUI/shared/src/com/android/systemui/shared/system/QuickStepContract.java @@ -41,6 +41,18 @@ public class QuickStepContract { public static final String KEY_EXTRA_INPUT_MONITOR = "extra_input_monitor"; public static final String KEY_EXTRA_WINDOW_CORNER_RADIUS = "extra_window_corner_radius"; public static final String KEY_EXTRA_SUPPORTS_WINDOW_CORNERS = "extra_supports_window_corners"; + // See IPip.aidl + public static final String KEY_EXTRA_SHELL_PIP = "extra_shell_pip"; + // See ISplitScreen.aidl + public static final String KEY_EXTRA_SHELL_SPLIT_SCREEN = "extra_shell_split_screen"; + // See IOneHanded.aidl + public static final String KEY_EXTRA_SHELL_ONE_HANDED = "extra_shell_one_handed"; + // See IShellTransitions.aidl + public static final String KEY_EXTRA_SHELL_SHELL_TRANSITIONS = + "extra_shell_shell_transitions"; + // See IStartingWindow.aidl + public static final String KEY_EXTRA_SHELL_STARTING_WINDOW = + "extra_shell_starting_window"; public static final String NAV_BAR_MODE_2BUTTON_OVERLAY = WindowManagerPolicyConstants.NAV_BAR_MODE_2BUTTON_OVERLAY; diff --git a/packages/SystemUI/src/com/android/systemui/appops/AppOpsControllerImpl.java b/packages/SystemUI/src/com/android/systemui/appops/AppOpsControllerImpl.java index 2040347de1b5..e53f5c97bb5c 100644 --- a/packages/SystemUI/src/com/android/systemui/appops/AppOpsControllerImpl.java +++ b/packages/SystemUI/src/com/android/systemui/appops/AppOpsControllerImpl.java @@ -20,7 +20,6 @@ import static android.hardware.SensorPrivacyManager.Sensors.CAMERA; import static android.hardware.SensorPrivacyManager.Sensors.MICROPHONE; import static android.media.AudioManager.ACTION_MICROPHONE_MUTE_CHANGED; -import android.Manifest; import android.app.AppOpsManager; import android.content.BroadcastReceiver; import android.content.Context; @@ -43,6 +42,7 @@ import androidx.annotation.WorkerThread; import com.android.internal.R; import com.android.internal.annotations.GuardedBy; import com.android.internal.annotations.VisibleForTesting; +import com.android.internal.config.sysui.SystemUiDeviceConfigFlags; import com.android.systemui.Dumpable; import com.android.systemui.broadcast.BroadcastDispatcher; import com.android.systemui.dagger.SysUISingleton; @@ -370,13 +370,9 @@ public class AppOpsControllerImpl extends BroadcastReceiver implements AppOpsCon } // TODO ntmyren: remove after teamfood is finished - private boolean shouldShowAppPredictor(String pkgName) { - if (!DeviceConfig.getBoolean(DeviceConfig.NAMESPACE_PRIVACY, "permissions_hub_2_enabled", - false)) { - return false; - } - return mPackageManager.checkPermission(Manifest.permission.MANAGE_APP_PREDICTIONS, pkgName) - == PackageManager.PERMISSION_GRANTED; + private boolean showSystemApps() { + return DeviceConfig.getBoolean(DeviceConfig.NAMESPACE_PRIVACY, + SystemUiDeviceConfigFlags.PROPERTY_PERMISSIONS_HUB_ENABLED, false); } /** @@ -399,8 +395,8 @@ public class AppOpsControllerImpl extends BroadcastReceiver implements AppOpsCon return true; } // TODO ntmyren: Replace this with more robust check if this moves beyond teamfood - if ((appOpCode == AppOpsManager.OP_CAMERA && isLocationProvider(packageName)) - || shouldShowAppPredictor(packageName) + if (((showSystemApps() && !packageName.equals("android")) + || appOpCode == AppOpsManager.OP_CAMERA && isLocationProvider(packageName)) || isSpeechRecognizerUsage(appOpCode, packageName)) { return true; } diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsEnrollHelper.java b/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsEnrollHelper.java index 62058a965c09..98a703f595d2 100644 --- a/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsEnrollHelper.java +++ b/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsEnrollHelper.java @@ -21,6 +21,9 @@ import android.annotation.Nullable; import android.content.Context; import android.graphics.PointF; import android.hardware.fingerprint.IUdfpsOverlayController; +import android.os.Build; +import android.os.UserHandle; +import android.provider.Settings; import android.util.TypedValue; import java.util.ArrayList; @@ -32,6 +35,10 @@ import java.util.List; public class UdfpsEnrollHelper { private static final String TAG = "UdfpsEnrollHelper"; + private static final String SCALE_OVERRIDE = + "com.android.systemui.biometrics.UdfpsEnrollHelper.scale"; + private static final float SCALE = 0.5f; + // Enroll with two center touches before going to guided enrollment private static final int NUM_CENTER_TOUCHES = 2; @@ -39,9 +46,10 @@ public class UdfpsEnrollHelper { void onEnrollmentProgress(int remaining, int totalSteps); } + @NonNull private final Context mContext; // IUdfpsOverlayController reason private final int mEnrollReason; - private final List<PointF> mGuidedEnrollmentPoints; + @NonNull private final List<PointF> mGuidedEnrollmentPoints; private int mTotalSteps = -1; private int mRemainingSteps = -1; @@ -53,6 +61,7 @@ public class UdfpsEnrollHelper { @Nullable Listener mListener; public UdfpsEnrollHelper(@NonNull Context context, int reason) { + mContext = context; mEnrollReason = reason; mGuidedEnrollmentPoints = new ArrayList<>(); @@ -121,9 +130,15 @@ public class UdfpsEnrollHelper { @NonNull PointF getNextGuidedEnrollmentPoint() { + float scale = SCALE; + if (Build.IS_ENG || Build.IS_USERDEBUG) { + scale = Settings.Secure.getFloatForUser(mContext.getContentResolver(), + SCALE_OVERRIDE, SCALE, + UserHandle.USER_CURRENT); + } final int index = mLocationsEnrolled - NUM_CENTER_TOUCHES; final PointF originalPoint = mGuidedEnrollmentPoints .get(index % mGuidedEnrollmentPoints.size()); - return new PointF(originalPoint.x * 0.5f, originalPoint.y * 0.5f); + return new PointF(originalPoint.x * scale, originalPoint.y * scale); } } diff --git a/packages/SystemUI/src/com/android/systemui/dagger/SysUIComponent.java b/packages/SystemUI/src/com/android/systemui/dagger/SysUIComponent.java index 8f79de518419..ed3d5ec33b41 100644 --- a/packages/SystemUI/src/com/android/systemui/dagger/SysUIComponent.java +++ b/packages/SystemUI/src/com/android/systemui/dagger/SysUIComponent.java @@ -34,7 +34,7 @@ import com.android.wm.shell.onehanded.OneHanded; import com.android.wm.shell.pip.Pip; import com.android.wm.shell.splitscreen.SplitScreen; import com.android.wm.shell.startingsurface.StartingSurface; -import com.android.wm.shell.transition.RemoteTransitions; +import com.android.wm.shell.transition.ShellTransitions; import java.util.Optional; @@ -87,7 +87,7 @@ public interface SysUIComponent { Builder setShellCommandHandler(Optional<ShellCommandHandler> shellDump); @BindsInstance - Builder setTransitions(RemoteTransitions t); + Builder setTransitions(ShellTransitions t); @BindsInstance Builder setStartingSurface(Optional<StartingSurface> s); diff --git a/packages/SystemUI/src/com/android/systemui/dagger/WMComponent.java b/packages/SystemUI/src/com/android/systemui/dagger/WMComponent.java index 1b77d1c16639..bbd95b4d0c90 100644 --- a/packages/SystemUI/src/com/android/systemui/dagger/WMComponent.java +++ b/packages/SystemUI/src/com/android/systemui/dagger/WMComponent.java @@ -33,7 +33,7 @@ import com.android.wm.shell.onehanded.OneHanded; import com.android.wm.shell.pip.Pip; import com.android.wm.shell.splitscreen.SplitScreen; import com.android.wm.shell.startingsurface.StartingSurface; -import com.android.wm.shell.transition.RemoteTransitions; +import com.android.wm.shell.transition.ShellTransitions; import java.util.Optional; @@ -98,7 +98,7 @@ public interface WMComponent { Optional<TaskViewFactory> getTaskViewFactory(); @WMSingleton - RemoteTransitions getTransitions(); + ShellTransitions getTransitions(); @WMSingleton Optional<StartingSurface> getStartingSurface(); diff --git a/packages/SystemUI/src/com/android/systemui/privacy/PrivacyDialogController.kt b/packages/SystemUI/src/com/android/systemui/privacy/PrivacyDialogController.kt index 03c184336364..f87ea7c61ca8 100644 --- a/packages/SystemUI/src/com/android/systemui/privacy/PrivacyDialogController.kt +++ b/packages/SystemUI/src/com/android/systemui/privacy/PrivacyDialogController.kt @@ -214,9 +214,7 @@ class PrivacyDialogController( private fun filterType(type: PrivacyType?): PrivacyType? { return type?.let { - if (privacyItemController.allIndicatorsAvailable) { - it - } else if ((it == PrivacyType.TYPE_CAMERA || it == PrivacyType.TYPE_MICROPHONE) && + if ((it == PrivacyType.TYPE_CAMERA || it == PrivacyType.TYPE_MICROPHONE) && privacyItemController.micCameraAvailable) { it } else if (it == PrivacyType.TYPE_LOCATION && privacyItemController.locationAvailable) { diff --git a/packages/SystemUI/src/com/android/systemui/privacy/PrivacyItemController.kt b/packages/SystemUI/src/com/android/systemui/privacy/PrivacyItemController.kt index 1e0451601e50..03d6154706eb 100644 --- a/packages/SystemUI/src/com/android/systemui/privacy/PrivacyItemController.kt +++ b/packages/SystemUI/src/com/android/systemui/privacy/PrivacyItemController.kt @@ -68,8 +68,6 @@ class PrivacyItemController @Inject constructor( addAction(Intent.ACTION_MANAGED_PROFILE_UNAVAILABLE) } const val TAG = "PrivacyItemController" - private const val ALL_INDICATORS = - SystemUiDeviceConfigFlags.PROPERTY_PERMISSIONS_HUB_ENABLED private const val MIC_CAMERA = SystemUiDeviceConfigFlags.PROPERTY_MIC_CAMERA_ENABLED private const val LOCATION = SystemUiDeviceConfigFlags.PROPERTY_LOCATION_INDICATORS_ENABLED private const val DEFAULT_ALL_INDICATORS = false @@ -83,11 +81,6 @@ class PrivacyItemController @Inject constructor( @Synchronized get() = field.toList() // Returns a shallow copy of the list @Synchronized set - private fun isAllIndicatorsEnabled(): Boolean { - return deviceConfigProxy.getBoolean(DeviceConfig.NAMESPACE_PRIVACY, - ALL_INDICATORS, DEFAULT_ALL_INDICATORS) - } - private fun isMicCameraEnabled(): Boolean { return deviceConfigProxy.getBoolean(DeviceConfig.NAMESPACE_PRIVACY, MIC_CAMERA, DEFAULT_MIC_CAMERA) @@ -120,34 +113,29 @@ class PrivacyItemController @Inject constructor( uiExecutor.execute(notifyChanges) } - var allIndicatorsAvailable = isAllIndicatorsEnabled() - private set var micCameraAvailable = isMicCameraEnabled() private set var locationAvailable = isLocationEnabled() + var allIndicatorsAvailable = micCameraAvailable && locationAvailable + private val devicePropertiesChangedListener = object : DeviceConfig.OnPropertiesChangedListener { override fun onPropertiesChanged(properties: DeviceConfig.Properties) { if (DeviceConfig.NAMESPACE_PRIVACY.equals(properties.getNamespace()) && - (properties.keyset.contains(ALL_INDICATORS) || - properties.keyset.contains(MIC_CAMERA) || + (properties.keyset.contains(MIC_CAMERA) || properties.keyset.contains(LOCATION))) { // Running on the ui executor so can iterate on callbacks - if (properties.keyset.contains(ALL_INDICATORS)) { - allIndicatorsAvailable = properties.getBoolean(ALL_INDICATORS, - DEFAULT_ALL_INDICATORS) - callbacks.forEach { it.get()?.onFlagAllChanged(allIndicatorsAvailable) } - } - if (properties.keyset.contains(MIC_CAMERA)) { micCameraAvailable = properties.getBoolean(MIC_CAMERA, DEFAULT_MIC_CAMERA) + allIndicatorsAvailable = micCameraAvailable && locationAvailable callbacks.forEach { it.get()?.onFlagMicCameraChanged(micCameraAvailable) } } if (properties.keyset.contains(LOCATION)) { locationAvailable = properties.getBoolean(LOCATION, DEFAULT_LOCATION) + allIndicatorsAvailable = micCameraAvailable && locationAvailable callbacks.forEach { it.get()?.onFlagLocationChanged(locationAvailable) } } internalUiExecutor.updateListeningState() @@ -163,8 +151,7 @@ class PrivacyItemController @Inject constructor( active: Boolean ) { // Check if we care about this code right now - if (!allIndicatorsAvailable && - (code in OPS_LOCATION && !locationAvailable)) { + if (code in OPS_LOCATION && !locationAvailable) { return } val userId = UserHandle.getUserId(uid) @@ -231,7 +218,7 @@ class PrivacyItemController @Inject constructor( */ private fun setListeningState() { val listen = !callbacks.isEmpty() and - (allIndicatorsAvailable || micCameraAvailable || locationAvailable) + (micCameraAvailable || locationAvailable) if (listening == listen) return listening = listen if (listening) { @@ -338,7 +325,7 @@ class PrivacyItemController @Inject constructor( AppOpsManager.OP_RECORD_AUDIO -> PrivacyType.TYPE_MICROPHONE else -> return null } - if (type == PrivacyType.TYPE_LOCATION && (!allIndicatorsAvailable && !locationAvailable)) { + if (type == PrivacyType.TYPE_LOCATION && !locationAvailable) { return null } val app = PrivacyApplication(appOpItem.packageName, appOpItem.uid) diff --git a/packages/SystemUI/src/com/android/systemui/privacy/television/TvOngoingPrivacyChip.java b/packages/SystemUI/src/com/android/systemui/privacy/television/TvOngoingPrivacyChip.java index 0fa7b59d0e54..5ab7bd88e49b 100644 --- a/packages/SystemUI/src/com/android/systemui/privacy/television/TvOngoingPrivacyChip.java +++ b/packages/SystemUI/src/com/android/systemui/privacy/television/TvOngoingPrivacyChip.java @@ -88,7 +88,6 @@ public class TvOngoingPrivacyChip extends SystemUI implements PrivacyItemControl private boolean mViewAndWindowAdded; private ObjectAnimator mAnimator; - private boolean mAllIndicatorsFlagEnabled; private boolean mMicCameraIndicatorFlagEnabled; private boolean mLocationIndicatorEnabled; private List<PrivacyItem> mPrivacyItems; @@ -111,12 +110,10 @@ public class TvOngoingPrivacyChip extends SystemUI implements PrivacyItemControl mIconMarginStart = Math.round(res.getDimension(R.dimen.privacy_chip_icon_margin)); mIconSize = res.getDimensionPixelSize(R.dimen.privacy_chip_icon_size); - mAllIndicatorsFlagEnabled = privacyItemController.getAllIndicatorsAvailable(); mMicCameraIndicatorFlagEnabled = privacyItemController.getMicCameraAvailable(); mLocationIndicatorEnabled = privacyItemController.getLocationAvailable(); if (DEBUG) { - Log.d(TAG, "allIndicators: " + mAllIndicatorsFlagEnabled); Log.d(TAG, "micCameraIndicators: " + mMicCameraIndicatorFlagEnabled); Log.d(TAG, "locationIndicators: " + mLocationIndicatorEnabled); } @@ -135,12 +132,6 @@ public class TvOngoingPrivacyChip extends SystemUI implements PrivacyItemControl } @Override - public void onFlagAllChanged(boolean flag) { - if (DEBUG) Log.d(TAG, "all indicators enabled: " + flag); - mAllIndicatorsFlagEnabled = flag; - } - - @Override public void onFlagMicCameraChanged(boolean flag) { if (DEBUG) Log.d(TAG, "mic/camera indicators enabled: " + flag); mMicCameraIndicatorFlagEnabled = flag; @@ -155,8 +146,8 @@ public class TvOngoingPrivacyChip extends SystemUI implements PrivacyItemControl private void updateUI() { if (DEBUG) Log.d(TAG, mPrivacyItems.size() + " privacy items"); - if ((mMicCameraIndicatorFlagEnabled || mAllIndicatorsFlagEnabled - || mLocationIndicatorEnabled) && !mPrivacyItems.isEmpty()) { + if ((mMicCameraIndicatorFlagEnabled || mLocationIndicatorEnabled) + && !mPrivacyItems.isEmpty()) { if (mState == STATE_NOT_SHOWN || mState == STATE_DISAPPEARING) { showIndicator(); } else { diff --git a/packages/SystemUI/src/com/android/systemui/qs/QuickQSPanel.java b/packages/SystemUI/src/com/android/systemui/qs/QuickQSPanel.java index 8f99a9e9c1be..e7828c366b64 100644 --- a/packages/SystemUI/src/com/android/systemui/qs/QuickQSPanel.java +++ b/packages/SystemUI/src/com/android/systemui/qs/QuickQSPanel.java @@ -355,7 +355,6 @@ public class QuickQSPanel extends QSPanel { setClipToPadding(false); LinearLayout.LayoutParams lp = new LinearLayout.LayoutParams(LayoutParams.MATCH_PARENT, LayoutParams.WRAP_CONTENT); - lp.gravity = Gravity.CENTER_HORIZONTAL; setLayoutParams(lp); setMaxColumns(4); } diff --git a/packages/SystemUI/src/com/android/systemui/qs/QuickStatusBarHeaderController.java b/packages/SystemUI/src/com/android/systemui/qs/QuickStatusBarHeaderController.java index e3c39aa77402..eedcdab68b9f 100644 --- a/packages/SystemUI/src/com/android/systemui/qs/QuickStatusBarHeaderController.java +++ b/packages/SystemUI/src/com/android/systemui/qs/QuickStatusBarHeaderController.java @@ -97,7 +97,6 @@ class QuickStatusBarHeaderController extends ViewController<QuickStatusBarHeader private boolean mListening; private AlarmClockInfo mNextAlarm; - private boolean mAllIndicatorsEnabled; private boolean mMicCameraIndicatorsEnabled; private boolean mLocationIndicatorsEnabled; private boolean mPrivacyChipLogged; @@ -151,14 +150,6 @@ class QuickStatusBarHeaderController extends ViewController<QuickStatusBarHeader } @Override - public void onFlagAllChanged(boolean flag) { - if (mAllIndicatorsEnabled != flag) { - mAllIndicatorsEnabled = flag; - update(); - } - } - - @Override public void onFlagMicCameraChanged(boolean flag) { if (mMicCameraIndicatorsEnabled != flag) { mMicCameraIndicatorsEnabled = flag; @@ -270,7 +261,6 @@ class QuickStatusBarHeaderController extends ViewController<QuickStatusBarHeader mRingerContainer.setOnClickListener(mOnClickListener); mPrivacyChip.setOnClickListener(mOnClickListener); - mAllIndicatorsEnabled = mPrivacyItemController.getAllIndicatorsAvailable(); mMicCameraIndicatorsEnabled = mPrivacyItemController.getMicCameraAvailable(); mLocationIndicatorsEnabled = mPrivacyItemController.getLocationAvailable(); @@ -321,7 +311,6 @@ class QuickStatusBarHeaderController extends ViewController<QuickStatusBarHeader mNextAlarmController.addCallback(mNextAlarmChangeCallback); mLifecycle.setCurrentState(Lifecycle.State.RESUMED); // Get the most up to date info - mAllIndicatorsEnabled = mPrivacyItemController.getAllIndicatorsAvailable(); mMicCameraIndicatorsEnabled = mPrivacyItemController.getMicCameraAvailable(); mLocationIndicatorsEnabled = mPrivacyItemController.getLocationAvailable(); mPrivacyItemController.addCallback(mPICCallback); @@ -353,13 +342,13 @@ class QuickStatusBarHeaderController extends ViewController<QuickStatusBarHeader private List<String> getIgnoredIconSlots() { ArrayList<String> ignored = new ArrayList<>(); if (getChipEnabled()) { - if (mAllIndicatorsEnabled || mMicCameraIndicatorsEnabled) { + if (mMicCameraIndicatorsEnabled) { ignored.add(mView.getResources().getString( com.android.internal.R.string.status_bar_camera)); ignored.add(mView.getResources().getString( com.android.internal.R.string.status_bar_microphone)); } - if (mAllIndicatorsEnabled || mLocationIndicatorsEnabled) { + if (mLocationIndicatorsEnabled) { ignored.add(mView.getResources().getString( com.android.internal.R.string.status_bar_location)); } @@ -368,7 +357,7 @@ class QuickStatusBarHeaderController extends ViewController<QuickStatusBarHeader } private boolean getChipEnabled() { - return mMicCameraIndicatorsEnabled || mLocationIndicatorsEnabled || mAllIndicatorsEnabled; + return mMicCameraIndicatorsEnabled || mLocationIndicatorsEnabled; } private boolean isZenOverridingRinger() { diff --git a/packages/SystemUI/src/com/android/systemui/recents/OverviewProxyService.java b/packages/SystemUI/src/com/android/systemui/recents/OverviewProxyService.java index a87bfd83916a..5a714f2ed384 100644 --- a/packages/SystemUI/src/com/android/systemui/recents/OverviewProxyService.java +++ b/packages/SystemUI/src/com/android/systemui/recents/OverviewProxyService.java @@ -25,6 +25,11 @@ import static android.view.WindowManagerPolicyConstants.NAV_BAR_MODE_3BUTTON; import static com.android.internal.accessibility.common.ShortcutConstants.CHOOSER_PACKAGE_NAME; import static com.android.systemui.shared.system.QuickStepContract.KEY_EXTRA_INPUT_MONITOR; +import static com.android.systemui.shared.system.QuickStepContract.KEY_EXTRA_SHELL_ONE_HANDED; +import static com.android.systemui.shared.system.QuickStepContract.KEY_EXTRA_SHELL_PIP; +import static com.android.systemui.shared.system.QuickStepContract.KEY_EXTRA_SHELL_SHELL_TRANSITIONS; +import static com.android.systemui.shared.system.QuickStepContract.KEY_EXTRA_SHELL_SPLIT_SCREEN; +import static com.android.systemui.shared.system.QuickStepContract.KEY_EXTRA_SHELL_STARTING_WINDOW; import static com.android.systemui.shared.system.QuickStepContract.KEY_EXTRA_SUPPORTS_WINDOW_CORNERS; import static com.android.systemui.shared.system.QuickStepContract.KEY_EXTRA_SYSUI_PROXY; import static com.android.systemui.shared.system.QuickStepContract.KEY_EXTRA_WINDOW_CORNER_RADIUS; @@ -35,15 +40,12 @@ import static com.android.systemui.shared.system.QuickStepContract.SYSUI_STATE_T import android.annotation.FloatRange; import android.app.ActivityTaskManager; -import android.app.PendingIntent; -import android.app.PictureInPictureParams; import android.content.BroadcastReceiver; import android.content.ComponentName; import android.content.Context; import android.content.Intent; import android.content.IntentFilter; import android.content.ServiceConnection; -import android.content.pm.ActivityInfo; import android.graphics.Bitmap; import android.graphics.Insets; import android.graphics.Rect; @@ -57,14 +59,12 @@ import android.os.Looper; import android.os.PatternMatcher; import android.os.RemoteException; import android.os.UserHandle; -import android.util.ArraySet; import android.util.Log; import android.view.InputMonitor; import android.view.KeyEvent; import android.view.MotionEvent; import android.view.Surface; import android.view.accessibility.AccessibilityManager; -import android.window.IRemoteTransition; import androidx.annotation.NonNull; @@ -83,15 +83,11 @@ import com.android.systemui.navigationbar.NavigationModeController; import com.android.systemui.recents.OverviewProxyService.OverviewProxyListener; import com.android.systemui.settings.CurrentUserTracker; import com.android.systemui.shared.recents.IOverviewProxy; -import com.android.systemui.shared.recents.IPinnedStackAnimationListener; -import com.android.systemui.shared.recents.ISplitScreenListener; -import com.android.systemui.shared.recents.IStartingWindowListener; import com.android.systemui.shared.recents.ISystemUiProxy; import com.android.systemui.shared.recents.model.Task; import com.android.systemui.shared.system.ActivityManagerWrapper; import com.android.systemui.shared.system.InputMonitorCompat; import com.android.systemui.shared.system.QuickStepContract; -import com.android.systemui.shared.system.RemoteTransitionCompat; import com.android.systemui.statusbar.CommandQueue; import com.android.systemui.statusbar.NotificationShadeWindowController; import com.android.systemui.statusbar.phone.StatusBar; @@ -103,7 +99,7 @@ import com.android.wm.shell.pip.Pip; import com.android.wm.shell.pip.PipAnimationController; import com.android.wm.shell.splitscreen.SplitScreen; import com.android.wm.shell.startingsurface.StartingSurface; -import com.android.wm.shell.transition.RemoteTransitions; +import com.android.wm.shell.transition.ShellTransitions; import java.io.FileDescriptor; import java.io.PrintWriter; @@ -111,7 +107,6 @@ import java.util.ArrayList; import java.util.List; import java.util.Optional; import java.util.function.BiConsumer; -import java.util.function.Consumer; import javax.inject.Inject; @@ -151,12 +146,11 @@ public class OverviewProxyService extends CurrentUserTracker implements private final ScreenshotHelper mScreenshotHelper; private final Optional<OneHanded> mOneHandedOptional; private final CommandQueue mCommandQueue; - private final RemoteTransitions mShellTransitions; + private final ShellTransitions mShellTransitions; private final Optional<StartingSurface> mStartingSurface; private Region mActiveNavBarRegion; - private IPinnedStackAnimationListener mIPinnedStackAnimationListener; private IOverviewProxy mOverviewProxy; private int mConnectionBackoffAttempts; private boolean mBound; @@ -169,8 +163,6 @@ public class OverviewProxyService extends CurrentUserTracker implements private float mWindowCornerRadius; private boolean mSupportsRoundedCornersOnWindows; private int mNavBarMode = NAV_BAR_MODE_3BUTTON; - private final ArraySet<IRemoteTransition> mRemoteTransitions = new ArraySet<>(); - private IStartingWindowListener mIStartingWindowListener; @VisibleForTesting public ISystemUiProxy mSysUiProxy = new ISystemUiProxy.Stub() { @@ -388,20 +380,6 @@ public class OverviewProxyService extends CurrentUserTracker implements } @Override - public void setShelfHeight(boolean visible, int shelfHeight) { - if (!verifyCaller("setShelfHeight")) { - return; - } - final long token = Binder.clearCallingIdentity(); - try { - mPipOptional.ifPresent( - pip -> pip.setShelfHeight(visible, shelfHeight)); - } finally { - Binder.restoreCallingIdentity(token); - } - } - - @Override public void handleImageAsScreenshot(Bitmap screenImage, Rect locationInScreen, Insets visibleInsets, int taskId) { // Deprecated @@ -429,36 +407,6 @@ public class OverviewProxyService extends CurrentUserTracker implements } @Override - public void setPinnedStackAnimationListener(IPinnedStackAnimationListener listener) { - if (!verifyCaller("setPinnedStackAnimationListener")) { - return; - } - mIPinnedStackAnimationListener = listener; - final long token = Binder.clearCallingIdentity(); - try { - mPipOptional.ifPresent( - pip -> pip.setPinnedStackAnimationListener(mPinnedStackAnimationCallback)); - } finally { - Binder.restoreCallingIdentity(token); - } - } - - @Override - public void setStartingWindowListener(IStartingWindowListener listener) { - if (!verifyCaller("setStartingWindowListener")) { - return; - } - mIStartingWindowListener = listener; - final long token = Binder.clearCallingIdentity(); - try { - mStartingSurface.ifPresent(s -> - s.setStartingWindowListener(mStartingWindowListener)); - } finally { - Binder.restoreCallingIdentity(token); - } - } - - @Override public void onQuickSwitchToNewTask(@Surface.Rotation int rotation) { if (!verifyCaller("onQuickSwitchToNewTask")) { return; @@ -472,32 +420,6 @@ public class OverviewProxyService extends CurrentUserTracker implements } @Override - public void startOneHandedMode() { - if (!verifyCaller("startOneHandedMode")) { - return; - } - final long token = Binder.clearCallingIdentity(); - try { - mOneHandedOptional.ifPresent(oneHanded -> oneHanded.startOneHanded()); - } finally { - Binder.restoreCallingIdentity(token); - } - } - - @Override - public void stopOneHandedMode() { - if (!verifyCaller("stopOneHandedMode")) { - return; - } - final long token = Binder.clearCallingIdentity(); - try { - mOneHandedOptional.ifPresent(oneHanded -> oneHanded.stopOneHanded()); - } finally { - Binder.restoreCallingIdentity(token); - } - } - - @Override public void handleImageBundleAsScreenshot(Bundle screenImageBundle, Rect locationInScreen, Insets visibleInsets, Task.TaskKey task) { mScreenshotHelper.provideScreenshot( @@ -525,190 +447,6 @@ public class OverviewProxyService extends CurrentUserTracker implements } } - @Override - public Rect startSwipePipToHome(ComponentName componentName, ActivityInfo activityInfo, - PictureInPictureParams pictureInPictureParams, - int launcherRotation, int shelfHeight) { - if (!verifyCaller("startSwipePipToHome")) { - return null; - } - final long binderToken = Binder.clearCallingIdentity(); - try { - return mPipOptional.map(pip -> - pip.startSwipePipToHome(componentName, activityInfo, - pictureInPictureParams, launcherRotation, shelfHeight)) - .orElse(null); - } finally { - Binder.restoreCallingIdentity(binderToken); - } - } - - @Override - public void stopSwipePipToHome(ComponentName componentName, Rect destinationBounds) { - if (!verifyCaller("stopSwipePipToHome")) { - return; - } - final long binderToken = Binder.clearCallingIdentity(); - try { - mPipOptional.ifPresent(pip -> pip.stopSwipePipToHome( - componentName, destinationBounds)); - } finally { - Binder.restoreCallingIdentity(binderToken); - } - } - - @Override - public void registerRemoteTransition(RemoteTransitionCompat remoteTransition) { - if (!verifyCaller("registerRemoteTransition")) return; - final long binderToken = Binder.clearCallingIdentity(); - try { - mRemoteTransitions.add(remoteTransition.getTransition()); - mShellTransitions.registerRemote( - remoteTransition.getFilter(), remoteTransition.getTransition()); - } finally { - Binder.restoreCallingIdentity(binderToken); - } - } - - @Override - public void unregisterRemoteTransition(RemoteTransitionCompat remoteTransition) { - if (!verifyCaller("registerRemoteTransition")) return; - final long binderToken = Binder.clearCallingIdentity(); - try { - mRemoteTransitions.remove(remoteTransition.getTransition()); - mShellTransitions.unregisterRemote(remoteTransition.getTransition()); - } finally { - Binder.restoreCallingIdentity(binderToken); - } - } - - @Override - public void registerSplitScreenListener(ISplitScreenListener listener) { - if (!verifyCaller("registerSplitScreenListener")) { - return; - } - mISplitScreenListener = listener; - final long token = Binder.clearCallingIdentity(); - try { - mSplitScreenOptional.ifPresent( - s -> s.registerSplitScreenListener(mSplitScreenListener)); - } finally { - Binder.restoreCallingIdentity(token); - } - } - - @Override - public void unregisterSplitScreenListener(ISplitScreenListener listener) { - if (!verifyCaller("unregisterSplitScreenListener")) { - return; - } - mISplitScreenListener = null; - final long token = Binder.clearCallingIdentity(); - try { - mSplitScreenOptional.ifPresent( - s -> s.unregisterSplitScreenListener(mSplitScreenListener)); - } finally { - Binder.restoreCallingIdentity(token); - } - } - - @Override - public void setSideStageVisibility(boolean visible) { - if (!verifyCaller("setSideStageVisibility")) { - return; - } - final long token = Binder.clearCallingIdentity(); - try { - mSplitScreenOptional.ifPresent(s -> s.setSideStageVisibility(visible)); - } finally { - Binder.restoreCallingIdentity(token); - } - } - - @Override - public void exitSplitScreen() { - if (!verifyCaller("exitSplitScreen")) { - return; - } - final long token = Binder.clearCallingIdentity(); - try { - mSplitScreenOptional.ifPresent(s -> s.exitSplitScreen()); - } finally { - Binder.restoreCallingIdentity(token); - } - } - - @Override - public void exitSplitScreenOnHide(boolean exitSplitScreenOnHide) { - if (!verifyCaller("exitSplitScreenOnHide")) { - return; - } - final long token = Binder.clearCallingIdentity(); - try { - mSplitScreenOptional.ifPresent(s -> s.exitSplitScreenOnHide(exitSplitScreenOnHide)); - } finally { - Binder.restoreCallingIdentity(token); - } - } - - @Override - public void startTask(int taskId, int stage, int position, Bundle options) { - if (!verifyCaller("startTask")) { - return; - } - final long token = Binder.clearCallingIdentity(); - try { - mSplitScreenOptional.ifPresent( - s -> s.startTask(taskId, stage, position, options)); - } finally { - Binder.restoreCallingIdentity(token); - } - } - - @Override - public void startShortcut(String packageName, String shortcutId, int stage, int position, - Bundle options, UserHandle user) { - if (!verifyCaller("startShortcut")) { - return; - } - final long token = Binder.clearCallingIdentity(); - try { - mSplitScreenOptional.ifPresent(s -> - s.startShortcut(packageName, shortcutId, stage, position, options, user)); - } finally { - Binder.restoreCallingIdentity(token); - } - } - - @Override - public void startIntent(PendingIntent intent, Intent fillInIntent, - int stage, int position, Bundle options) { - if (!verifyCaller("startIntent")) { - return; - } - final long token = Binder.clearCallingIdentity(); - try { - mSplitScreenOptional.ifPresent(s -> - s.startIntent(intent, mContext, fillInIntent, stage, position, options)); - } finally { - Binder.restoreCallingIdentity(token); - } - } - - @Override - public void removeFromSideStage(int taskId) { - if (!verifyCaller("removeFromSideStage")) { - return; - } - final long token = Binder.clearCallingIdentity(); - try { - mSplitScreenOptional.ifPresent( - s -> s.removeFromSideStage(taskId)); - } finally { - Binder.restoreCallingIdentity(token); - } - } - private boolean verifyCaller(String reason) { final int callerId = Binder.getCallingUserHandle().getIdentifier(); if (callerId != mCurrentBoundedUserId) { @@ -762,6 +500,22 @@ public class OverviewProxyService extends CurrentUserTracker implements params.putBinder(KEY_EXTRA_SYSUI_PROXY, mSysUiProxy.asBinder()); params.putFloat(KEY_EXTRA_WINDOW_CORNER_RADIUS, mWindowCornerRadius); params.putBoolean(KEY_EXTRA_SUPPORTS_WINDOW_CORNERS, mSupportsRoundedCornersOnWindows); + + mPipOptional.ifPresent((pip) -> params.putBinder( + KEY_EXTRA_SHELL_PIP, + pip.createExternalInterface().asBinder())); + mSplitScreenOptional.ifPresent((splitscreen) -> params.putBinder( + KEY_EXTRA_SHELL_SPLIT_SCREEN, + splitscreen.createExternalInterface().asBinder())); + mOneHandedOptional.ifPresent((onehanded) -> params.putBinder( + KEY_EXTRA_SHELL_ONE_HANDED, + onehanded.createExternalInterface().asBinder())); + params.putBinder(KEY_EXTRA_SHELL_SHELL_TRANSITIONS, + mShellTransitions.createExternalInterface().asBinder()); + mStartingSurface.ifPresent((startingwindow) -> params.putBinder( + KEY_EXTRA_SHELL_STARTING_WINDOW, + startingwindow.createExternalInterface().asBinder())); + try { mOverviewProxy.onInitialize(params); } catch (RemoteException e) { @@ -801,42 +555,11 @@ public class OverviewProxyService extends CurrentUserTracker implements private final StatusBarWindowCallback mStatusBarWindowCallback = this::onStatusBarStateChanged; private final BiConsumer<Rect, Rect> mSplitScreenBoundsChangeListener = this::notifySplitScreenBoundsChanged; - private final Consumer<Boolean> mPinnedStackAnimationCallback = - this::notifyPinnedStackAnimationStarted; - - private final BiConsumer<Integer, Integer> mStartingWindowListener = - this::notifyTaskLaunching; // This is the death handler for the binder from the launcher service private final IBinder.DeathRecipient mOverviewServiceDeathRcpt = this::cleanupAfterDeath; - private ISplitScreenListener mISplitScreenListener; - private final SplitScreen.SplitScreenListener mSplitScreenListener = - new SplitScreen.SplitScreenListener() { - @Override - public void onStagePositionChanged(int stage, int position) { - try { - if (mISplitScreenListener != null) { - mISplitScreenListener.onStagePositionChanged(stage, position); - } - } catch (RemoteException e) { - Log.e(TAG_OPS, "onStagePositionChanged", e); - } - } - - @Override - public void onTaskStageChanged(int taskId, int stage, boolean visible) { - try { - if (mISplitScreenListener != null) { - mISplitScreenListener.onTaskStageChanged(taskId, stage, visible); - } - } catch (RemoteException e) { - Log.e(TAG_OPS, "onTaskStageChanged", e); - } - } - }; - @SuppressWarnings("OptionalUsedAsFieldOrParameterType") @Inject public OverviewProxyService(Context context, CommandQueue commandQueue, @@ -849,7 +572,7 @@ public class OverviewProxyService extends CurrentUserTracker implements Optional<Lazy<StatusBar>> statusBarOptionalLazy, Optional<OneHanded> oneHandedOptional, BroadcastDispatcher broadcastDispatcher, - RemoteTransitions shellTransitions, + ShellTransitions shellTransitions, Optional<StartingSurface> startingSurface) { super(broadcastDispatcher); mContext = context; @@ -966,29 +689,6 @@ public class OverviewProxyService extends CurrentUserTracker implements } } - private void notifyPinnedStackAnimationStarted(Boolean isAnimationStarted) { - if (mIPinnedStackAnimationListener == null) { - return; - } - try { - mIPinnedStackAnimationListener.onPinnedStackAnimationStarted(); - } catch (RemoteException e) { - Log.e(TAG_OPS, "Failed to call onPinnedStackAnimationStarted()", e); - } - } - - private void notifyTaskLaunching(int taskId, int supportedType) { - if (mIStartingWindowListener == null) { - return; - } - - try { - mIStartingWindowListener.onTaskLaunching(taskId, supportedType); - } catch (RemoteException e) { - Log.e(TAG_OPS, "Failed to call notifyTaskLaunching()", e); - } - } - private void onStatusBarStateChanged(boolean keyguardShowing, boolean keyguardOccluded, boolean bouncerShowing) { mSysUiState.setFlag(SYSUI_STATE_STATUS_BAR_KEYGUARD_SHOWING, @@ -1032,12 +732,6 @@ public class OverviewProxyService extends CurrentUserTracker implements // Clean up the minimized state if launcher dies mLegacySplitScreenOptional.ifPresent( splitScreen -> splitScreen.setMinimized(false)); - - // Clean up any registered remote transitions - for (int i = mRemoteTransitions.size() - 1; i >= 0; --i) { - mShellTransitions.unregisterRemote(mRemoteTransitions.valueAt(i)); - } - mRemoteTransitions.clear(); } public void startConnectionToCurrentUser() { diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationChildrenContainer.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationChildrenContainer.java index 2b194ba15816..f65ae0c39331 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationChildrenContainer.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationChildrenContainer.java @@ -337,6 +337,7 @@ public class NotificationChildrenContainer extends ViewGroup { } else { header.reapply(getContext(), mNotificationHeader); } + mNotificationHeaderWrapper.setExpanded(mChildrenExpanded); mNotificationHeaderWrapper.onContentUpdated(mContainingNotification); if (mNotificationHeaderWrapper instanceof NotificationHeaderViewWrapper) { NotificationHeaderViewWrapper headerWrapper = diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBarPolicy.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBarPolicy.java index d53724159244..f1405dea1294 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBarPolicy.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBarPolicy.java @@ -675,8 +675,7 @@ public class PhoneStatusBarPolicy mIconController.setIconVisibility(mSlotCamera, showCamera); mIconController.setIconVisibility(mSlotMicrophone, showMicrophone); - if (mPrivacyItemController.getAllIndicatorsAvailable() - || mPrivacyItemController.getLocationAvailable()) { + if (mPrivacyItemController.getLocationAvailable()) { mIconController.setIconVisibility(mSlotLocation, showLocation); } mPrivacyLogger.logStatusBarIconsVisible(showCamera, showMicrophone, showLocation); @@ -684,8 +683,7 @@ public class PhoneStatusBarPolicy @Override public void onLocationActiveChanged(boolean active) { - if (!mPrivacyItemController.getAllIndicatorsAvailable() - && !mPrivacyItemController.getLocationAvailable()) { + if (!mPrivacyItemController.getLocationAvailable()) { updateLocationFromController(); } } diff --git a/packages/SystemUI/src/com/android/systemui/wmshell/WMShellBaseModule.java b/packages/SystemUI/src/com/android/systemui/wmshell/WMShellBaseModule.java index 1b6c61237e29..1d18750f1fdf 100644 --- a/packages/SystemUI/src/com/android/systemui/wmshell/WMShellBaseModule.java +++ b/packages/SystemUI/src/com/android/systemui/wmshell/WMShellBaseModule.java @@ -81,7 +81,7 @@ import com.android.wm.shell.splitscreen.SplitScreen; import com.android.wm.shell.splitscreen.SplitScreenController; import com.android.wm.shell.startingsurface.StartingSurface; import com.android.wm.shell.startingsurface.StartingWindowController; -import com.android.wm.shell.transition.RemoteTransitions; +import com.android.wm.shell.transition.ShellTransitions; import com.android.wm.shell.transition.Transitions; import java.util.Optional; @@ -399,8 +399,8 @@ public abstract class WMShellBaseModule { @WMSingleton @Provides - static RemoteTransitions provideRemoteTransitions(Transitions transitions) { - return Transitions.asRemoteTransitions(transitions); + static ShellTransitions provideRemoteTransitions(Transitions transitions) { + return transitions.asRemoteTransitions(); } @WMSingleton @@ -509,27 +509,33 @@ public abstract class WMShellBaseModule { @WMSingleton @Provides - static ShellInit provideShellInit(DisplayImeController displayImeController, + static ShellInit provideShellInit(ShellInitImpl impl) { + return impl.asShellInit(); + } + + @WMSingleton + @Provides + static ShellInitImpl provideShellInitImpl(DisplayImeController displayImeController, DragAndDropController dragAndDropController, ShellTaskOrganizer shellTaskOrganizer, Optional<LegacySplitScreenController> legacySplitScreenOptional, Optional<SplitScreenController> splitScreenOptional, Optional<AppPairsController> appPairsOptional, - Optional<StartingSurface> startingSurface, Optional<PipTouchHandler> pipTouchHandlerOptional, FullscreenTaskListener fullscreenTaskListener, Transitions transitions, + StartingWindowController startingWindow, @ShellMainThread ShellExecutor mainExecutor) { - return ShellInitImpl.create(displayImeController, + return new ShellInitImpl(displayImeController, dragAndDropController, shellTaskOrganizer, legacySplitScreenOptional, splitScreenOptional, appPairsOptional, - startingSurface, pipTouchHandlerOptional, fullscreenTaskListener, transitions, + startingWindow, mainExecutor); } @@ -539,7 +545,13 @@ public abstract class WMShellBaseModule { */ @WMSingleton @Provides - static Optional<ShellCommandHandler> provideShellCommandHandler( + static Optional<ShellCommandHandler> provideShellCommandHandler(ShellCommandHandlerImpl impl) { + return Optional.of(impl.asShellCommandHandler()); + } + + @WMSingleton + @Provides + static ShellCommandHandlerImpl provideShellCommandHandlerImpl( ShellTaskOrganizer shellTaskOrganizer, Optional<LegacySplitScreenController> legacySplitScreenOptional, Optional<SplitScreenController> splitScreenOptional, @@ -548,8 +560,8 @@ public abstract class WMShellBaseModule { Optional<HideDisplayCutoutController> hideDisplayCutout, Optional<AppPairsController> appPairsOptional, @ShellMainThread ShellExecutor mainExecutor) { - return Optional.of(ShellCommandHandlerImpl.create(shellTaskOrganizer, + return new ShellCommandHandlerImpl(shellTaskOrganizer, legacySplitScreenOptional, splitScreenOptional, pipOptional, oneHandedOptional, - hideDisplayCutout, appPairsOptional, mainExecutor)); + hideDisplayCutout, appPairsOptional, mainExecutor); } } diff --git a/packages/SystemUI/tests/src/com/android/systemui/privacy/PrivacyDialogControllerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/privacy/PrivacyDialogControllerTest.kt index 072f7b8a7756..791dd121852f 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/privacy/PrivacyDialogControllerTest.kt +++ b/packages/SystemUI/tests/src/com/android/systemui/privacy/PrivacyDialogControllerTest.kt @@ -395,9 +395,8 @@ class PrivacyDialogControllerTest : SysuiTestCase() { `when`(permissionManager.indicatorAppOpUsageData).thenReturn( listOf(usage_camera, usage_location, usage_microphone) ) - `when`(privacyItemController.micCameraAvailable).thenReturn(false) - `when`(privacyItemController.locationAvailable).thenReturn(false) - `when`(privacyItemController.allIndicatorsAvailable).thenReturn(true) + `when`(privacyItemController.micCameraAvailable).thenReturn(true) + `when`(privacyItemController.locationAvailable).thenReturn(true) controller.showDialog(context) exhaustExecutors() @@ -422,7 +421,6 @@ class PrivacyDialogControllerTest : SysuiTestCase() { ) `when`(privacyItemController.micCameraAvailable).thenReturn(false) `when`(privacyItemController.locationAvailable).thenReturn(false) - `when`(privacyItemController.allIndicatorsAvailable).thenReturn(false) controller.showDialog(context) exhaustExecutors() @@ -525,7 +523,6 @@ class PrivacyDialogControllerTest : SysuiTestCase() { `when`(privacyItemController.locationAvailable).thenReturn(true) `when`(privacyItemController.micCameraAvailable).thenReturn(true) - `when`(privacyItemController.allIndicatorsAvailable).thenReturn(false) `when`(userTracker.userProfiles).thenReturn(listOf( UserInfo(USER_ID, "", 0), diff --git a/packages/SystemUI/tests/src/com/android/systemui/privacy/PrivacyItemControllerFlagsTest.kt b/packages/SystemUI/tests/src/com/android/systemui/privacy/PrivacyItemControllerFlagsTest.kt index 132bee0e7fdf..f991e718122e 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/privacy/PrivacyItemControllerFlagsTest.kt +++ b/packages/SystemUI/tests/src/com/android/systemui/privacy/PrivacyItemControllerFlagsTest.kt @@ -37,7 +37,6 @@ import org.junit.runner.RunWith import org.mockito.ArgumentCaptor import org.mockito.Mock import org.mockito.Mockito -import org.mockito.Mockito.anyBoolean import org.mockito.Mockito.atLeastOnce import org.mockito.Mockito.never import org.mockito.Mockito.verify @@ -51,8 +50,6 @@ class PrivacyItemControllerFlagsTest : SysuiTestCase() { fun <T> eq(value: T): T = Mockito.eq(value) ?: value fun <T> any(): T = Mockito.any<T>() - private const val ALL_INDICATORS = - SystemUiDeviceConfigFlags.PROPERTY_PERMISSIONS_HUB_ENABLED private const val MIC_CAMERA = SystemUiDeviceConfigFlags.PROPERTY_MIC_CAMERA_ENABLED private const val LOCATION = SystemUiDeviceConfigFlags.PROPERTY_LOCATION_INDICATORS_ENABLED } @@ -96,11 +93,6 @@ class PrivacyItemControllerFlagsTest : SysuiTestCase() { } @Test - fun testNotListeningAllByDefault() { - assertFalse(privacyItemController.allIndicatorsAvailable) - } - - @Test fun testMicCameraListeningByDefault() { assertTrue(privacyItemController.micCameraAvailable) } @@ -111,10 +103,8 @@ class PrivacyItemControllerFlagsTest : SysuiTestCase() { executor.runAllReady() verify(callback).onFlagMicCameraChanged(false) - verify(callback, never()).onFlagAllChanged(anyBoolean()) assertFalse(privacyItemController.micCameraAvailable) - assertFalse(privacyItemController.allIndicatorsAvailable) } @Test @@ -127,26 +117,15 @@ class PrivacyItemControllerFlagsTest : SysuiTestCase() { } @Test - fun testAllChanged() { - changeAll(true) - executor.runAllReady() - - verify(callback).onFlagAllChanged(true) - verify(callback, never()).onFlagMicCameraChanged(anyBoolean()) - - assertTrue(privacyItemController.allIndicatorsAvailable) - } - - @Test fun testBothChanged() { changeAll(true) changeMicCamera(false) executor.runAllReady() - verify(callback, atLeastOnce()).onFlagAllChanged(true) + verify(callback, atLeastOnce()).onFlagLocationChanged(true) verify(callback, atLeastOnce()).onFlagMicCameraChanged(false) - assertTrue(privacyItemController.allIndicatorsAvailable) + assertTrue(privacyItemController.locationAvailable) assertFalse(privacyItemController.micCameraAvailable) } @@ -186,28 +165,6 @@ class PrivacyItemControllerFlagsTest : SysuiTestCase() { } @Test - fun testSomeListening_stillListening() { - // Mic and camera are true by default - changeAll(true) - executor.runAllReady() - changeAll(false) - executor.runAllReady() - - verify(appOpsController, never()).removeCallback(any(), any()) - } - - @Test - fun testAllDeleted_micCameraFalse_stopListening() { - changeMicCamera(false) - changeAll(true) - executor.runAllReady() - changeAll(null) - executor.runAllReady() - - verify(appOpsController).removeCallback(any(), any()) - } - - @Test fun testMicDeleted_stillListening() { changeMicCamera(true) executor.runAllReady() @@ -219,7 +176,10 @@ class PrivacyItemControllerFlagsTest : SysuiTestCase() { private fun changeMicCamera(value: Boolean?) = changeProperty(MIC_CAMERA, value) private fun changeLocation(value: Boolean?) = changeProperty(LOCATION, value) - private fun changeAll(value: Boolean?) = changeProperty(ALL_INDICATORS, value) + private fun changeAll(value: Boolean?) { + changeMicCamera(value) + changeLocation(value) + } private fun changeProperty(name: String, value: Boolean?) { deviceConfigProxy.setProperty( diff --git a/packages/SystemUI/tests/src/com/android/systemui/privacy/PrivacyItemControllerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/privacy/PrivacyItemControllerTest.kt index 7ca468edfd9c..b87c7a6ad2d9 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/privacy/PrivacyItemControllerTest.kt +++ b/packages/SystemUI/tests/src/com/android/systemui/privacy/PrivacyItemControllerTest.kt @@ -43,7 +43,6 @@ import org.junit.Assert.assertEquals import org.junit.Assert.assertThat import org.junit.Assert.assertTrue import org.junit.Before -import org.junit.Ignore import org.junit.Test import org.junit.runner.RunWith import org.mockito.ArgumentCaptor @@ -72,8 +71,8 @@ class PrivacyItemControllerTest : SysuiTestCase() { val TEST_UID = CURRENT_USER_ID * UserHandle.PER_USER_RANGE const val TEST_PACKAGE_NAME = "test" - private const val ALL_INDICATORS = - SystemUiDeviceConfigFlags.PROPERTY_PERMISSIONS_HUB_ENABLED + private const val LOCATION_INDICATOR = + SystemUiDeviceConfigFlags.PROPERTY_LOCATION_INDICATORS_ENABLED private const val MIC_CAMERA = SystemUiDeviceConfigFlags.PROPERTY_MIC_CAMERA_ENABLED fun <T> capture(argumentCaptor: ArgumentCaptor<T>): T = argumentCaptor.capture() fun <T> eq(value: T): T = Mockito.eq(value) ?: value @@ -119,7 +118,8 @@ class PrivacyItemControllerTest : SysuiTestCase() { deviceConfigProxy = DeviceConfigProxyFake() // Listen to everything by default - changeAll(true) + changeMicCamera(true) + changeLocation(true) `when`(userTracker.userProfiles).thenReturn(listOf(UserInfo(CURRENT_USER_ID, "", 0))) @@ -259,9 +259,8 @@ class PrivacyItemControllerTest : SysuiTestCase() { } @Test - @Ignore // TODO(b/168209929) fun testNotListeningWhenIndicatorsDisabled() { - changeAll(false) + changeLocation(false) changeMicCamera(false) privacyItemController.addCallback(callback) executor.runAllReady() @@ -271,7 +270,7 @@ class PrivacyItemControllerTest : SysuiTestCase() { @Test fun testNotSendingLocationWhenOnlyMicCamera() { - changeAll(false) + changeLocation(false) changeMicCamera(true) executor.runAllReady() @@ -294,7 +293,7 @@ class PrivacyItemControllerTest : SysuiTestCase() { .`when`(appOpsController).getActiveAppOpsForUser(anyInt()) privacyItemController.addCallback(callback) - changeAll(false) + changeLocation(false) changeMicCamera(true) executor.runAllReady() reset(callback) // Clean callback @@ -521,7 +520,7 @@ class PrivacyItemControllerTest : SysuiTestCase() { } private fun changeMicCamera(value: Boolean?) = changeProperty(MIC_CAMERA, value) - private fun changeAll(value: Boolean?) = changeProperty(ALL_INDICATORS, value) + private fun changeLocation(value: Boolean?) = changeProperty(LOCATION_INDICATOR, value) private fun changeProperty(name: String, value: Boolean?) { deviceConfigProxy.setProperty( diff --git a/packages/SystemUI/tests/src/com/android/systemui/qs/QuickStatusBarHeaderControllerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/qs/QuickStatusBarHeaderControllerTest.kt index 97a845916185..4948c2b18746 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/qs/QuickStatusBarHeaderControllerTest.kt +++ b/packages/SystemUI/tests/src/com/android/systemui/qs/QuickStatusBarHeaderControllerTest.kt @@ -148,7 +148,7 @@ class QuickStatusBarHeaderControllerTest : SysuiTestCase() { @Test fun testIgnoredSlotsOnAttached_noIndicators() { - setPrivacyController(false, false, false) + setPrivacyController(micCamera = false, location = false) controller.init() @@ -160,7 +160,7 @@ class QuickStatusBarHeaderControllerTest : SysuiTestCase() { @Test fun testIgnoredSlotsOnAttached_onlyMicCamera() { - setPrivacyController(false, true, false) + setPrivacyController(micCamera = true, location = false) controller.init() @@ -177,7 +177,7 @@ class QuickStatusBarHeaderControllerTest : SysuiTestCase() { @Test fun testIgnoredSlotsOnAttached_onlyLocation() { - setPrivacyController(false, false, true) + setPrivacyController(micCamera = false, location = true) controller.init() @@ -192,26 +192,7 @@ class QuickStatusBarHeaderControllerTest : SysuiTestCase() { @Test fun testIgnoredSlotsOnAttached_locationMicCamera() { - setPrivacyController(false, true, true) - - controller.init() - - val captor = argumentCaptor<List<String>>() - verify(iconContainer).setIgnoredSlots(capture(captor)) - - val cameraString = mContext.resources.getString( - com.android.internal.R.string.status_bar_camera) - val micString = mContext.resources.getString( - com.android.internal.R.string.status_bar_microphone) - val locationString = mContext.resources.getString( - com.android.internal.R.string.status_bar_location) - - assertThat(captor.value).containsExactly(cameraString, micString, locationString) - } - - @Test - fun testIgnoredSlotsOnAttached_all() { - setPrivacyController(true, false, false) + setPrivacyController(micCamera = true, location = true) controller.init() @@ -248,8 +229,7 @@ class QuickStatusBarHeaderControllerTest : SysuiTestCase() { `when`(view.findViewById<Clock>(R.id.clock)).thenReturn(clock) } - private fun setPrivacyController(all: Boolean, micCamera: Boolean, location: Boolean) { - `when`(privacyItemController.allIndicatorsAvailable).thenReturn(all) + private fun setPrivacyController(micCamera: Boolean, location: Boolean) { `when`(privacyItemController.micCameraAvailable).thenReturn(micCamera) `when`(privacyItemController.locationAvailable).thenReturn(location) } diff --git a/packages/SystemUI/tests/src/com/android/systemui/recents/OverviewProxyServiceTest.java b/packages/SystemUI/tests/src/com/android/systemui/recents/OverviewProxyServiceTest.java deleted file mode 100644 index 25104b8b1d20..000000000000 --- a/packages/SystemUI/tests/src/com/android/systemui/recents/OverviewProxyServiceTest.java +++ /dev/null @@ -1,123 +0,0 @@ -/* - * Copyright (C) 2020 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.android.systemui.recents; - -import static android.content.pm.PackageManager.FEATURE_PICTURE_IN_PICTURE; - -import static org.mockito.ArgumentMatchers.any; -import static org.mockito.Mockito.never; -import static org.mockito.Mockito.spy; -import static org.mockito.Mockito.verify; -import static org.mockito.Mockito.when; - -import android.content.pm.PackageManager; -import android.os.RemoteException; -import android.test.suitebuilder.annotation.SmallTest; -import android.testing.AndroidTestingRunner; -import android.testing.TestableContext; -import android.testing.TestableLooper; - -import com.android.systemui.SysuiTestCase; -import com.android.systemui.broadcast.BroadcastDispatcher; -import com.android.systemui.model.SysUiState; -import com.android.systemui.navigationbar.NavigationBarController; -import com.android.systemui.navigationbar.NavigationModeController; -import com.android.systemui.shared.recents.IPinnedStackAnimationListener; -import com.android.systemui.statusbar.CommandQueue; -import com.android.systemui.statusbar.NotificationShadeWindowController; -import com.android.systemui.statusbar.phone.StatusBar; -import com.android.wm.shell.legacysplitscreen.LegacySplitScreen; -import com.android.wm.shell.pip.Pip; -import com.android.wm.shell.splitscreen.SplitScreen; -import com.android.wm.shell.startingsurface.StartingSurface; -import com.android.wm.shell.transition.RemoteTransitions; - -import org.junit.Before; -import org.junit.Test; -import org.junit.runner.RunWith; -import org.mockito.Mock; -import org.mockito.MockitoAnnotations; - -import java.util.Optional; - -import dagger.Lazy; - -/** - * Unit tests for {@link com.android.systemui.recents.OverviewProxyService} - */ -@SmallTest -@RunWith(AndroidTestingRunner.class) -@TestableLooper.RunWithLooper -public class OverviewProxyServiceTest extends SysuiTestCase { - private OverviewProxyService mSpiedOverviewProxyService; - private TestableContext mSpiedContext; - - @Mock private BroadcastDispatcher mMockBroadcastDispatcher; - @Mock private CommandQueue mMockCommandQueue; - @Mock private Lazy<NavigationBarController> mMockNavBarControllerLazy; - @Mock private IPinnedStackAnimationListener mMockPinnedStackAnimationListener; - @Mock private NavigationModeController mMockNavModeController; - @Mock private NotificationShadeWindowController mMockStatusBarWinController; - @Mock private Optional<Pip> mMockPipOptional; - @Mock private Optional<LegacySplitScreen> mMockLegacySplitScreenOptional; - @Mock private Optional<SplitScreen> mMockSplitScreenOptional; - @Mock private Optional<Lazy<StatusBar>> mMockStatusBarOptionalLazy; - @Mock private Optional<com.android.wm.shell.onehanded.OneHanded> mMockOneHandedOptional; - @Mock private PackageManager mPackageManager; - @Mock private SysUiState mMockSysUiState; - @Mock private RemoteTransitions mMockTransitions; - @Mock private Optional<StartingSurface> mStartingSurface; - - @Before - public void setUp() throws RemoteException { - MockitoAnnotations.initMocks(this); - - mSpiedContext = spy(mContext); - - when(mPackageManager.hasSystemFeature(FEATURE_PICTURE_IN_PICTURE)).thenReturn(false); - when(mSpiedContext.getPackageManager()).thenReturn(mPackageManager); - - mSpiedOverviewProxyService = spy(new OverviewProxyService(mSpiedContext, mMockCommandQueue, - mMockNavBarControllerLazy, mMockNavModeController, mMockStatusBarWinController, - mMockSysUiState, mMockPipOptional, mMockLegacySplitScreenOptional, - mMockSplitScreenOptional, mMockStatusBarOptionalLazy, mMockOneHandedOptional, - mMockBroadcastDispatcher, mMockTransitions, mStartingSurface)); - } - - @Test - public void testNonPipDevice_shouldNotNotifySwipeToHomeFinished() throws RemoteException { - mSpiedOverviewProxyService.mSysUiProxy.notifySwipeToHomeFinished(); - - verify(mMockPipOptional, never()).ifPresent(any()); - } - - @Test - public void testNonPipDevice_shouldNotSetPinnedStackAnimationListener() throws RemoteException { - mSpiedOverviewProxyService.mSysUiProxy.setPinnedStackAnimationListener( - mMockPinnedStackAnimationListener); - - verify(mMockPipOptional, never()).ifPresent(any()); - } - - @Test - public void testNonPipDevice_shouldNotSetShelfHeight() throws RemoteException { - mSpiedOverviewProxyService.mSysUiProxy.setShelfHeight(true /* visible */, - 100 /* shelfHeight */); - - verify(mMockPipOptional, never()).ifPresent(any()); - } -} diff --git a/services/core/java/com/android/server/BatteryService.java b/services/core/java/com/android/server/BatteryService.java index fbfde436a16f..1e608f5c1240 100644 --- a/services/core/java/com/android/server/BatteryService.java +++ b/services/core/java/com/android/server/BatteryService.java @@ -1595,6 +1595,8 @@ public final class BatteryService extends SystemService { if (Objects.equals(newService, oldService)) return; Slog.i(TAG, "health: new instance registered " + mInstanceName); + // #init() may be called with null callback. Skip null callbacks. + if (mCallback == null) return; mCallback.onRegistration(oldService, newService, mInstanceName); } catch (NoSuchElementException | RemoteException ex) { Slog.e(TAG, "health: Cannot get instance '" + mInstanceName diff --git a/services/core/java/com/android/server/OWNERS b/services/core/java/com/android/server/OWNERS index e12586bfdc06..c9836001da77 100644 --- a/services/core/java/com/android/server/OWNERS +++ b/services/core/java/com/android/server/OWNERS @@ -18,6 +18,7 @@ per-file ServiceWatcher.java = sooniln@google.com per-file *Alarm* = file:/apex/jobscheduler/OWNERS per-file *AppOp* = file:/core/java/android/permission/OWNERS +per-file *Battery* = file:/BATTERY_STATS_OWNERS per-file *Bluetooth* = file:/core/java/android/bluetooth/OWNERS per-file *Gnss* = file:/services/core/java/com/android/server/location/OWNERS per-file *Location* = file:/services/core/java/com/android/server/location/OWNERS diff --git a/services/core/java/com/android/server/TelephonyRegistry.java b/services/core/java/com/android/server/TelephonyRegistry.java index a9904ba0de91..5adbdff150ea 100644 --- a/services/core/java/com/android/server/TelephonyRegistry.java +++ b/services/core/java/com/android/server/TelephonyRegistry.java @@ -318,7 +318,8 @@ public class TelephonyRegistry extends ITelephonyRegistry.Stub { private int[] mDataEnabledReason; - private Map<Integer, Long> mAllowedNetworkTypesList; + private int[] mAllowedNetworkTypeReason; + private long[] mAllowedNetworkTypeValue; /** * Per-phone map of precise data connection state. The key of the map is the pair of transport @@ -383,7 +384,8 @@ public class TelephonyRegistry extends ITelephonyRegistry.Stub { private boolean isPrivilegedPhoneStatePermissionRequired(Set<Integer> events) { return events.contains(TelephonyCallback.EVENT_SRVCC_STATE_CHANGED) || events.contains(TelephonyCallback.EVENT_VOICE_ACTIVATION_STATE_CHANGED) - || events.contains(TelephonyCallback.EVENT_RADIO_POWER_STATE_CHANGED); + || events.contains(TelephonyCallback.EVENT_RADIO_POWER_STATE_CHANGED) + || events.contains(TelephonyCallback.EVENT_ALLOWED_NETWORK_TYPE_LIST_CHANGED); } private static final int MSG_USER_SWITCHED = 1; @@ -527,6 +529,8 @@ public class TelephonyRegistry extends ITelephonyRegistry.Stub { mTelephonyDisplayInfos = copyOf(mTelephonyDisplayInfos, mNumPhones); mIsDataEnabled= copyOf(mIsDataEnabled, mNumPhones); mDataEnabledReason = copyOf(mDataEnabledReason, mNumPhones); + mAllowedNetworkTypeReason = copyOf(mAllowedNetworkTypeReason, mNumPhones); + mAllowedNetworkTypeValue = copyOf(mAllowedNetworkTypeValue, mNumPhones); // ds -> ss switch. if (mNumPhones < oldNumPhones) { @@ -571,6 +575,8 @@ public class TelephonyRegistry extends ITelephonyRegistry.Stub { mIsDataEnabled[i] = false; mDataEnabledReason[i] = TelephonyManager.DATA_ENABLED_REASON_USER; mPhysicalChannelConfigs.add(i, new PhysicalChannelConfig.Builder().build()); + mAllowedNetworkTypeReason[i] = -1; + mAllowedNetworkTypeValue[i] = -1; } } @@ -630,9 +636,11 @@ public class TelephonyRegistry extends ITelephonyRegistry.Stub { mBarringInfo = new ArrayList<>(); mTelephonyDisplayInfos = new TelephonyDisplayInfo[numPhones]; mPhysicalChannelConfigs = new ArrayList<>(); - mAllowedNetworkTypesList = new HashMap<>(); + mAllowedNetworkTypeReason = new int[numPhones]; + mAllowedNetworkTypeValue = new long[numPhones]; mIsDataEnabled = new boolean[numPhones]; mDataEnabledReason = new int[numPhones]; + for (int i = 0; i < numPhones; i++) { mCallState[i] = TelephonyManager.CALL_STATE_IDLE; mDataActivity[i] = TelephonyManager.DATA_ACTIVITY_NONE; @@ -665,6 +673,8 @@ public class TelephonyRegistry extends ITelephonyRegistry.Stub { mIsDataEnabled[i] = false; mDataEnabledReason[i] = TelephonyManager.DATA_ENABLED_REASON_USER; mPhysicalChannelConfigs.add(i, new PhysicalChannelConfig.Builder().build()); + mAllowedNetworkTypeReason[i] = -1; + mAllowedNetworkTypeValue[i] = -1; } mAppOps = mContext.getSystemService(AppOpsManager.class); @@ -1172,14 +1182,6 @@ public class TelephonyRegistry extends ITelephonyRegistry.Stub { remove(r.binder); } } - if (events.contains( - TelephonyCallback.EVENT_ALLOWED_NETWORK_TYPE_LIST_CHANGED)) { - try { - r.callback.onAllowedNetworkTypesChanged(mAllowedNetworkTypesList); - } catch (RemoteException ex) { - remove(r.binder); - } - } } } } @@ -2454,18 +2456,19 @@ public class TelephonyRegistry extends ITelephonyRegistry.Stub { * * @param phoneId the phone id. * @param subId the subId. - * @param allowedNetworkTypesList Map associating all allowed network type reasons with reason's - * allowed network type values. + * @param reason the allowed network type reason. + * @param allowedNetworkType the allowed network type value. */ - public void notifyAllowedNetworkTypesChanged(int phoneId, int subId, - Map allowedNetworkTypesList) { + public void notifyAllowedNetworkTypesChanged(int phoneId, int subId, int reason, + long allowedNetworkType) { if (!checkNotifyPermission("notifyAllowedNetworkTypesChanged()")) { return; } synchronized (mRecords) { if (validatePhoneId(phoneId)) { - mAllowedNetworkTypesList = allowedNetworkTypesList; + mAllowedNetworkTypeReason[phoneId] = reason; + mAllowedNetworkTypeValue[phoneId] = allowedNetworkType; for (Record r : mRecords) { if (r.matchTelephonyCallbackEvent( @@ -2473,10 +2476,12 @@ public class TelephonyRegistry extends ITelephonyRegistry.Stub { && idMatch(r.subId, subId, phoneId)) { try { if (VDBG) { - log("notifyAllowedNetworkTypesChanged: AllowedNetworkTypesList= " - + mAllowedNetworkTypesList.toString()); + log("notifyAllowedNetworkTypesChanged: reason= " + reason + + ", allowed network type:" + + TelephonyManager.convertNetworkTypeBitmaskToString( + allowedNetworkType)); } - r.callback.onAllowedNetworkTypesChanged(mAllowedNetworkTypesList); + r.callback.onAllowedNetworkTypesChanged(reason, allowedNetworkType); } catch (RemoteException ex) { mRemoveList.add(r.binder); } @@ -2531,6 +2536,8 @@ public class TelephonyRegistry extends ITelephonyRegistry.Stub { pw.println("mTelephonyDisplayInfo=" + mTelephonyDisplayInfos[i]); pw.println("mIsDataEnabled=" + mIsDataEnabled); pw.println("mDataEnabledReason=" + mDataEnabledReason); + pw.println("mAllowedNetworkTypeReason=" + mAllowedNetworkTypeReason[i]); + pw.println("mAllowedNetworkTypeValue=" + mAllowedNetworkTypeValue[i]); pw.decreaseIndent(); } pw.println("mCarrierNetworkChangeState=" + mCarrierNetworkChangeState); diff --git a/services/core/java/com/android/server/VcnManagementService.java b/services/core/java/com/android/server/VcnManagementService.java index cd3892da43e4..140f24f7cf8f 100644 --- a/services/core/java/com/android/server/VcnManagementService.java +++ b/services/core/java/com/android/server/VcnManagementService.java @@ -666,6 +666,10 @@ public class VcnManagementService extends IVcnManagementService.Stub { @NonNull IVcnUnderlyingNetworkPolicyListener listener) { requireNonNull(listener, "listener was null"); + mContext.enforceCallingOrSelfPermission( + android.Manifest.permission.NETWORK_FACTORY, + "Must have permission NETWORK_FACTORY to unregister a policy listener"); + Binder.withCleanCallingIdentity(() -> { synchronized (mLock) { PolicyListenerBinderDeath listenerBinderDeath = diff --git a/services/core/java/com/android/server/app/GameManagerSettings.java b/services/core/java/com/android/server/app/GameManagerSettings.java index 3e32380b60a9..2982545a5e6f 100644 --- a/services/core/java/com/android/server/app/GameManagerSettings.java +++ b/services/core/java/com/android/server/app/GameManagerSettings.java @@ -137,6 +137,11 @@ public class GameManagerSettings { boolean readPersistentDataLocked() { mGameModes.clear(); + if (!mSettingsFile.exists()) { + Slog.v(GameManagerService.TAG, "Settings file doesn't exists, skip reading"); + return false; + } + try { final FileInputStream str = mSettingsFile.openRead(); diff --git a/services/core/java/com/android/server/appop/AppOpsService.java b/services/core/java/com/android/server/appop/AppOpsService.java index 6614e06aba8c..1122f7f4115a 100644 --- a/services/core/java/com/android/server/appop/AppOpsService.java +++ b/services/core/java/com/android/server/appop/AppOpsService.java @@ -2098,26 +2098,28 @@ public class AppOpsService extends IAppOpsService.Stub { ensureHistoricalOpRequestIsValid(uid, packageName, attributionTag, opNames, filter, beginTimeMillis, endTimeMillis, flags); Objects.requireNonNull(callback, "callback cannot be null"); - ActivityManagerInternal ami = LocalServices.getService(ActivityManagerInternal.class); - boolean isCallerInstrumented = ami.isUidCurrentlyInstrumented(Binder.getCallingUid()); - boolean isCallerSystem = Binder.getCallingPid() == Process.myPid(); - boolean isCallerPermissionController; - try { - isCallerPermissionController = pm.getPackageUid( - mContext.getPackageManager().getPermissionControllerPackageName(), 0) - == Binder.getCallingUid(); - } catch (PackageManager.NameNotFoundException doesNotHappen) { - return; - } + boolean isSelfRequest = (filter & FILTER_BY_UID) != 0 && uid == Binder.getCallingUid(); + if (!isSelfRequest) { + boolean isCallerInstrumented = ami.isUidCurrentlyInstrumented(Binder.getCallingUid()); + boolean isCallerSystem = Binder.getCallingPid() == Process.myPid(); + boolean isCallerPermissionController; + try { + isCallerPermissionController = pm.getPackageUid( + mContext.getPackageManager().getPermissionControllerPackageName(), 0) + == Binder.getCallingUid(); + } catch (PackageManager.NameNotFoundException doesNotHappen) { + return; + } - if (!isCallerSystem && !isCallerInstrumented && !isCallerPermissionController) { - mHandler.post(() -> callback.sendResult(new Bundle())); - return; - } + if (!isCallerSystem && !isCallerInstrumented && !isCallerPermissionController) { + mHandler.post(() -> callback.sendResult(new Bundle())); + return; + } - mContext.enforcePermission(android.Manifest.permission.GET_APP_OPS_STATS, - Binder.getCallingPid(), Binder.getCallingUid(), "getHistoricalOps"); + mContext.enforcePermission(android.Manifest.permission.GET_APP_OPS_STATS, + Binder.getCallingPid(), Binder.getCallingUid(), "getHistoricalOps"); + } final String[] opNamesArray = (opNames != null) ? opNames.toArray(new String[opNames.size()]) : null; diff --git a/services/core/java/com/android/server/appop/DiscreteRegistry.java b/services/core/java/com/android/server/appop/DiscreteRegistry.java index ed62abc7d773..2b0157c88136 100644 --- a/services/core/java/com/android/server/appop/DiscreteRegistry.java +++ b/services/core/java/com/android/server/appop/DiscreteRegistry.java @@ -49,8 +49,6 @@ import com.android.internal.annotations.GuardedBy; import com.android.internal.util.ArrayUtils; import com.android.internal.util.XmlUtils; -import libcore.util.EmptyArray; - import java.io.File; import java.io.FileInputStream; import java.io.FileOutputStream; @@ -85,6 +83,8 @@ final class DiscreteRegistry { private static final String TAG = DiscreteRegistry.class.getSimpleName(); private static final long TIMELINE_HISTORY_CUTOFF = Duration.ofHours(24).toMillis(); + private static final long TIMELINE_QUANTIZATION = Duration.ofMinutes(1).toMillis(); + private static final String TAG_HISTORY = "h"; private static final String ATTR_VERSION = "v"; private static final int CURRENT_VERSION = 1; @@ -107,6 +107,8 @@ final class DiscreteRegistry { private static final String ATTR_UID_STATE = "us"; private static final String ATTR_FLAGS = "f"; + private static final int OP_FLAGS_DISCRETE = OP_FLAG_SELF | OP_FLAG_TRUSTED_PROXIED; + // Lock for read/write access to on disk state private final Object mOnDiskLock = new Object(); @@ -119,6 +121,9 @@ final class DiscreteRegistry { @GuardedBy("mInMemoryLock") private DiscreteOps mDiscreteOps; + @GuardedBy("mOnDiskLock") + private DiscreteOps mCachedOps = null; + DiscreteRegistry(Object inMemoryLock) { mInMemoryLock = inMemoryLock; mDiscreteAccessDir = new File(new File(Environment.getDataSystemDirectory(), "appops"), @@ -173,23 +178,25 @@ final class DiscreteRegistry { } } } - } - DiscreteOps discreteOps; - synchronized (mInMemoryLock) { - discreteOps = mDiscreteOps; - mDiscreteOps = new DiscreteOps(); - } - if (discreteOps.isEmpty()) { - return; - } - long currentTimeStamp = Instant.now().toEpochMilli(); - try { - final File file = new File(mDiscreteAccessDir, currentTimeStamp + TIMELINE_FILE_SUFFIX); - discreteOps.writeToFile(file); - } catch (Throwable t) { - Slog.e(TAG, - "Error writing timeline state: " + t.getMessage() + " " - + Arrays.toString(t.getStackTrace())); + DiscreteOps discreteOps; + synchronized (mInMemoryLock) { + discreteOps = mDiscreteOps; + mDiscreteOps = new DiscreteOps(); + mCachedOps = null; + } + if (discreteOps.isEmpty()) { + return; + } + long currentTimeStamp = Instant.now().toEpochMilli(); + try { + final File file = new File(mDiscreteAccessDir, + currentTimeStamp + TIMELINE_FILE_SUFFIX); + discreteOps.writeToFile(file); + } catch (Throwable t) { + Slog.e(TAG, + "Error writing timeline state: " + t.getMessage() + " " + + Arrays.toString(t.getStackTrace())); + } } } @@ -197,25 +204,33 @@ final class DiscreteRegistry { long endTimeMillis, @AppOpsManager.HistoricalOpsRequestFilter int filter, int uidFilter, @Nullable String packageNameFilter, @Nullable String[] opNamesFilter, @Nullable String attributionTagFilter, @AppOpsManager.OpFlags int flagsFilter) { - writeAndClearAccessHistory(); - DiscreteOps discreteOps = new DiscreteOps(); - readDiscreteOpsFromDisk(discreteOps, beginTimeMillis, endTimeMillis, filter, uidFilter, - packageNameFilter, opNamesFilter, attributionTagFilter, flagsFilter); + DiscreteOps discreteOps = getAndCacheDiscreteOps(); + discreteOps.filter(beginTimeMillis, endTimeMillis, filter, uidFilter, packageNameFilter, + opNamesFilter, attributionTagFilter, flagsFilter); discreteOps.applyToHistoricalOps(result); return; } - private void readDiscreteOpsFromDisk(DiscreteOps discreteOps, long beginTimeMillis, - long endTimeMillis, @AppOpsManager.HistoricalOpsRequestFilter int filter, int uidFilter, - @Nullable String packageNameFilter, @Nullable String[] opNamesFilter, - @Nullable String attributionTagFilter, @AppOpsManager.OpFlags int flagsFilter) { + private DiscreteOps getAndCacheDiscreteOps() { + DiscreteOps discreteOps = new DiscreteOps(); + synchronized (mOnDiskLock) { - long historyBeginTimeMillis = Instant.now().minus(TIMELINE_HISTORY_CUTOFF, - ChronoUnit.MILLIS).toEpochMilli(); - if (historyBeginTimeMillis > endTimeMillis) { - return; + synchronized (mInMemoryLock) { + discreteOps.merge(mDiscreteOps); + } + if (mCachedOps == null) { + mCachedOps = new DiscreteOps(); + readDiscreteOpsFromDisk(mCachedOps); } - beginTimeMillis = max(beginTimeMillis, historyBeginTimeMillis); + discreteOps.merge(mCachedOps); + } + return discreteOps; + } + + private void readDiscreteOpsFromDisk(DiscreteOps discreteOps) { + synchronized (mOnDiskLock) { + long beginTimeMillis = Instant.now().minus(TIMELINE_HISTORY_CUTOFF, + ChronoUnit.MILLIS).toEpochMilli(); final File[] files = mDiscreteAccessDir.listFiles(); if (files != null && files.length > 0) { @@ -229,8 +244,7 @@ final class DiscreteRegistry { if (timestamp < beginTimeMillis) { continue; } - discreteOps.readFromFile(f, beginTimeMillis, endTimeMillis, filter, uidFilter, - packageNameFilter, opNamesFilter, attributionTagFilter, flagsFilter); + discreteOps.readFromFile(f, beginTimeMillis); } } } @@ -251,15 +265,11 @@ final class DiscreteRegistry { @AppOpsManager.HistoricalOpsRequestFilter int filter, int dumpOp, @NonNull SimpleDateFormat sdf, @NonNull Date date, @NonNull String prefix, int nDiscreteOps) { - DiscreteOps discreteOps = new DiscreteOps(); - synchronized (mOnDiskLock) { - writeAndClearAccessHistory(); - String[] opNamesFilter = dumpOp == OP_NONE ? EmptyArray.STRING - : new String[]{AppOpsManager.opToPublicName(dumpOp)}; - readDiscreteOpsFromDisk(discreteOps, 0, Instant.now().toEpochMilli(), filter, - uidFilter, packageNameFilter, opNamesFilter, attributionTagFilter, - OP_FLAGS_ALL); - } + DiscreteOps discreteOps = getAndCacheDiscreteOps(); + String[] opNamesFilter = dumpOp == OP_NONE ? null + : new String[]{AppOpsManager.opToPublicName(dumpOp)}; + discreteOps.filter(0, Instant.now().toEpochMilli(), filter, uidFilter, packageNameFilter, + opNamesFilter, attributionTagFilter, OP_FLAGS_ALL); discreteOps.dump(pw, sdf, date, prefix, nDiscreteOps); } @@ -270,7 +280,7 @@ final class DiscreteRegistry { if (!isDiscreteUid(uid)) { return false; } - if ((flags & (OP_FLAG_SELF | OP_FLAG_TRUSTED_PROXIED)) == 0) { + if ((flags & (OP_FLAGS_DISCRETE)) == 0) { return false; } return true; @@ -298,6 +308,19 @@ final class DiscreteRegistry { mUids = new ArrayMap<>(); } + boolean isEmpty() { + return mUids.isEmpty(); + } + + void merge(DiscreteOps other) { + int nUids = other.mUids.size(); + for (int i = 0; i < nUids; i++) { + int uid = other.mUids.keyAt(i); + DiscreteUidOps uidOps = other.mUids.valueAt(i); + getOrCreateDiscreteUidOps(uid).merge(uidOps); + } + } + void addDiscreteAccess(int op, int uid, @NonNull String packageName, @Nullable String attributionTag, @AppOpsManager.OpFlags int flags, @AppOpsManager.UidState int uidState, long accessTime, long accessDuration) { @@ -305,6 +328,25 @@ final class DiscreteRegistry { uidState, accessTime, accessDuration); } + private void filter(long beginTimeMillis, long endTimeMillis, + @AppOpsManager.HistoricalOpsRequestFilter int filter, int uidFilter, + @Nullable String packageNameFilter, @Nullable String[] opNamesFilter, + @Nullable String attributionTagFilter, @AppOpsManager.OpFlags int flagsFilter) { + if ((filter & FILTER_BY_UID) != 0) { + ArrayMap<Integer, DiscreteUidOps> uids = new ArrayMap<>(); + uids.put(uidFilter, getOrCreateDiscreteUidOps(uidFilter)); + mUids = uids; + } + int nUids = mUids.size(); + for (int i = nUids - 1; i >= 0; i--) { + mUids.valueAt(i).filter(beginTimeMillis, endTimeMillis, filter, packageNameFilter, + opNamesFilter, attributionTagFilter, flagsFilter); + if (mUids.valueAt(i).isEmpty()) { + mUids.removeAt(i); + } + } + } + private void applyToHistoricalOps(AppOpsManager.HistoricalOps result) { int nUids = mUids.size(); for (int i = 0; i < nUids; i++) { @@ -353,14 +395,7 @@ final class DiscreteRegistry { return result; } - boolean isEmpty() { - return mUids.isEmpty(); - } - - private void readFromFile(File f, long beginTimeMillis, long endTimeMillis, - @AppOpsManager.HistoricalOpsRequestFilter int filter, - int uidFilter, @Nullable String packageNameFilter, @Nullable String[] opNamesFilter, - @Nullable String attributionTagFilter, @AppOpsManager.OpFlags int flagsFilter) { + private void readFromFile(File f, long beginTimeMillis) { try { FileInputStream stream = new FileInputStream(f); TypedXmlPullParser parser = Xml.resolvePullParser(stream); @@ -377,12 +412,7 @@ final class DiscreteRegistry { while (XmlUtils.nextElementWithin(parser, depth)) { if (TAG_UID.equals(parser.getName())) { int uid = parser.getAttributeInt(null, ATTR_UID, -1); - if ((filter & FILTER_BY_UID) != 0 && uid != uidFilter) { - continue; - } - getOrCreateDiscreteUidOps(uid).deserialize(parser, beginTimeMillis, - endTimeMillis, filter, packageNameFilter, opNamesFilter, - attributionTagFilter, flagsFilter); + getOrCreateDiscreteUidOps(uid).deserialize(parser, beginTimeMillis); } } } catch (Throwable t) { @@ -400,6 +430,38 @@ final class DiscreteRegistry { mPackages = new ArrayMap<>(); } + boolean isEmpty() { + return mPackages.isEmpty(); + } + + void merge(DiscreteUidOps other) { + int nPackages = other.mPackages.size(); + for (int i = 0; i < nPackages; i++) { + String packageName = other.mPackages.keyAt(i); + DiscretePackageOps p = other.mPackages.valueAt(i); + getOrCreateDiscretePackageOps(packageName).merge(p); + } + } + + private void filter(long beginTimeMillis, long endTimeMillis, + @AppOpsManager.HistoricalOpsRequestFilter int filter, + @Nullable String packageNameFilter, @Nullable String[] opNamesFilter, + @Nullable String attributionTagFilter, @AppOpsManager.OpFlags int flagsFilter) { + if ((filter & FILTER_BY_PACKAGE_NAME) != 0) { + ArrayMap<String, DiscretePackageOps> packages = new ArrayMap<>(); + packages.put(packageNameFilter, getOrCreateDiscretePackageOps(packageNameFilter)); + mPackages = packages; + } + int nPackages = mPackages.size(); + for (int i = nPackages - 1; i >= 0; i--) { + mPackages.valueAt(i).filter(beginTimeMillis, endTimeMillis, filter, opNamesFilter, + attributionTagFilter, flagsFilter); + if (mPackages.valueAt(i).isEmpty()) { + mPackages.removeAt(i); + } + } + } + void addDiscreteAccess(int op, @NonNull String packageName, @Nullable String attributionTag, @AppOpsManager.OpFlags int flags, @AppOpsManager.UidState int uidState, long accessTime, long accessDuration) { @@ -445,22 +507,12 @@ final class DiscreteRegistry { } } - void deserialize(TypedXmlPullParser parser, long beginTimeMillis, - long endTimeMillis, @AppOpsManager.HistoricalOpsRequestFilter int filter, - @Nullable String packageNameFilter, - @Nullable String[] opNamesFilter, @Nullable String attributionTagFilter, - @AppOpsManager.OpFlags int flagsFilter) throws Exception { + void deserialize(TypedXmlPullParser parser, long beginTimeMillis) throws Exception { int depth = parser.getDepth(); while (XmlUtils.nextElementWithin(parser, depth)) { if (TAG_PACKAGE.equals(parser.getName())) { String packageName = parser.getAttributeValue(null, ATTR_PACKAGE_NAME); - if ((filter & FILTER_BY_PACKAGE_NAME) != 0 - && !packageName.equals(packageNameFilter)) { - continue; - } - getOrCreateDiscretePackageOps(packageName).deserialize(parser, beginTimeMillis, - endTimeMillis, filter, opNamesFilter, attributionTagFilter, - flagsFilter); + getOrCreateDiscretePackageOps(packageName).deserialize(parser, beginTimeMillis); } } } @@ -473,6 +525,10 @@ final class DiscreteRegistry { mPackageOps = new ArrayMap<>(); } + boolean isEmpty() { + return mPackageOps.isEmpty(); + } + void addDiscreteAccess(int op, @Nullable String attributionTag, @AppOpsManager.OpFlags int flags, @AppOpsManager.UidState int uidState, long accessTime, long accessDuration) { @@ -480,6 +536,35 @@ final class DiscreteRegistry { accessDuration); } + void merge(DiscretePackageOps other) { + int nOps = other.mPackageOps.size(); + for (int i = 0; i < nOps; i++) { + int opId = other.mPackageOps.keyAt(i); + DiscreteOp op = other.mPackageOps.valueAt(i); + getOrCreateDiscreteOp(opId).merge(op); + } + } + + private void filter(long beginTimeMillis, long endTimeMillis, + @AppOpsManager.HistoricalOpsRequestFilter int filter, + @Nullable String[] opNamesFilter, @Nullable String attributionTagFilter, + @AppOpsManager.OpFlags int flagsFilter) { + int nOps = mPackageOps.size(); + for (int i = nOps - 1; i >= 0; i--) { + int opId = mPackageOps.keyAt(i); + if ((filter & FILTER_BY_OP_NAMES) != 0 && !ArrayUtils.contains(opNamesFilter, + AppOpsManager.opToPublicName(opId))) { + mPackageOps.removeAt(i); + continue; + } + mPackageOps.valueAt(i).filter(beginTimeMillis, endTimeMillis, filter, + attributionTagFilter, flagsFilter); + if (mPackageOps.valueAt(i).isEmpty()) { + mPackageOps.removeAt(i); + } + } + } + private DiscreteOp getOrCreateDiscreteOp(int op) { DiscreteOp result = mPackageOps.get(op); if (result == null) { @@ -519,20 +604,12 @@ final class DiscreteRegistry { } } - void deserialize(TypedXmlPullParser parser, long beginTimeMillis, long endTimeMillis, - @AppOpsManager.HistoricalOpsRequestFilter int filter, - @Nullable String[] opNamesFilter, @Nullable String attributionTagFilter, - @AppOpsManager.OpFlags int flagsFilter) throws Exception { + void deserialize(TypedXmlPullParser parser, long beginTimeMillis) throws Exception { int depth = parser.getDepth(); while (XmlUtils.nextElementWithin(parser, depth)) { if (TAG_OP.equals(parser.getName())) { int op = parser.getAttributeInt(null, ATTR_OP_ID); - if ((filter & FILTER_BY_OP_NAMES) != 0 && !ArrayUtils.contains(opNamesFilter, - AppOpsManager.opToPublicName(op))) { - continue; - } - getOrCreateDiscreteOp(op).deserialize(parser, beginTimeMillis, endTimeMillis, - filter, attributionTagFilter, flagsFilter); + getOrCreateDiscreteOp(op).deserialize(parser, beginTimeMillis); } } } @@ -545,31 +622,66 @@ final class DiscreteRegistry { mAttributedOps = new ArrayMap<>(); } + boolean isEmpty() { + return mAttributedOps.isEmpty(); + } + + void merge(DiscreteOp other) { + int nTags = other.mAttributedOps.size(); + for (int i = 0; i < nTags; i++) { + String tag = other.mAttributedOps.keyAt(i); + List<DiscreteOpEvent> otherEvents = other.mAttributedOps.valueAt(i); + List<DiscreteOpEvent> events = getOrCreateDiscreteOpEventsList(tag); + mAttributedOps.put(tag, stableListMerge(events, otherEvents)); + } + } + + private void filter(long beginTimeMillis, long endTimeMillis, + @AppOpsManager.HistoricalOpsRequestFilter int filter, + @Nullable String attributionTagFilter, @AppOpsManager.OpFlags int flagsFilter) { + if ((filter & FILTER_BY_ATTRIBUTION_TAG) != 0) { + ArrayMap<String, List<DiscreteOpEvent>> attributedOps = new ArrayMap<>(); + attributedOps.put(attributionTagFilter, + getOrCreateDiscreteOpEventsList(attributionTagFilter)); + mAttributedOps = attributedOps; + } + + int nTags = mAttributedOps.size(); + for (int i = nTags - 1; i >= 0; i--) { + String tag = mAttributedOps.keyAt(i); + List<DiscreteOpEvent> list = mAttributedOps.valueAt(i); + list = filterEventsList(list, beginTimeMillis, endTimeMillis, flagsFilter); + mAttributedOps.put(tag, list); + if (list.size() == 0) { + mAttributedOps.removeAt(i); + } + } + } + void addDiscreteAccess(@Nullable String attributionTag, @AppOpsManager.OpFlags int flags, @AppOpsManager.UidState int uidState, long accessTime, long accessDuration) { List<DiscreteOpEvent> attributedOps = getOrCreateDiscreteOpEventsList( attributionTag); - accessTime = Instant.ofEpochMilli(accessTime).truncatedTo( - ChronoUnit.MINUTES).toEpochMilli(); + accessTime = accessTime / TIMELINE_QUANTIZATION * TIMELINE_QUANTIZATION; int nAttributedOps = attributedOps.size(); - for (int i = nAttributedOps - 1; i >= 0; i--) { - DiscreteOpEvent previousOp = attributedOps.get(i); - if (i == nAttributedOps - 1 && previousOp.mNoteTime == accessTime - && accessDuration > -1) { - // existing event with updated duration - attributedOps.remove(i); - break; - } + int i = nAttributedOps; + for (; i > 0; i--) { + DiscreteOpEvent previousOp = attributedOps.get(i - 1); if (previousOp.mNoteTime < accessTime) { break; } if (previousOp.mOpFlag == flags && previousOp.mUidState == uidState) { - return; + if (accessDuration != previousOp.mNoteDuration + && accessDuration > TIMELINE_QUANTIZATION) { + break; + } else { + return; + } } } - attributedOps.add(new DiscreteOpEvent(accessTime, accessDuration, uidState, flags)); + attributedOps.add(i, new DiscreteOpEvent(accessTime, accessDuration, uidState, flags)); } private List<DiscreteOpEvent> getOrCreateDiscreteOpEventsList(String attributionTag) { @@ -633,18 +745,11 @@ final class DiscreteRegistry { } } - void deserialize(TypedXmlPullParser parser, long beginTimeMillis, long endTimeMillis, - @AppOpsManager.HistoricalOpsRequestFilter int filter, - @Nullable String attributionTagFilter, - @AppOpsManager.OpFlags int flagsFilter) throws Exception { + void deserialize(TypedXmlPullParser parser, long beginTimeMillis) throws Exception { int outerDepth = parser.getDepth(); while (XmlUtils.nextElementWithin(parser, outerDepth)) { if (TAG_TAG.equals(parser.getName())) { String attributionTag = parser.getAttributeValue(null, ATTR_TAG); - if ((filter & FILTER_BY_ATTRIBUTION_TAG) != 0 && !attributionTag.equals( - attributionTagFilter)) { - continue; - } List<DiscreteOpEvent> events = getOrCreateDiscreteOpEventsList( attributionTag); int innerDepth = parser.getDepth(); @@ -655,11 +760,7 @@ final class DiscreteRegistry { -1); int uidState = parser.getAttributeInt(null, ATTR_UID_STATE); int opFlags = parser.getAttributeInt(null, ATTR_FLAGS); - if ((flagsFilter & opFlags) == 0) { - continue; - } - if ((noteTime + noteDuration < beginTimeMillis - && noteTime > endTimeMillis)) { + if (noteTime + noteDuration < beginTimeMillis) { continue; } DiscreteOpEvent event = new DiscreteOpEvent(noteTime, noteDuration, @@ -715,5 +816,41 @@ final class DiscreteRegistry { out.attributeInt(null, ATTR_FLAGS, mOpFlag); } } + + private static List<DiscreteOpEvent> stableListMerge(List<DiscreteOpEvent> a, + List<DiscreteOpEvent> b) { + int nA = a.size(); + int nB = b.size(); + int i = 0; + int k = 0; + List<DiscreteOpEvent> result = new ArrayList<>(nA + nB); + while (i < nA || k < nB) { + if (i == nA) { + result.add(b.get(k++)); + } else if (k == nB) { + result.add(a.get(i++)); + } else if (a.get(i).mNoteTime < b.get(k).mNoteTime) { + result.add(a.get(i++)); + } else { + result.add(b.get(k++)); + } + } + return result; + } + + private static List<DiscreteOpEvent> filterEventsList(List<DiscreteOpEvent> list, + long beginTimeMillis, long endTimeMillis, @AppOpsManager.OpFlags int flagsFilter) { + int n = list.size(); + List<DiscreteOpEvent> result = new ArrayList<>(n); + for (int i = 0; i < n; i++) { + DiscreteOpEvent event = list.get(i); + if ((event.mOpFlag & flagsFilter) != 0 + && event.mNoteTime + event.mNoteDuration > beginTimeMillis + && event.mNoteTime < endTimeMillis) { + result.add(event); + } + } + return result; + } } diff --git a/services/core/java/com/android/server/appop/HistoricalRegistry.java b/services/core/java/com/android/server/appop/HistoricalRegistry.java index 22d628b8e789..4435c4795730 100644 --- a/services/core/java/com/android/server/appop/HistoricalRegistry.java +++ b/services/core/java/com/android/server/appop/HistoricalRegistry.java @@ -532,7 +532,7 @@ final class HistoricalRegistry { System.currentTimeMillis()).increaseAccessDuration(op, uid, packageName, attributionTag, uidState, flags, increment); mDiscreteRegistry.recordDiscreteAccess(uid, packageName, op, attributionTag, - flags, uidState, increment, eventStartTime); + flags, uidState, eventStartTime, increment); } } } @@ -795,7 +795,7 @@ final class HistoricalRegistry { private static boolean isApiEnabled() { return Binder.getCallingUid() == Process.myUid() || DeviceConfig.getBoolean(DeviceConfig.NAMESPACE_PRIVACY, - PROPERTY_PERMISSIONS_HUB_ENABLED, false); + PROPERTY_PERMISSIONS_HUB_ENABLED, true); } private static final class Persistence { diff --git a/services/core/java/com/android/server/inputmethod/InputMethodManagerService.java b/services/core/java/com/android/server/inputmethod/InputMethodManagerService.java index 672ed3d00344..6ab4a69eaf65 100644 --- a/services/core/java/com/android/server/inputmethod/InputMethodManagerService.java +++ b/services/core/java/com/android/server/inputmethod/InputMethodManagerService.java @@ -2621,9 +2621,8 @@ public class InputMethodManagerService extends IInputMethodManager.Stub } if (DEBUG) Slog.v(TAG, "Initiating attach with token: " + mCurToken); // Dispatch display id for InputMethodService to update context display. - executeOrSendMessage(mCurMethod, mCaller.obtainMessageIOOO( - MSG_INITIALIZE_IME, mCurTokenDisplayId, mCurMethod, mCurToken, - mMethodMap.get(mCurMethodId).getConfigChanges())); + executeOrSendMessage(mCurMethod, mCaller.obtainMessageIOO( + MSG_INITIALIZE_IME, mCurTokenDisplayId, mCurMethod, mCurToken)); scheduleNotifyImeUidToAudioService(mCurMethodUid); if (mCurClient != null) { clearClientSessionLocked(mCurClient); @@ -4479,8 +4478,7 @@ public class InputMethodManagerService extends IInputMethodManager.Stub } final IBinder token = (IBinder) args.arg2; ((IInputMethod) args.arg1).initializeInternal(token, msg.arg1, - new InputMethodPrivilegedOperationsImpl(this, token), - (int) args.arg3); + new InputMethodPrivilegedOperationsImpl(this, token)); } catch (RemoteException e) { } args.recycle(); diff --git a/services/core/java/com/android/server/notification/NotificationManagerService.java b/services/core/java/com/android/server/notification/NotificationManagerService.java index 0cc9f9e150c6..d5a9e3c0d4f8 100755 --- a/services/core/java/com/android/server/notification/NotificationManagerService.java +++ b/services/core/java/com/android/server/notification/NotificationManagerService.java @@ -7376,15 +7376,7 @@ public class NotificationManagerService extends SystemService { // so need to check the notification still valide for vibrate. synchronized (mNotificationLock) { if (mNotificationsByKey.get(record.getKey()) != null) { - // Vibrator checks the appops for the op package, not the caller, - // so we need to add the bypass dnd flag to be heard. it's ok to - // always add this flag here because we've already checked that we can - // bypass dnd - AudioAttributes.Builder aab = - new AudioAttributes.Builder(record.getAudioAttributes()) - .setFlags(FLAG_BYPASS_INTERRUPTION_POLICY); - mVibrator.vibrate(record.getSbn().getUid(), record.getSbn().getOpPkg(), - effect, "Notification (delayed)", aab.build()); + vibrate(record, effect, true); } else { Slog.e(TAG, "No vibration for canceled notification : " + record.getKey()); @@ -7392,8 +7384,7 @@ public class NotificationManagerService extends SystemService { } }).start(); } else { - mVibrator.vibrate(record.getSbn().getUid(), record.getSbn().getPackageName(), - effect, "Notification", record.getAudioAttributes()); + vibrate(record, effect, false); } return true; } finally{ @@ -7401,6 +7392,16 @@ public class NotificationManagerService extends SystemService { } } + private void vibrate(NotificationRecord record, VibrationEffect effect, boolean delayed) { + // We need to vibrate as "android" so we can breakthrough DND. VibratorManagerService + // doesn't have a concept of vibrating on an app's behalf, so add the app information + // to the reason so we can still debug from bugreports + String reason = "Notification (" + record.getSbn().getOpPkg() + " " + + record.getSbn().getUid() + ") " + (delayed ? "(Delayed)" : ""); + mVibrator.vibrate(Process.SYSTEM_UID, PackageManagerService.PLATFORM_PACKAGE_NAME, + effect, reason, record.getAudioAttributes()); + } + private boolean isNotificationForCurrentUser(NotificationRecord record) { final int currentUser; final long token = Binder.clearCallingIdentity(); diff --git a/services/core/java/com/android/server/pm/AppsFilter.java b/services/core/java/com/android/server/pm/AppsFilter.java index 1acbabda9e19..ca8202f5f94b 100644 --- a/services/core/java/com/android/server/pm/AppsFilter.java +++ b/services/core/java/com/android/server/pm/AppsFilter.java @@ -105,6 +105,12 @@ public class AppsFilter implements Watchable, Snappable { private final SparseSetArray<Integer> mQueriesViaComponent = new SparseSetArray<>(); /** + * A mapping from the set of App IDs that query other App IDs via library name to the + * list of packages that they can see. + */ + private final SparseSetArray<Integer> mQueryableViaUsesLibrary = new SparseSetArray<>(); + + /** * Executor for running reasonably short background tasks such as building the initial * visibility cache. */ @@ -239,6 +245,7 @@ public class AppsFilter implements Watchable, Snappable { Snapshots.copy(mImplicitlyQueryable, orig.mImplicitlyQueryable); Snapshots.copy(mQueriesViaPackage, orig.mQueriesViaPackage); Snapshots.copy(mQueriesViaComponent, orig.mQueriesViaComponent); + Snapshots.copy(mQueryableViaUsesLibrary, orig.mQueryableViaUsesLibrary); mQueriesViaComponentRequireRecompute = orig.mQueriesViaComponentRequireRecompute; mForceQueryable.addAll(orig.mForceQueryable); mForceQueryableByDevicePackageNames = orig.mForceQueryableByDevicePackageNames; @@ -508,6 +515,22 @@ public class AppsFilter implements Watchable, Snappable { return false; } + private static boolean canQueryViaUsesLibrary(AndroidPackage querying, + AndroidPackage potentialTarget) { + if (potentialTarget.getLibraryNames().isEmpty()) { + return false; + } + final List<String> libNames = potentialTarget.getLibraryNames(); + for (int i = 0, size = libNames.size(); i < size; i++) { + final String libName = libNames.get(i); + if (querying.getUsesLibraries().contains(libName) + || querying.getUsesOptionalLibraries().contains(libName)) { + return true; + } + } + return false; + } + private static boolean matchesProviders( Set<String> queriesAuthorities, AndroidPackage potentialTarget) { for (int p = ArrayUtils.size(potentialTarget.getProviders()) - 1; p >= 0; p--) { @@ -707,6 +730,9 @@ public class AppsFilter implements Watchable, Snappable { || canQueryAsInstaller(existingSetting, newPkg)) { mQueriesViaPackage.add(existingSetting.appId, newPkgSetting.appId); } + if (canQueryViaUsesLibrary(existingPkg, newPkg)) { + mQueryableViaUsesLibrary.add(existingSetting.appId, newPkgSetting.appId); + } } // now we'll evaluate our new package's ability to see existing packages if (!mForceQueryable.contains(existingSetting.appId)) { @@ -718,6 +744,9 @@ public class AppsFilter implements Watchable, Snappable { || canQueryAsInstaller(newPkgSetting, existingPkg)) { mQueriesViaPackage.add(newPkgSetting.appId, existingSetting.appId); } + if (canQueryViaUsesLibrary(newPkg, existingPkg)) { + mQueryableViaUsesLibrary.add(newPkgSetting.appId, existingSetting.appId); + } } // if either package instruments the other, mark both as visible to one another if (newPkgSetting.pkg != null && existingSetting.pkg != null @@ -1035,6 +1064,10 @@ public class AppsFilter implements Watchable, Snappable { for (int i = mQueriesViaPackage.size() - 1; i >= 0; i--) { mQueriesViaPackage.remove(mQueriesViaPackage.keyAt(i), setting.appId); } + mQueryableViaUsesLibrary.remove(setting.appId); + for (int i = mQueryableViaUsesLibrary.size() - 1; i >= 0; i--) { + mQueryableViaUsesLibrary.remove(mQueryableViaUsesLibrary.keyAt(i), setting.appId); + } mForceQueryable.remove(setting.appId); @@ -1315,6 +1348,18 @@ public class AppsFilter implements Watchable, Snappable { Trace.traceEnd(TRACE_TAG_PACKAGE_MANAGER); } + try { + Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "mQueryableViaUsesLibrary"); + if (mQueryableViaUsesLibrary.contains(callingAppId, targetAppId)) { + if (DEBUG_LOGGING) { + log(callingSetting, targetPkgSetting, "queryable for library users"); + } + return false; + } + } finally { + Trace.traceEnd(TRACE_TAG_PACKAGE_MANAGER); + } + return true; } finally { Trace.traceEnd(TRACE_TAG_PACKAGE_MANAGER); @@ -1394,6 +1439,8 @@ public class AppsFilter implements Watchable, Snappable { filteringAppId == null ? null : UserHandle.getUid(user, filteringAppId), mImplicitlyQueryable, " ", expandPackages); } + pw.println(" queryable via uses-library:"); + dumpQueriesMap(pw, filteringAppId, mQueryableViaUsesLibrary, " ", expandPackages); } private static void dumpQueriesMap(PrintWriter pw, @Nullable Integer filteringId, diff --git a/services/core/java/com/android/server/pm/DataLoaderManagerService.java b/services/core/java/com/android/server/pm/DataLoaderManagerService.java index b34611b9cd6f..29322e2553e9 100644 --- a/services/core/java/com/android/server/pm/DataLoaderManagerService.java +++ b/services/core/java/com/android/server/pm/DataLoaderManagerService.java @@ -180,6 +180,8 @@ public class DataLoaderManagerService extends SystemService { mId = id; mListener = listener; mDataLoader = null; + + callListener(IDataLoaderStatusListener.DATA_LOADER_BINDING); } @Override diff --git a/services/core/java/com/android/server/pm/PackageInstallerSession.java b/services/core/java/com/android/server/pm/PackageInstallerSession.java index 82b12aac0a11..bafe987cb546 100644 --- a/services/core/java/com/android/server/pm/PackageInstallerSession.java +++ b/services/core/java/com/android/server/pm/PackageInstallerSession.java @@ -1011,8 +1011,9 @@ public class PackageInstallerSession extends IPackageInstallerSession.Stub { "DataLoader installation of APEX modules is not allowed."); } - if (this.params.dataLoaderParams.getComponentName().getPackageName() - == SYSTEM_DATA_LOADER_PACKAGE && mContext.checkCallingOrSelfPermission( + boolean systemDataLoader = SYSTEM_DATA_LOADER_PACKAGE.equals( + this.params.dataLoaderParams.getComponentName().getPackageName()); + if (systemDataLoader && mContext.checkCallingOrSelfPermission( Manifest.permission.USE_SYSTEM_DATA_LOADERS) != PackageManager.PERMISSION_GRANTED) { throw new SecurityException("You need the " @@ -3653,6 +3654,7 @@ public class PackageInstallerSession extends IPackageInstallerSession.Stub { @Override public void onStatusChanged(int dataLoaderId, int status) { switch (status) { + case IDataLoaderStatusListener.DATA_LOADER_BINDING: case IDataLoaderStatusListener.DATA_LOADER_STOPPED: case IDataLoaderStatusListener.DATA_LOADER_DESTROYED: return; @@ -3763,8 +3765,8 @@ public class PackageInstallerSession extends IPackageInstallerSession.Stub { healthCheckParams.unhealthyTimeoutMs = INCREMENTAL_STORAGE_UNHEALTHY_TIMEOUT_MS; healthCheckParams.unhealthyMonitoringMs = INCREMENTAL_STORAGE_UNHEALTHY_MONITORING_MS; - final boolean systemDataLoader = - params.getComponentName().getPackageName() == SYSTEM_DATA_LOADER_PACKAGE; + final boolean systemDataLoader = SYSTEM_DATA_LOADER_PACKAGE.equals( + params.getComponentName().getPackageName()); final IStorageHealthListener healthListener = new IStorageHealthListener.Stub() { @Override diff --git a/services/core/java/com/android/server/pm/verify/domain/DomainVerificationManagerInternal.java b/services/core/java/com/android/server/pm/verify/domain/DomainVerificationManagerInternal.java index 0c2b4c547dae..b4bcde726173 100644 --- a/services/core/java/com/android/server/pm/verify/domain/DomainVerificationManagerInternal.java +++ b/services/core/java/com/android/server/pm/verify/domain/DomainVerificationManagerInternal.java @@ -80,14 +80,14 @@ public interface DomainVerificationManagerInternal { * been preserved for migration purposes, but is otherwise ignored. Corresponds to * {@link PackageManager#INTENT_FILTER_DOMAIN_VERIFICATION_STATUS_ALWAYS}. */ - int APPROVAL_LEVEL_LEGACY_ALWAYS = 1; + int APPROVAL_LEVEL_LEGACY_ALWAYS = 2; /** * The app has been chosen by the user through * {@link DomainVerificationManager#setDomainVerificationUserSelection(UUID, Set, boolean)}, * indicating an explicit choice to use this app to open an unverified domain. */ - int APPROVAL_LEVEL_SELECTION = 2; + int APPROVAL_LEVEL_SELECTION = 3; /** * The app is approved through the digital asset link statement being hosted at the domain @@ -95,7 +95,7 @@ public interface DomainVerificationManagerInternal { * {@link DomainVerificationManager#setDomainVerificationStatus(UUID, Set, int)} by * the domain verification agent on device. */ - int APPROVAL_LEVEL_VERIFIED = 3; + int APPROVAL_LEVEL_VERIFIED = 4; /** * The app has been installed as an instant app, which grants it total authority on the domains @@ -105,7 +105,7 @@ public interface DomainVerificationManagerInternal { * The user is still able to disable instant app link handling through * {@link DomainVerificationManager#setDomainVerificationLinkHandlingAllowed(String, boolean)}. */ - int APPROVAL_LEVEL_INSTANT_APP = 4; + int APPROVAL_LEVEL_INSTANT_APP = 5; /** * Defines the possible values for {@link #approvalLevelForDomain(PackageSetting, Intent, int)} diff --git a/services/core/java/com/android/server/vibrator/VibratorController.java b/services/core/java/com/android/server/vibrator/VibratorController.java index eaba083c551c..e3dc70b41c0d 100644 --- a/services/core/java/com/android/server/vibrator/VibratorController.java +++ b/services/core/java/com/android/server/vibrator/VibratorController.java @@ -54,50 +54,6 @@ final class VibratorController { void onComplete(int vibratorId, long vibrationId); } - /** - * Initializes the native part of this controller, creating a global reference to given - * {@link OnVibrationCompleteListener} and returns a newly allocated native pointer. This - * wrapper is responsible for deleting this pointer by calling the method pointed - * by {@link #vibratorGetFinalizer()}. - * - * <p><b>Note:</b> Make sure the given implementation of {@link OnVibrationCompleteListener} - * do not hold any strong reference to the instance responsible for deleting the returned - * pointer, to avoid creating a cyclic GC root reference. - */ - static native long vibratorInit(int vibratorId, OnVibrationCompleteListener listener); - - /** - * Returns pointer to native function responsible for cleaning up the native pointer allocated - * and returned by {@link #vibratorInit(int, OnVibrationCompleteListener)}. - */ - static native long vibratorGetFinalizer(); - - static native boolean vibratorIsAvailable(long nativePtr); - - static native void vibratorOn(long nativePtr, long milliseconds, long vibrationId); - - static native void vibratorOff(long nativePtr); - - static native void vibratorSetAmplitude(long nativePtr, int amplitude); - - static native int[] vibratorGetSupportedEffects(long nativePtr); - - static native int[] vibratorGetSupportedPrimitives(long nativePtr); - - static native long vibratorPerformEffect( - long nativePtr, long effect, long strength, long vibrationId); - - static native long vibratorPerformComposedEffect( - long nativePtr, VibrationEffect.Composition.PrimitiveEffect[] effect, long vibrationId); - - static native void vibratorSetExternalControl(long nativePtr, boolean enabled); - - static native long vibratorGetCapabilities(long nativePtr); - - static native void vibratorAlwaysOnEnable(long nativePtr, long id, long effect, long strength); - - static native void vibratorAlwaysOnDisable(long nativePtr, long id); - VibratorController(int vibratorId, OnVibrationCompleteListener listener) { this(vibratorId, listener, new NativeWrapper()); } @@ -109,7 +65,8 @@ final class VibratorController { mNativeWrapper.init(vibratorId, listener); mVibratorInfo = new VibratorInfo(vibratorId, nativeWrapper.getCapabilities(), - nativeWrapper.getSupportedEffects(), nativeWrapper.getSupportedPrimitives()); + nativeWrapper.getSupportedEffects(), nativeWrapper.getSupportedPrimitives(), + nativeWrapper.getResonantFrequency(), nativeWrapper.getQFactor()); } /** Register state listener for this vibrator. */ @@ -336,13 +293,47 @@ final class VibratorController { /** Wrapper around the static-native methods of {@link VibratorController} for tests. */ @VisibleForTesting public static class NativeWrapper { + /** + * Initializes the native part of this controller, creating a global reference to given + * {@link OnVibrationCompleteListener} and returns a newly allocated native pointer. This + * wrapper is responsible for deleting this pointer by calling the method pointed + * by {@link #getNativeFinalizer()}. + * + * <p><b>Note:</b> Make sure the given implementation of {@link OnVibrationCompleteListener} + * do not hold any strong reference to the instance responsible for deleting the returned + * pointer, to avoid creating a cyclic GC root reference. + */ + private static native long nativeInit(int vibratorId, OnVibrationCompleteListener listener); + + /** + * Returns pointer to native function responsible for cleaning up the native pointer + * allocated and returned by {@link #nativeInit(int, OnVibrationCompleteListener)}. + */ + private static native long getNativeFinalizer(); + private static native boolean isAvailable(long nativePtr); + private static native void on(long nativePtr, long milliseconds, long vibrationId); + private static native void off(long nativePtr); + private static native void setAmplitude(long nativePtr, int amplitude); + private static native int[] getSupportedEffects(long nativePtr); + private static native int[] getSupportedPrimitives(long nativePtr); + private static native long performEffect( + long nativePtr, long effect, long strength, long vibrationId); + private static native long performComposedEffect(long nativePtr, + VibrationEffect.Composition.PrimitiveEffect[] effect, long vibrationId); + private static native void setExternalControl(long nativePtr, boolean enabled); + private static native long getCapabilities(long nativePtr); + private static native void alwaysOnEnable(long nativePtr, long id, long effect, + long strength); + private static native void alwaysOnDisable(long nativePtr, long id); + private static native float getResonantFrequency(long nativePtr); + private static native float getQFactor(long nativePtr); private long mNativePtr = 0; /** Initializes native controller and allocation registry to destroy native instances. */ public void init(int vibratorId, OnVibrationCompleteListener listener) { - mNativePtr = VibratorController.vibratorInit(vibratorId, listener); - long finalizerPtr = VibratorController.vibratorGetFinalizer(); + mNativePtr = nativeInit(vibratorId, listener); + long finalizerPtr = getNativeFinalizer(); if (finalizerPtr != 0) { NativeAllocationRegistry registry = @@ -354,65 +345,73 @@ final class VibratorController { /** Check if the vibrator is currently available. */ public boolean isAvailable() { - return VibratorController.vibratorIsAvailable(mNativePtr); + return isAvailable(mNativePtr); } /** Turns vibrator on for given time. */ public void on(long milliseconds, long vibrationId) { - VibratorController.vibratorOn(mNativePtr, milliseconds, vibrationId); + on(mNativePtr, milliseconds, vibrationId); } /** Turns vibrator off. */ public void off() { - VibratorController.vibratorOff(mNativePtr); + off(mNativePtr); } /** Sets the amplitude for the vibrator to run. */ public void setAmplitude(int amplitude) { - VibratorController.vibratorSetAmplitude(mNativePtr, amplitude); + setAmplitude(mNativePtr, amplitude); } /** Returns all predefined effects supported by the device vibrator. */ public int[] getSupportedEffects() { - return VibratorController.vibratorGetSupportedEffects(mNativePtr); + return getSupportedEffects(mNativePtr); } /** Returns all compose primitives supported by the device vibrator. */ public int[] getSupportedPrimitives() { - return VibratorController.vibratorGetSupportedPrimitives(mNativePtr); + return getSupportedPrimitives(mNativePtr); } /** Turns vibrator on to perform one of the supported effects. */ public long perform(long effect, long strength, long vibrationId) { - return VibratorController.vibratorPerformEffect( - mNativePtr, effect, strength, vibrationId); + return performEffect(mNativePtr, effect, strength, vibrationId); } /** Turns vibrator on to perform one of the supported composed effects. */ public long compose( VibrationEffect.Composition.PrimitiveEffect[] effect, long vibrationId) { - return VibratorController.vibratorPerformComposedEffect(mNativePtr, effect, - vibrationId); + return performComposedEffect(mNativePtr, effect, vibrationId); } /** Enabled the device vibrator to be controlled by another service. */ public void setExternalControl(boolean enabled) { - VibratorController.vibratorSetExternalControl(mNativePtr, enabled); + setExternalControl(mNativePtr, enabled); } /** Returns all capabilities of the device vibrator. */ public long getCapabilities() { - return VibratorController.vibratorGetCapabilities(mNativePtr); + return getCapabilities(mNativePtr); } /** Enable always-on vibration with given id and effect. */ public void alwaysOnEnable(long id, long effect, long strength) { - VibratorController.vibratorAlwaysOnEnable(mNativePtr, id, effect, strength); + alwaysOnEnable(mNativePtr, id, effect, strength); } /** Disable always-on vibration for given id. */ public void alwaysOnDisable(long id) { - VibratorController.vibratorAlwaysOnDisable(mNativePtr, id); + alwaysOnDisable(mNativePtr, id); + } + + /** Gets the vibrator's resonant frequency (F0) */ + public float getResonantFrequency() { + return getResonantFrequency(mNativePtr); + } + + /** Gets the vibrator's Q factor */ + public float getQFactor() { + return getQFactor(mNativePtr); } } } diff --git a/services/core/java/com/android/server/wm/TaskOrganizerController.java b/services/core/java/com/android/server/wm/TaskOrganizerController.java index 385dc79567fa..5d22f8fde057 100644 --- a/services/core/java/com/android/server/wm/TaskOrganizerController.java +++ b/services/core/java/com/android/server/wm/TaskOrganizerController.java @@ -884,6 +884,7 @@ class TaskOrganizerController extends ITaskOrganizerController.Stub { mPendingTaskEvents.remove(pending); } mPendingTaskEvents.add(pending); + mService.mWindowManager.mWindowPlacerLocked.requestTraversal(); return true; } diff --git a/services/core/jni/com_android_server_vibrator_VibratorController.cpp b/services/core/jni/com_android_server_vibrator_VibratorController.cpp index ef2d0baff031..f60b35499013 100644 --- a/services/core/jni/com_android_server_vibrator_VibratorController.cpp +++ b/services/core/jni/com_android_server_vibrator_VibratorController.cpp @@ -32,8 +32,6 @@ #include "com_android_server_vibrator_VibratorManagerService.h" namespace V1_0 = android::hardware::vibrator::V1_0; -namespace V1_1 = android::hardware::vibrator::V1_1; -namespace V1_2 = android::hardware::vibrator::V1_2; namespace V1_3 = android::hardware::vibrator::V1_3; namespace aidl = android::hardware::vibrator; @@ -85,10 +83,11 @@ static std::shared_ptr<vibrator::HalController> findVibrator(int32_t vibratorId) class VibratorControllerWrapper { public: VibratorControllerWrapper(JNIEnv* env, int32_t vibratorId, jobject callbackListener) - : mHal(std::move(findVibrator(vibratorId))), + : mHal(findVibrator(vibratorId)), mVibratorId(vibratorId), mCallbackListener(env->NewGlobalRef(callbackListener)) { - LOG_ALWAYS_FATAL_IF(mHal == nullptr, "Unable to find reference to vibrator hal"); + LOG_ALWAYS_FATAL_IF(mHal == nullptr, + "Failed to connect to vibrator HAL, or vibratorId is invalid"); LOG_ALWAYS_FATAL_IF(mCallbackListener == nullptr, "Unable to create global reference to vibration callback handler"); } @@ -130,15 +129,15 @@ static void destroyNativeWrapper(void* ptr) { } } -static jlong vibratorInit(JNIEnv* env, jclass /* clazz */, jint vibratorId, - jobject callbackListener) { +static jlong vibratorNativeInit(JNIEnv* env, jclass /* clazz */, jint vibratorId, + jobject callbackListener) { std::unique_ptr<VibratorControllerWrapper> wrapper = std::make_unique<VibratorControllerWrapper>(env, vibratorId, callbackListener); wrapper->hal()->init(); return reinterpret_cast<jlong>(wrapper.release()); } -static jlong vibratorGetFinalizer(JNIEnv* /* env */, jclass /* clazz */) { +static jlong vibratorGetNativeFinalizer(JNIEnv* /* env */, jclass /* clazz */) { return static_cast<jlong>(reinterpret_cast<uintptr_t>(&destroyNativeWrapper)); } @@ -286,25 +285,46 @@ static void vibratorAlwaysOnDisable(JNIEnv* env, jclass /* clazz */, jlong ptr, wrapper->hal()->alwaysOnDisable(static_cast<int32_t>(id)); } +static float vibratorGetResonantFrequency(JNIEnv* env, jclass /* clazz */, jlong ptr) { + VibratorControllerWrapper* wrapper = reinterpret_cast<VibratorControllerWrapper*>(ptr); + if (wrapper == nullptr) { + ALOGE("vibratorGetResonantFrequency failed because native wrapper was not initialized"); + return NAN; + } + auto result = wrapper->hal()->getResonantFrequency(); + return result.isOk() ? static_cast<jfloat>(result.value()) : NAN; +} + +static float vibratorGetQFactor(JNIEnv* env, jclass /* clazz */, jlong ptr) { + VibratorControllerWrapper* wrapper = reinterpret_cast<VibratorControllerWrapper*>(ptr); + if (wrapper == nullptr) { + ALOGE("vibratorGetQFactor failed because native wrapper was not initialized"); + return NAN; + } + auto result = wrapper->hal()->getQFactor(); + return result.isOk() ? static_cast<jfloat>(result.value()) : NAN; +} + static const JNINativeMethod method_table[] = { - {"vibratorInit", + {"nativeInit", "(ILcom/android/server/vibrator/VibratorController$OnVibrationCompleteListener;)J", - (void*)vibratorInit}, - {"vibratorGetFinalizer", "()J", (void*)vibratorGetFinalizer}, - {"vibratorIsAvailable", "(J)Z", (void*)vibratorIsAvailable}, - {"vibratorOn", "(JJJ)V", (void*)vibratorOn}, - {"vibratorOff", "(J)V", (void*)vibratorOff}, - {"vibratorSetAmplitude", "(JI)V", (void*)vibratorSetAmplitude}, - {"vibratorPerformEffect", "(JJJJ)J", (void*)vibratorPerformEffect}, - {"vibratorPerformComposedEffect", - "(J[Landroid/os/VibrationEffect$Composition$PrimitiveEffect;J)J", + (void*)vibratorNativeInit}, + {"getNativeFinalizer", "()J", (void*)vibratorGetNativeFinalizer}, + {"isAvailable", "(J)Z", (void*)vibratorIsAvailable}, + {"on", "(JJJ)V", (void*)vibratorOn}, + {"off", "(J)V", (void*)vibratorOff}, + {"setAmplitude", "(JI)V", (void*)vibratorSetAmplitude}, + {"performEffect", "(JJJJ)J", (void*)vibratorPerformEffect}, + {"performComposedEffect", "(J[Landroid/os/VibrationEffect$Composition$PrimitiveEffect;J)J", (void*)vibratorPerformComposedEffect}, - {"vibratorGetSupportedEffects", "(J)[I", (void*)vibratorGetSupportedEffects}, - {"vibratorGetSupportedPrimitives", "(J)[I", (void*)vibratorGetSupportedPrimitives}, - {"vibratorSetExternalControl", "(JZ)V", (void*)vibratorSetExternalControl}, - {"vibratorGetCapabilities", "(J)J", (void*)vibratorGetCapabilities}, - {"vibratorAlwaysOnEnable", "(JJJJ)V", (void*)vibratorAlwaysOnEnable}, - {"vibratorAlwaysOnDisable", "(JJ)V", (void*)vibratorAlwaysOnDisable}, + {"getSupportedEffects", "(J)[I", (void*)vibratorGetSupportedEffects}, + {"getSupportedPrimitives", "(J)[I", (void*)vibratorGetSupportedPrimitives}, + {"setExternalControl", "(JZ)V", (void*)vibratorSetExternalControl}, + {"getCapabilities", "(J)J", (void*)vibratorGetCapabilities}, + {"alwaysOnEnable", "(JJJJ)V", (void*)vibratorAlwaysOnEnable}, + {"alwaysOnDisable", "(JJ)V", (void*)vibratorAlwaysOnDisable}, + {"getResonantFrequency", "(J)F", (void*)vibratorGetResonantFrequency}, + {"getQFactor", "(J)F", (void*)vibratorGetQFactor}, }; int register_android_server_vibrator_VibratorController(JavaVM* jvm, JNIEnv* env) { @@ -320,7 +340,8 @@ int register_android_server_vibrator_VibratorController(JavaVM* jvm, JNIEnv* env sPrimitiveClassInfo.scale = GetFieldIDOrDie(env, primitiveClass, "scale", "F"); sPrimitiveClassInfo.delay = GetFieldIDOrDie(env, primitiveClass, "delay", "I"); - return jniRegisterNativeMethods(env, "com/android/server/vibrator/VibratorController", + return jniRegisterNativeMethods(env, + "com/android/server/vibrator/VibratorController$NativeWrapper", method_table, NELEM(method_table)); } diff --git a/services/devicepolicy/java/com/android/server/devicepolicy/ActiveAdmin.java b/services/devicepolicy/java/com/android/server/devicepolicy/ActiveAdmin.java index 48ae8d672fb1..aed13b263a7f 100644 --- a/services/devicepolicy/java/com/android/server/devicepolicy/ActiveAdmin.java +++ b/services/devicepolicy/java/com/android/server/devicepolicy/ActiveAdmin.java @@ -19,6 +19,8 @@ package com.android.server.devicepolicy; import static android.app.admin.DevicePolicyManager.PASSWORD_COMPLEXITY_NONE; import static android.app.admin.DevicePolicyManager.PASSWORD_QUALITY_UNSPECIFIED; +import static com.android.server.devicepolicy.DevicePolicyManagerService.LOG_TAG; + import static org.xmlpull.v1.XmlPullParser.END_DOCUMENT; import static org.xmlpull.v1.XmlPullParser.END_TAG; import static org.xmlpull.v1.XmlPullParser.TEXT; @@ -38,7 +40,6 @@ import android.text.TextUtils; import android.util.ArrayMap; import android.util.ArraySet; import android.util.IndentingPrintWriter; -import android.util.Log; import android.util.Slog; import android.util.TypedXmlPullParser; import android.util.TypedXmlSerializer; @@ -455,8 +456,7 @@ class ActiveAdmin { try { trustAgentInfo.options.saveToXml(out); } catch (XmlPullParserException e) { - Log.e(DevicePolicyManagerService.LOG_TAG, - "Failed to save TrustAgent options", e); + Slog.e(LOG_TAG, e, "Failed to save TrustAgent options"); } out.endTag(null, TAG_TRUST_AGENT_COMPONENT_OPTIONS); } @@ -629,8 +629,7 @@ class ActiveAdmin { String tag = parser.getName(); if (TAG_POLICIES.equals(tag)) { if (shouldOverridePolicies) { - Log.d(DevicePolicyManagerService.LOG_TAG, - "Overriding device admin policies from XML."); + Slog.d(LOG_TAG, "Overriding device admin policies from XML."); info.readPoliciesFromXml(parser); } } else if (TAG_PASSWORD_QUALITY.equals(tag)) { @@ -726,16 +725,14 @@ class ActiveAdmin { if (type == TypedXmlPullParser.TEXT) { shortSupportMessage = parser.getText(); } else { - Log.w(DevicePolicyManagerService.LOG_TAG, - "Missing text when loading short support message"); + Slog.w(LOG_TAG, "Missing text when loading short support message"); } } else if (TAG_LONG_SUPPORT_MESSAGE.equals(tag)) { type = parser.next(); if (type == TypedXmlPullParser.TEXT) { longSupportMessage = parser.getText(); } else { - Log.w(DevicePolicyManagerService.LOG_TAG, - "Missing text when loading long support message"); + Slog.w(LOG_TAG, "Missing text when loading long support message"); } } else if (TAG_PARENT_ADMIN.equals(tag)) { Preconditions.checkState(!isParent); @@ -748,8 +745,7 @@ class ActiveAdmin { if (type == TypedXmlPullParser.TEXT) { organizationName = parser.getText(); } else { - Log.w(DevicePolicyManagerService.LOG_TAG, - "Missing text when loading organization name"); + Slog.w(LOG_TAG, "Missing text when loading organization name"); } } else if (TAG_IS_LOGOUT_ENABLED.equals(tag)) { isLogoutEnabled = parser.getAttributeBoolean(null, ATTR_VALUE, false); @@ -758,16 +754,14 @@ class ActiveAdmin { if (type == TypedXmlPullParser.TEXT) { startUserSessionMessage = parser.getText(); } else { - Log.w(DevicePolicyManagerService.LOG_TAG, - "Missing text when loading start session message"); + Slog.w(LOG_TAG, "Missing text when loading start session message"); } } else if (TAG_END_USER_SESSION_MESSAGE.equals(tag)) { type = parser.next(); if (type == TypedXmlPullParser.TEXT) { endUserSessionMessage = parser.getText(); } else { - Log.w(DevicePolicyManagerService.LOG_TAG, - "Missing text when loading end session message"); + Slog.w(LOG_TAG, "Missing text when loading end session message"); } } else if (TAG_CROSS_PROFILE_CALENDAR_PACKAGES.equals(tag)) { mCrossProfileCalendarPackages = readPackageList(parser, tag); @@ -802,16 +796,14 @@ class ActiveAdmin { if (type == TypedXmlPullParser.TEXT) { mOrganizationId = parser.getText(); } else { - Log.w(DevicePolicyManagerService.LOG_TAG, - "Missing Organization ID."); + Slog.w(LOG_TAG, "Missing Organization ID."); } } else if (TAG_ENROLLMENT_SPECIFIC_ID.equals(tag)) { type = parser.next(); if (type == TypedXmlPullParser.TEXT) { mEnrollmentSpecificId = parser.getText(); } else { - Log.w(DevicePolicyManagerService.LOG_TAG, - "Missing Enrollment-specific ID."); + Slog.w(LOG_TAG, "Missing Enrollment-specific ID."); } } else if (TAG_ADMIN_CAN_GRANT_SENSORS_PERMISSIONS.equals(tag)) { mAdminCanGrantSensorsPermissions = parser.getAttributeBoolean(null, ATTR_VALUE, @@ -820,7 +812,7 @@ class ActiveAdmin { mUsbDataSignalingEnabled = parser.getAttributeBoolean(null, ATTR_VALUE, USB_DATA_SIGNALING_ENABLED_DEFAULT); } else { - Slog.w(DevicePolicyManagerService.LOG_TAG, "Unknown admin tag: " + tag); + Slog.w(LOG_TAG, "Unknown admin tag: %s", tag); XmlUtils.skipCurrentTag(parser); } } @@ -842,12 +834,10 @@ class ActiveAdmin { if (packageName != null) { result.add(packageName); } else { - Slog.w(DevicePolicyManagerService.LOG_TAG, - "Package name missing under " + outerTag); + Slog.w(LOG_TAG, "Package name missing under %s", outerTag); } } else { - Slog.w(DevicePolicyManagerService.LOG_TAG, - "Unknown tag under " + tag + ": " + outerTag); + Slog.w(LOG_TAG, "Unknown tag under %s: ", tag, outerTag); } } return result; @@ -868,8 +858,7 @@ class ActiveAdmin { if (tag.equals(tagDAM)) { result.add(parser.getAttributeValue(null, ATTR_VALUE)); } else { - Slog.e(DevicePolicyManagerService.LOG_TAG, - "Expected tag " + tag + " but found " + tagDAM); + Slog.e(LOG_TAG, "Expected tag %s but found %s", tag, tagDAM); } } } @@ -891,8 +880,7 @@ class ActiveAdmin { final TrustAgentInfo trustAgentInfo = getTrustAgentInfo(parser, tag); result.put(component, trustAgentInfo); } else { - Slog.w(DevicePolicyManagerService.LOG_TAG, - "Unknown tag under " + tag + ": " + tagDAM); + Slog.w(LOG_TAG, "Unknown tag under %s: %s", tag, tagDAM); } } return result; @@ -912,8 +900,7 @@ class ActiveAdmin { if (TAG_TRUST_AGENT_COMPONENT_OPTIONS.equals(tagDAM)) { result.options = PersistableBundle.restoreFromXml(parser); } else { - Slog.w(DevicePolicyManagerService.LOG_TAG, - "Unknown tag under " + tag + ": " + tagDAM); + Slog.w(LOG_TAG, "Unknown tag under %s: %s", tag, tagDAM); } } return result; diff --git a/services/devicepolicy/java/com/android/server/devicepolicy/CertificateMonitor.java b/services/devicepolicy/java/com/android/server/devicepolicy/CertificateMonitor.java index d812b8f7fadb..e0c5e328f8c7 100644 --- a/services/devicepolicy/java/com/android/server/devicepolicy/CertificateMonitor.java +++ b/services/devicepolicy/java/com/android/server/devicepolicy/CertificateMonitor.java @@ -16,6 +16,8 @@ package com.android.server.devicepolicy; +import static com.android.server.devicepolicy.DevicePolicyManagerService.LOG_TAG; + import android.app.Notification; import android.app.PendingIntent; import android.content.BroadcastReceiver; @@ -33,7 +35,7 @@ import android.provider.Settings; import android.security.Credentials; import android.security.KeyChain; import android.security.KeyChain.KeyChainConnection; -import android.util.Log; +import android.util.Slog; import com.android.internal.R; import com.android.internal.messages.nano.SystemMessageProto.SystemMessage; @@ -47,7 +49,6 @@ import java.security.cert.X509Certificate; import java.util.List; public class CertificateMonitor { - protected static final String LOG_TAG = DevicePolicyManagerService.LOG_TAG; protected static final int MONITORING_CERT_NOTIFICATION_ID = SystemMessage.NOTE_SSL_CERT_INFO; private final DevicePolicyManagerService mService; @@ -78,16 +79,16 @@ public class CertificateMonitor { X509Certificate cert = parseCert(certBuffer); pemCert = Credentials.convertToPem(cert); } catch (CertificateException | IOException ce) { - Log.e(LOG_TAG, "Problem converting cert", ce); + Slog.e(LOG_TAG, ce, "Problem converting cert"); return null; } try (KeyChainConnection keyChainConnection = mInjector.keyChainBindAsUser(userHandle)) { return keyChainConnection.getService().installCaCertificate(pemCert); } catch (RemoteException e) { - Log.e(LOG_TAG, "installCaCertsToKeyChain(): ", e); + Slog.e(LOG_TAG, e, "installCaCertsToKeyChain(): "); } catch (InterruptedException e1) { - Log.w(LOG_TAG, "installCaCertsToKeyChain(): ", e1); + Slog.w(LOG_TAG, e1, "installCaCertsToKeyChain(): "); Thread.currentThread().interrupt(); } return null; @@ -99,9 +100,9 @@ public class CertificateMonitor { keyChainConnection.getService().deleteCaCertificate(aliases[i]); } } catch (RemoteException e) { - Log.e(LOG_TAG, "from CaCertUninstaller: ", e); + Slog.e(LOG_TAG, e, "from CaCertUninstaller: "); } catch (InterruptedException ie) { - Log.w(LOG_TAG, "CaCertUninstaller: ", ie); + Slog.w(LOG_TAG, ie, "CaCertUninstaller: "); Thread.currentThread().interrupt(); } } @@ -137,7 +138,8 @@ public class CertificateMonitor { }; private void updateInstalledCertificates(final UserHandle userHandle) { - if (!mInjector.getUserManager().isUserUnlocked(userHandle.getIdentifier())) { + final int userId = userHandle.getIdentifier(); + if (!mInjector.getUserManager().isUserUnlocked(userId)) { return; } @@ -145,7 +147,8 @@ public class CertificateMonitor { try { installedCerts = getInstalledCaCertificates(userHandle); } catch (RemoteException | RuntimeException e) { - Log.e(LOG_TAG, "Could not retrieve certificates from KeyChain service", e); + Slog.e(LOG_TAG, e, "Could not retrieve certificates from KeyChain service for user %d", + userId); return; } mService.onInstalledCertificatesChanged(userHandle, installedCerts); @@ -167,7 +170,7 @@ public class CertificateMonitor { try { userContext = mInjector.createContextAsUser(userHandle); } catch (PackageManager.NameNotFoundException e) { - Log.e(LOG_TAG, "Create context as " + userHandle + " failed", e); + Slog.e(LOG_TAG, e, "Create context as %s failed", userHandle); return null; } @@ -183,7 +186,6 @@ public class CertificateMonitor { smallIconId = R.drawable.stat_sys_certificate_info; parentUserId = mService.getProfileParentId(userHandle.getIdentifier()); } else if (mService.getDeviceOwnerUserId() == userHandle.getIdentifier()) { - final String ownerName = mService.getDeviceOwnerName(); contentText = resources.getString(R.string.ssl_ca_cert_noti_managed, mService.getDeviceOwnerName()); smallIconId = R.drawable.stat_sys_certificate_info; diff --git a/services/devicepolicy/java/com/android/server/devicepolicy/DeviceAdminServiceController.java b/services/devicepolicy/java/com/android/server/devicepolicy/DeviceAdminServiceController.java index 3067d4507162..00e0292d404f 100644 --- a/services/devicepolicy/java/com/android/server/devicepolicy/DeviceAdminServiceController.java +++ b/services/devicepolicy/java/com/android/server/devicepolicy/DeviceAdminServiceController.java @@ -46,19 +46,11 @@ public class DeviceAdminServiceController { final Object mLock = new Object(); final Context mContext; - private final DevicePolicyManagerService mService; private final DevicePolicyManagerService.Injector mInjector; private final DevicePolicyConstants mConstants; private final Handler mHandler; // needed? - static void debug(String format, Object... args) { - if (!DEBUG) { - return; - } - Slog.d(TAG, String.format(format, args)); - } - private class DevicePolicyServiceConnection extends PersistentConnection<IDeviceAdminService> { public DevicePolicyServiceConnection(int userId, @NonNull ComponentName componentName) { @@ -88,7 +80,6 @@ public class DeviceAdminServiceController { public DeviceAdminServiceController(DevicePolicyManagerService service, DevicePolicyConstants constants) { - mService = service; mInjector = service.mInjector; mContext = mInjector.mContext; mHandler = new Handler(BackgroundThread.get().getLooper()); @@ -122,8 +113,9 @@ public class DeviceAdminServiceController { synchronized (mLock) { final ServiceInfo service = findService(packageName, userId); if (service == null) { - debug("Owner package %s on u%d has no service.", - packageName, userId); + if (DEBUG) { + Slog.d(TAG, "Owner package %s on u%d has no service.", packageName, userId); + } disconnectServiceOnUserLocked(userId, actionForLog); return; } @@ -134,14 +126,17 @@ public class DeviceAdminServiceController { // Note even when we're already connected to the same service, the binding // would have died at this point due to a package update. So we disconnect // anyway and re-connect. - debug("Disconnecting from existing service connection.", - packageName, userId); + if (DEBUG) { + Slog.d("Disconnecting from existing service connection.", packageName, + userId); + } disconnectServiceOnUserLocked(userId, actionForLog); } - debug("Owner package %s on u%d has service %s for %s", - packageName, userId, + if (DEBUG) { + Slog.d("Owner package %s on u%d has service %s for %s", packageName, userId, service.getComponentName().flattenToShortString(), actionForLog); + } final DevicePolicyServiceConnection conn = new DevicePolicyServiceConnection( @@ -172,8 +167,10 @@ public class DeviceAdminServiceController { private void disconnectServiceOnUserLocked(int userId, @NonNull String actionForLog) { final DevicePolicyServiceConnection conn = mConnections.get(userId); if (conn != null) { - debug("Stopping service for u%d if already running for %s.", - userId, actionForLog); + if (DEBUG) { + Slog.d(TAG, "Stopping service for u%d if already running for %s.", userId, + actionForLog); + } conn.unbind(); mConnections.remove(userId); } diff --git a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyConstants.java b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyConstants.java index 464d6f5ea835..84e6da0d9851 100644 --- a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyConstants.java +++ b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyConstants.java @@ -88,7 +88,7 @@ public class DevicePolicyConstants { } catch (IllegalArgumentException e) { // Failed to parse the settings string, log this and move on // with defaults. - Slog.e(TAG, "Bad device policy settings: " + settings); + Slog.e(TAG, "Bad device policy settings: %s", settings); } long dasDiedServiceReconnectBackoffSec = parser.getLong( diff --git a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyData.java b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyData.java index c0b2ed4cc955..52cdce6ee7b3 100644 --- a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyData.java +++ b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyData.java @@ -179,11 +179,11 @@ class DevicePolicyData { */ static boolean store(DevicePolicyData policyData, JournaledFile file, boolean isFdeDevice) { FileOutputStream stream = null; + File chooseForWrite = null; try { - File chooseForWrite = file.chooseForWrite(); + chooseForWrite = file.chooseForWrite(); if (VERBOSE_LOG) { - Slog.v(TAG, "Storing data for user " + policyData.mUserId + " on " - + chooseForWrite); + Slog.v(TAG, "Storing data for user %d on %s ", policyData.mUserId, chooseForWrite); } stream = new FileOutputStream(chooseForWrite, false); TypedXmlSerializer out = Xml.resolveSerializer(stream); @@ -195,7 +195,7 @@ class DevicePolicyData { policyData.mRestrictionsProvider.flattenToString()); } if (policyData.mUserSetupComplete) { - if (VERBOSE_LOG) Slog.v(TAG, "setting " + ATTR_SETUP_COMPLETE + " to true"); + if (VERBOSE_LOG) Slog.v(TAG, "setting %s to true", ATTR_SETUP_COMPLETE); out.attributeBoolean(null, ATTR_SETUP_COMPLETE, true); } if (policyData.mPaired) { @@ -216,8 +216,8 @@ class DevicePolicyData { if (policyData.mFactoryResetFlags != 0) { if (VERBOSE_LOG) { - Slog.v(TAG, "Storing factory reset flags for user " + policyData.mUserId + ": " - + factoryResetFlagsToString(policyData.mFactoryResetFlags)); + Slog.v(TAG, "Storing factory reset flags for user %d: %s", policyData.mUserId, + factoryResetFlagsToString(policyData.mFactoryResetFlags)); } out.attributeInt(null, ATTR_FACTORY_RESET_FLAGS, policyData.mFactoryResetFlags); } @@ -382,7 +382,7 @@ class DevicePolicyData { file.commit(); return true; } catch (XmlPullParserException | IOException e) { - Slog.w(TAG, "failed writing file", e); + Slog.w(TAG, e, "failed writing file %s", chooseForWrite); try { if (stream != null) { stream.close(); @@ -404,10 +404,8 @@ class DevicePolicyData { ComponentName ownerComponent) { FileInputStream stream = null; File file = journaledFile.chooseForRead(); - if (VERBOSE_LOG) { - Slog.v(TAG, "Loading data for user " + policy.mUserId + " from " + file); - } - + if (VERBOSE_LOG) Slog.v(TAG, "Loading data for user %d from %s", policy.mUserId, file); + boolean needsRewrite = false; try { stream = new FileInputStream(file); TypedXmlPullParser parser = Xml.resolvePullParser(stream); @@ -454,8 +452,8 @@ class DevicePolicyData { policy.mFactoryResetFlags = parser.getAttributeInt(null, ATTR_FACTORY_RESET_FLAGS, 0); if (VERBOSE_LOG) { - Slog.v(TAG, "Restored factory reset flags for user " + policy.mUserId + ": " - + factoryResetFlagsToString(policy.mFactoryResetFlags)); + Slog.v(TAG, "Restored factory reset flags for user %d: %s", policy.mUserId, + factoryResetFlagsToString(policy.mFactoryResetFlags)); } policy.mFactoryResetReason = parser.getAttributeValue(null, ATTR_FACTORY_RESET_REASON); @@ -488,7 +486,7 @@ class DevicePolicyData { policy.mAdminMap.put(ap.info.getComponent(), ap); } } catch (RuntimeException e) { - Slog.w(TAG, "Failed loading admin " + name, e); + Slog.w(TAG, e, "Failed loading admin %s", name); } } else if ("delegation".equals(tag)) { // Parse delegation info. @@ -560,7 +558,7 @@ class DevicePolicyData { policy.mAppsSuspended = parser.getAttributeBoolean(null, ATTR_VALUE, false); } else { - Slog.w(TAG, "Unknown tag: " + tag); + Slog.w(TAG, "Unknown tag: %s", tag); XmlUtils.skipCurrentTag(parser); } } @@ -568,7 +566,7 @@ class DevicePolicyData { // Don't be noisy, this is normal if we haven't defined any policies. } catch (NullPointerException | NumberFormatException | XmlPullParserException | IOException | IndexOutOfBoundsException e) { - Slog.w(TAG, "failed parsing " + file, e); + Slog.w(TAG, e, "failed parsing %s", file); } try { if (stream != null) { @@ -592,8 +590,8 @@ class DevicePolicyData { } } if (!haveOwner) { - Slog.w(TAG, "Previous password owner " + mPasswordOwner - + " no longer active; disabling"); + Slog.w(TAG, "Previous password owner %s no longer active; disabling", + mPasswordOwner); mPasswordOwner = -1; } } diff --git a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java index 2855c70368b1..577f3f5a1cb4 100644 --- a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java +++ b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java @@ -1106,7 +1106,7 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager { * Used by {@code setDevicePolicySafetyChecker()} above and {@link OneTimeSafetyChecker}. */ void setDevicePolicySafetyCheckerUnchecked(DevicePolicySafetyChecker safetyChecker) { - Slog.i(LOG_TAG, String.format("Setting DevicePolicySafetyChecker as %s", safetyChecker)); + Slog.i(LOG_TAG, "Setting DevicePolicySafetyChecker as %s", safetyChecker); mSafetyChecker = safetyChecker; mInjector.setDevicePolicySafetyChecker(safetyChecker); } diff --git a/services/devicepolicy/java/com/android/server/devicepolicy/FactoryResetter.java b/services/devicepolicy/java/com/android/server/devicepolicy/FactoryResetter.java index 457255bd9a73..28a6987bb846 100644 --- a/services/devicepolicy/java/com/android/server/devicepolicy/FactoryResetter.java +++ b/services/devicepolicy/java/com/android/server/devicepolicy/FactoryResetter.java @@ -68,17 +68,16 @@ public final class FactoryResetter { IResultReceiver receiver = new IResultReceiver.Stub() { @Override public void send(int resultCode, Bundle resultData) throws RemoteException { - Slog.i(TAG, String.format("Factory reset confirmed by %s, proceeding", - mSafetyChecker)); + Slog.i(TAG, "Factory reset confirmed by %s, proceeding", mSafetyChecker); try { factoryResetInternalUnchecked(); } catch (IOException e) { // Shouldn't happen - Slog.wtf(TAG, "IOException calling underlying systems", e); + Slog.wtf(TAG, e, "IOException calling underlying systems"); } } }; - Slog.i(TAG, String.format("Delaying factory reset until %s confirms", mSafetyChecker)); + Slog.i(TAG, "Delaying factory reset until %s confirms", mSafetyChecker); mSafetyChecker.onFactoryReset(receiver); return false; } @@ -113,9 +112,9 @@ public final class FactoryResetter { } private void factoryResetInternalUnchecked() throws IOException { - Slog.i(TAG, String.format("factoryReset(): reason=%s, shutdown=%b, force=%b, wipeEuicc=%b, " + Slog.i(TAG, "factoryReset(): reason=%s, shutdown=%b, force=%b, wipeEuicc=%b, " + "wipeAdoptableStorage=%b, wipeFRP=%b", mReason, mShutdown, mForce, mWipeEuicc, - mWipeAdoptableStorage, mWipeFactoryResetProtection)); + mWipeAdoptableStorage, mWipeFactoryResetProtection); UserManager um = mContext.getSystemService(UserManager.class); if (!mForce && um.hasUserRestriction(UserManager.DISALLOW_FACTORY_RESET)) { diff --git a/services/devicepolicy/java/com/android/server/devicepolicy/PersonalAppsSuspensionHelper.java b/services/devicepolicy/java/com/android/server/devicepolicy/PersonalAppsSuspensionHelper.java index 37dbfc170aff..0b9ece466df4 100644 --- a/services/devicepolicy/java/com/android/server/devicepolicy/PersonalAppsSuspensionHelper.java +++ b/services/devicepolicy/java/com/android/server/devicepolicy/PersonalAppsSuspensionHelper.java @@ -18,6 +18,8 @@ package com.android.server.devicepolicy; import static android.accessibilityservice.AccessibilityServiceInfo.FEEDBACK_ALL_MASK; +import static com.android.server.devicepolicy.DevicePolicyManagerService.LOG_TAG; + import android.accessibilityservice.AccessibilityServiceInfo; import android.annotation.Nullable; import android.annotation.UserIdInt; @@ -36,6 +38,7 @@ import android.provider.Telephony; import android.text.TextUtils; import android.util.ArraySet; import android.util.IndentingPrintWriter; +import android.util.Log; import android.util.Slog; import android.view.accessibility.AccessibilityManager; import android.view.accessibility.IAccessibilityManager; @@ -105,7 +108,9 @@ public final class PersonalAppsSuspensionHelper { result.remove(pkg); } - Slog.i(LOG_TAG, "Packages subject to suspension: " + String.join(",", result)); + if (Log.isLoggable(LOG_TAG, Log.INFO)) { + Slog.i(LOG_TAG, "Packages subject to suspension: %s", String.join(",", result)); + } return result.toArray(new String[0]); } @@ -118,7 +123,7 @@ public final class PersonalAppsSuspensionHelper { for (final ResolveInfo resolveInfo : matchingActivities) { if (resolveInfo.activityInfo == null || TextUtils.isEmpty(resolveInfo.activityInfo.packageName)) { - Slog.wtf(LOG_TAG, "Could not find package name for launcher app" + resolveInfo); + Slog.wtf(LOG_TAG, "Could not find package name for launcher app %s", resolveInfo); continue; } final String packageName = resolveInfo.activityInfo.packageName; @@ -129,7 +134,8 @@ public final class PersonalAppsSuspensionHelper { result.add(packageName); } } catch (PackageManager.NameNotFoundException e) { - Slog.e(LOG_TAG, "Could not find application info for launcher app: " + packageName); + Slog.e(LOG_TAG, "Could not find application info for launcher app: %s", + packageName); } } return result; diff --git a/services/devicepolicy/java/com/android/server/devicepolicy/RemoteBugreportManager.java b/services/devicepolicy/java/com/android/server/devicepolicy/RemoteBugreportManager.java index 543f3815454e..2959c10d5508 100644 --- a/services/devicepolicy/java/com/android/server/devicepolicy/RemoteBugreportManager.java +++ b/services/devicepolicy/java/com/android/server/devicepolicy/RemoteBugreportManager.java @@ -25,6 +25,8 @@ import static android.app.admin.DevicePolicyManager.NOTIFICATION_BUGREPORT_ACCEP import static android.app.admin.DevicePolicyManager.NOTIFICATION_BUGREPORT_FINISHED_NOT_ACCEPTED; import static android.app.admin.DevicePolicyManager.NOTIFICATION_BUGREPORT_STARTED; +import static com.android.server.devicepolicy.DevicePolicyManagerService.LOG_TAG; + import android.annotation.IntDef; import android.app.Notification; import android.app.PendingIntent; @@ -58,7 +60,6 @@ import java.util.concurrent.atomic.AtomicBoolean; * Class managing bugreport collection upon device owner's request. */ public class RemoteBugreportManager { - private static final String LOG_TAG = DevicePolicyManagerService.LOG_TAG; static final String BUGREPORT_MIMETYPE = "application/vnd.android.bugreport"; @@ -206,7 +207,7 @@ public class RemoteBugreportManager { return true; } catch (RemoteException re) { // should never happen - Slog.e(LOG_TAG, "Failed to make remote calls to start bugreportremote service", re); + Slog.e(LOG_TAG, re, "Failed to make remote calls to start bugreportremote service"); return false; } finally { mInjector.binderRestoreCallingIdentity(callingIdentity); @@ -220,7 +221,7 @@ public class RemoteBugreportManager { mContext.registerReceiver(mRemoteBugreportFinishedReceiver, filterFinished); } catch (IntentFilter.MalformedMimeTypeException e) { // should never happen, as setting a constant - Slog.w(LOG_TAG, "Failed to set type " + BUGREPORT_MIMETYPE, e); + Slog.w(LOG_TAG, e, "Failed to set type %s", BUGREPORT_MIMETYPE); } final IntentFilter filterConsent = new IntentFilter(); filterConsent.addAction(ACTION_BUGREPORT_SHARING_DECLINED); diff --git a/services/incremental/IncrementalService.cpp b/services/incremental/IncrementalService.cpp index 1fcc2843bd43..c38d0b3cc7db 100644 --- a/services/incremental/IncrementalService.cpp +++ b/services/incremental/IncrementalService.cpp @@ -74,6 +74,13 @@ struct Constants { // If DL was up and not crashing for 10mins, we consider it healthy and reset all delays. static constexpr auto healthyDataLoaderUptime = 10min; + + // For healthy DLs, we'll retry every ~5secs for ~10min + static constexpr auto bindRetryInterval = 5s; + static constexpr auto bindGracePeriod = 10min; + + static constexpr auto bindingTimeout = 1min; + // 10s, 100s (~2min), 1000s (~15min), 10000s (~3hrs) static constexpr auto minBindDelay = 10s; static constexpr auto maxBindDelay = 10000s; @@ -293,6 +300,7 @@ IncrementalService::IncrementalService(ServiceManagerWrapper&& sm, std::string_v mTimedQueue(sm.getTimedQueue()), mProgressUpdateJobQueue(sm.getProgressUpdateJobQueue()), mFs(sm.getFs()), + mClock(sm.getClock()), mIncrementalDir(rootDir) { CHECK(mVold) << "Vold service is unavailable"; CHECK(mDataLoaderManager) << "DataLoaderManagerService is unavailable"; @@ -302,6 +310,7 @@ IncrementalService::IncrementalService(ServiceManagerWrapper&& sm, std::string_v CHECK(mTimedQueue) << "TimedQueue is unavailable"; CHECK(mProgressUpdateJobQueue) << "mProgressUpdateJobQueue is unavailable"; CHECK(mFs) << "Fs is unavailable"; + CHECK(mClock) << "Clock is unavailable"; mJobQueue.reserve(16); mJobProcessor = std::thread([this]() { @@ -2241,17 +2250,44 @@ void IncrementalService::DataLoaderStub::setTargetStatusLocked(int status) { << status << " (current " << mCurrentStatus << ")"; } -Milliseconds IncrementalService::DataLoaderStub::updateBindDelay() { +std::optional<Milliseconds> IncrementalService::DataLoaderStub::needToBind() { std::unique_lock lock(mMutex); + + const auto now = mService.mClock->now(); + const bool healthy = (mPreviousBindDelay == 0ms); + + if (mCurrentStatus == IDataLoaderStatusListener::DATA_LOADER_BINDING && + now - mCurrentStatusTs <= Constants::bindingTimeout) { + LOG(INFO) << "Binding still in progress. " + << (healthy ? "The DL is healthy/freshly bound, ok to retry for a few times." + : "Already unhealthy, don't do anything."); + // Binding still in progress. + if (!healthy) { + // Already unhealthy, don't do anything. + return {}; + } + // The DL is healthy/freshly bound, ok to retry for a few times. + if (now - mPreviousBindTs <= Constants::bindGracePeriod) { + // Still within grace period. + if (now - mCurrentStatusTs >= Constants::bindRetryInterval) { + // Retry interval passed, retrying. + mCurrentStatusTs = now; + mPreviousBindDelay = 0ms; + return 0ms; + } + return {}; + } + // fallthrough, mark as unhealthy, and retry with delay + } + const auto previousBindTs = mPreviousBindTs; - const auto now = Clock::now(); mPreviousBindTs = now; const auto nonCrashingInterval = std::max(castToMs(now - previousBindTs), 100ms); if (previousBindTs.time_since_epoch() == Clock::duration::zero() || nonCrashingInterval > Constants::healthyDataLoaderUptime) { mPreviousBindDelay = 0ms; - return mPreviousBindDelay; + return 0ms; } constexpr auto minBindDelayMs = castToMs(Constants::minBindDelay); @@ -2264,12 +2300,16 @@ Milliseconds IncrementalService::DataLoaderStub::updateBindDelay() { const auto bindDelayJitterRangeMs = bindDelayMs / Constants::bindDelayJitterDivider; const auto bindDelayJitterMs = rand() % (bindDelayJitterRangeMs * 2) - bindDelayJitterRangeMs; mPreviousBindDelay = std::chrono::milliseconds(bindDelayMs + bindDelayJitterMs); - return mPreviousBindDelay; } bool IncrementalService::DataLoaderStub::bind() { - const auto bindDelay = updateBindDelay(); + const auto maybeBindDelay = needToBind(); + if (!maybeBindDelay) { + LOG(DEBUG) << "Skipping bind to " << mParams.packageName << " because of pending bind."; + return true; + } + const auto bindDelay = *maybeBindDelay; if (bindDelay > 1s) { LOG(INFO) << "Delaying bind to " << mParams.packageName << " by " << bindDelay.count() / 1000 << "s"; @@ -2279,7 +2319,21 @@ bool IncrementalService::DataLoaderStub::bind() { auto status = mService.mDataLoaderManager->bindToDataLoader(id(), mParams, bindDelay.count(), this, &result); if (!status.isOk() || !result) { - LOG(ERROR) << "Failed to bind a data loader for mount " << id(); + const bool healthy = (bindDelay == 0ms); + LOG(ERROR) << "Failed to bind a data loader for mount " << id() + << (healthy ? ", retrying." : ""); + + // Internal error, retry for healthy/new DLs. + // Let needToBind migrate it to unhealthy after too many retries. + if (healthy) { + if (mService.addTimedJob(*mService.mTimedQueue, id(), Constants::bindRetryInterval, + [this]() { fsmStep(); })) { + // Mark as binding so that we know it's not the DL's fault. + setCurrentStatus(IDataLoaderStatusListener::DATA_LOADER_BINDING); + return true; + } + } + return false; } return true; @@ -2339,7 +2393,14 @@ bool IncrementalService::DataLoaderStub::fsmStep() { // Do nothing, this is a reset state. break; case IDataLoaderStatusListener::DATA_LOADER_DESTROYED: { - return destroy(); + switch (currentStatus) { + case IDataLoaderStatusListener::DATA_LOADER_BINDING: + setCurrentStatus(IDataLoaderStatusListener::DATA_LOADER_DESTROYED); + return true; + default: + return destroy(); + } + break; } case IDataLoaderStatusListener::DATA_LOADER_STARTED: { switch (currentStatus) { @@ -2353,6 +2414,7 @@ bool IncrementalService::DataLoaderStub::fsmStep() { switch (currentStatus) { case IDataLoaderStatusListener::DATA_LOADER_DESTROYED: case IDataLoaderStatusListener::DATA_LOADER_UNAVAILABLE: + case IDataLoaderStatusListener::DATA_LOADER_BINDING: return bind(); case IDataLoaderStatusListener::DATA_LOADER_BOUND: return create(); @@ -2372,7 +2434,8 @@ binder::Status IncrementalService::DataLoaderStub::onStatusChanged(MountId mount fromServiceSpecificError(-EINVAL, "onStatusChange came to invalid DataLoaderStub"); } if (id() != mountId) { - LOG(ERROR) << "Mount ID mismatch: expected " << id() << ", but got: " << mountId; + LOG(ERROR) << "onStatusChanged: mount ID mismatch: expected " << id() + << ", but got: " << mountId; return binder::Status::fromServiceSpecificError(-EPERM, "Mount ID mismatch."); } if (newStatus == IDataLoaderStatusListener::DATA_LOADER_UNRECOVERABLE) { @@ -2396,11 +2459,13 @@ void IncrementalService::DataLoaderStub::setCurrentStatus(int newStatus) { } oldStatus = mCurrentStatus; - mCurrentStatus = newStatus; targetStatus = mTargetStatus; - listener = mStatusListener; + // Change the status. + mCurrentStatus = newStatus; + mCurrentStatusTs = mService.mClock->now(); + if (mCurrentStatus == IDataLoaderStatusListener::DATA_LOADER_UNAVAILABLE || mCurrentStatus == IDataLoaderStatusListener::DATA_LOADER_UNRECOVERABLE) { // For unavailable, unbind from DataLoader to ensure proper re-commit. @@ -2428,7 +2493,8 @@ binder::Status IncrementalService::DataLoaderStub::reportStreamHealth(MountId mo "reportStreamHealth came to invalid DataLoaderStub"); } if (id() != mountId) { - LOG(ERROR) << "Mount ID mismatch: expected " << id() << ", but got: " << mountId; + LOG(ERROR) << "reportStreamHealth: mount ID mismatch: expected " << id() + << ", but got: " << mountId; return binder::Status::fromServiceSpecificError(-EPERM, "Mount ID mismatch."); } { @@ -2694,6 +2760,8 @@ static std::string toHexString(const RawMetadata& metadata) { void IncrementalService::DataLoaderStub::onDump(int fd) { dprintf(fd, " dataLoader: {\n"); dprintf(fd, " currentStatus: %d\n", mCurrentStatus); + dprintf(fd, " currentStatusTs: %lldmcs\n", + (long long)(elapsedMcs(mCurrentStatusTs, Clock::now()))); dprintf(fd, " targetStatus: %d\n", mTargetStatus); dprintf(fd, " targetStatusTs: %lldmcs\n", (long long)(elapsedMcs(mTargetStatusTs, Clock::now()))); diff --git a/services/incremental/IncrementalService.h b/services/incremental/IncrementalService.h index 14e5a7734172..4eb513808342 100644 --- a/services/incremental/IncrementalService.h +++ b/services/incremental/IncrementalService.h @@ -267,7 +267,10 @@ private: BootClockTsUs getOldestTsFromLastPendingReads(); Milliseconds elapsedMsSinceKernelTs(TimePoint now, BootClockTsUs kernelTsUs); - Milliseconds updateBindDelay(); + // If the stub has to bind to the DL. + // Returns {} if bind operation is already in progress. + // Or bind delay in ms. + std::optional<Milliseconds> needToBind(); void registerForPendingReads(); void unregisterFromPendingReads(); @@ -283,6 +286,7 @@ private: std::condition_variable mStatusCondition; int mCurrentStatus = content::pm::IDataLoaderStatusListener::DATA_LOADER_DESTROYED; + TimePoint mCurrentStatusTs = {}; int mTargetStatus = content::pm::IDataLoaderStatusListener::DATA_LOADER_DESTROYED; TimePoint mTargetStatusTs = {}; @@ -443,6 +447,7 @@ private: const std::unique_ptr<TimedQueueWrapper> mTimedQueue; const std::unique_ptr<TimedQueueWrapper> mProgressUpdateJobQueue; const std::unique_ptr<FsWrapper> mFs; + const std::unique_ptr<ClockWrapper> mClock; const std::string mIncrementalDir; mutable std::mutex mLock; diff --git a/services/incremental/ServiceWrappers.cpp b/services/incremental/ServiceWrappers.cpp index d61328942e5c..80f409ff1c61 100644 --- a/services/incremental/ServiceWrappers.cpp +++ b/services/incremental/ServiceWrappers.cpp @@ -329,6 +329,14 @@ public: } }; +class RealClockWrapper final : public ClockWrapper { +public: + RealClockWrapper() = default; + ~RealClockWrapper() = default; + + TimePoint now() const final { return Clock::now(); } +}; + RealServiceManager::RealServiceManager(sp<IServiceManager> serviceManager, JNIEnv* env) : mServiceManager(std::move(serviceManager)), mJvm(RealJniWrapper::getJvm(env)) {} @@ -388,6 +396,10 @@ std::unique_ptr<FsWrapper> RealServiceManager::getFs() { return std::make_unique<RealFsWrapper>(); } +std::unique_ptr<ClockWrapper> RealServiceManager::getClock() { + return std::make_unique<RealClockWrapper>(); +} + static JavaVM* getJavaVm(JNIEnv* env) { CHECK(env); JavaVM* jvm = nullptr; diff --git a/services/incremental/ServiceWrappers.h b/services/incremental/ServiceWrappers.h index 245bb3105be5..d113f992de71 100644 --- a/services/incremental/ServiceWrappers.h +++ b/services/incremental/ServiceWrappers.h @@ -158,6 +158,12 @@ public: virtual void listFilesRecursive(std::string_view directoryPath, FileCallback onFile) const = 0; }; +class ClockWrapper { +public: + virtual ~ClockWrapper() = default; + virtual TimePoint now() const = 0; +}; + class ServiceManagerWrapper { public: virtual ~ServiceManagerWrapper() = default; @@ -170,6 +176,7 @@ public: virtual std::unique_ptr<TimedQueueWrapper> getTimedQueue() = 0; virtual std::unique_ptr<TimedQueueWrapper> getProgressUpdateJobQueue() = 0; virtual std::unique_ptr<FsWrapper> getFs() = 0; + virtual std::unique_ptr<ClockWrapper> getClock() = 0; }; // --- Real stuff --- @@ -187,6 +194,7 @@ public: std::unique_ptr<TimedQueueWrapper> getTimedQueue() final; std::unique_ptr<TimedQueueWrapper> getProgressUpdateJobQueue() final; std::unique_ptr<FsWrapper> getFs() final; + std::unique_ptr<ClockWrapper> getClock() final; private: template <class INTERFACE> diff --git a/services/incremental/test/IncrementalServiceTest.cpp b/services/incremental/test/IncrementalServiceTest.cpp index 5236983c83ff..25b34b5669b8 100644 --- a/services/incremental/test/IncrementalServiceTest.cpp +++ b/services/incremental/test/IncrementalServiceTest.cpp @@ -248,6 +248,27 @@ public: } return binder::Status::ok(); } + binder::Status bindToDataLoaderNotOkWithNoDelay(int32_t mountId, + const DataLoaderParamsParcel& params, + int bindDelayMs, + const sp<IDataLoaderStatusListener>& listener, + bool* _aidl_return) { + CHECK(bindDelayMs == 0) << bindDelayMs; + *_aidl_return = false; + return binder::Status::ok(); + } + binder::Status bindToDataLoaderBindingWithNoDelay(int32_t mountId, + const DataLoaderParamsParcel& params, + int bindDelayMs, + const sp<IDataLoaderStatusListener>& listener, + bool* _aidl_return) { + CHECK(bindDelayMs == 0) << bindDelayMs; + *_aidl_return = true; + if (listener) { + listener->onStatusChanged(mId, IDataLoaderStatusListener::DATA_LOADER_BINDING); + } + return binder::Status::ok(); + } binder::Status bindToDataLoaderOkWith10sDelay(int32_t mountId, const DataLoaderParamsParcel& params, int bindDelayMs, @@ -557,6 +578,21 @@ public: } }; +class MockClockWrapper : public ClockWrapper { +public: + MOCK_CONST_METHOD0(now, TimePoint()); + + void start() { ON_CALL(*this, now()).WillByDefault(Invoke(this, &MockClockWrapper::getClock)); } + template <class Delta> + void advance(Delta delta) { + mClock += delta; + } + + TimePoint getClock() const { return mClock; } + + TimePoint mClock = Clock::now(); +}; + class MockStorageHealthListener : public os::incremental::BnStorageHealthListener { public: MOCK_METHOD2(onHealthStatus, binder::Status(int32_t storageId, int32_t status)); @@ -594,7 +630,7 @@ public: std::unique_ptr<MockLooperWrapper> looper, std::unique_ptr<MockTimedQueueWrapper> timedQueue, std::unique_ptr<MockTimedQueueWrapper> progressUpdateJobQueue, - std::unique_ptr<MockFsWrapper> fs) + std::unique_ptr<MockFsWrapper> fs, std::unique_ptr<MockClockWrapper> clock) : mVold(std::move(vold)), mDataLoaderManager(std::move(dataLoaderManager)), mIncFs(std::move(incfs)), @@ -603,7 +639,8 @@ public: mLooper(std::move(looper)), mTimedQueue(std::move(timedQueue)), mProgressUpdateJobQueue(std::move(progressUpdateJobQueue)), - mFs(std::move(fs)) {} + mFs(std::move(fs)), + mClock(std::move(clock)) {} std::unique_ptr<VoldServiceWrapper> getVoldService() final { return std::move(mVold); } std::unique_ptr<DataLoaderManagerWrapper> getDataLoaderManager() final { return std::move(mDataLoaderManager); @@ -619,6 +656,7 @@ public: return std::move(mProgressUpdateJobQueue); } std::unique_ptr<FsWrapper> getFs() final { return std::move(mFs); } + std::unique_ptr<ClockWrapper> getClock() final { return std::move(mClock); } private: std::unique_ptr<MockVoldService> mVold; @@ -630,6 +668,7 @@ private: std::unique_ptr<MockTimedQueueWrapper> mTimedQueue; std::unique_ptr<MockTimedQueueWrapper> mProgressUpdateJobQueue; std::unique_ptr<MockFsWrapper> mFs; + std::unique_ptr<MockClockWrapper> mClock; }; // --- IncrementalServiceTest --- @@ -657,6 +696,8 @@ public: mProgressUpdateJobQueue = progressUpdateJobQueue.get(); auto fs = std::make_unique<NiceMock<MockFsWrapper>>(); mFs = fs.get(); + auto clock = std::make_unique<NiceMock<MockClockWrapper>>(); + mClock = clock.get(); mIncrementalService = std::make_unique< IncrementalService>(MockServiceManager(std::move(vold), std::move(dataloaderManager), @@ -664,12 +705,13 @@ public: std::move(jni), std::move(looper), std::move(timedQueue), std::move(progressUpdateJobQueue), - std::move(fs)), + std::move(fs), std::move(clock)), mRootDir.path); mDataLoaderParcel.packageName = "com.test"; mDataLoaderParcel.arguments = "uri"; mDataLoaderManager->unbindFromDataLoaderSuccess(); mIncrementalService->onSystemReady(); + mClock->start(); setupSuccess(); } @@ -724,6 +766,7 @@ protected: NiceMock<MockTimedQueueWrapper>* mTimedQueue = nullptr; NiceMock<MockTimedQueueWrapper>* mProgressUpdateJobQueue = nullptr; NiceMock<MockFsWrapper>* mFs = nullptr; + NiceMock<MockClockWrapper>* mClock = nullptr; NiceMock<MockDataLoader>* mDataLoader = nullptr; std::unique_ptr<IncrementalService> mIncrementalService; TemporaryDir mRootDir; @@ -853,6 +896,119 @@ TEST_F(IncrementalServiceTest, testDataLoaderDestroyedAndDelayed) { mDataLoaderManager->setDataLoaderStatusDestroyed(); } +TEST_F(IncrementalServiceTest, testDataLoaderOnRestart) { + mIncFs->waitForPendingReadsSuccess(); + mIncFs->openMountSuccess(); + + constexpr auto bindRetryInterval = 5s; + + EXPECT_CALL(*mDataLoaderManager, bindToDataLoader(_, _, _, _, _)).Times(10); + EXPECT_CALL(*mDataLoaderManager, unbindFromDataLoader(_)).Times(1); + EXPECT_CALL(*mDataLoader, create(_, _, _, _)).Times(6); + EXPECT_CALL(*mDataLoader, start(_)).Times(6); + EXPECT_CALL(*mDataLoader, destroy(_)).Times(1); + EXPECT_CALL(*mVold, unmountIncFs(_)).Times(2); + EXPECT_CALL(*mTimedQueue, addJob(_, _, _)).Times(2); + TemporaryDir tempDir; + int storageId = + mIncrementalService->createStorage(tempDir.path, mDataLoaderParcel, + IncrementalService::CreateOptions::CreateNew); + ASSERT_GE(storageId, 0); + + // First binds to DataLoader fails... because it's restart. + ON_CALL(*mDataLoaderManager, bindToDataLoader(_, _, _, _, _)) + .WillByDefault(Invoke(mDataLoaderManager, + &MockDataLoaderManager::bindToDataLoaderNotOkWithNoDelay)); + + // Request DL start. + mIncrementalService->startLoading(storageId, std::move(mDataLoaderParcel), {}, {}, {}, {}); + + // Retry callback present. + ASSERT_EQ(storageId, mTimedQueue->mId); + ASSERT_EQ(mTimedQueue->mAfter, bindRetryInterval); + auto retryCallback = mTimedQueue->mWhat; + mTimedQueue->clearJob(storageId); + + // Expecting the same bindToDataLoaderNotOkWithNoDelay call. + mClock->advance(5s); + + retryCallback(); + // Retry callback present. + ASSERT_EQ(storageId, mTimedQueue->mId); + ASSERT_EQ(mTimedQueue->mAfter, bindRetryInterval); + retryCallback = mTimedQueue->mWhat; + mTimedQueue->clearJob(storageId); + + // Returning "binding" so that we can retry. + ON_CALL(*mDataLoaderManager, bindToDataLoader(_, _, _, _, _)) + .WillByDefault(Invoke(mDataLoaderManager, + &MockDataLoaderManager::bindToDataLoaderBindingWithNoDelay)); + + // Expecting bindToDataLoaderBindingWithNoDelay call. + mClock->advance(5s); + + retryCallback(); + // No retry callback. + ASSERT_EQ(mTimedQueue->mAfter, 0ms); + ASSERT_EQ(mTimedQueue->mWhat, nullptr); + + // Should not change the bindToDataLoader call count + ASSERT_NE(nullptr, mLooper->mCallback); + ASSERT_NE(nullptr, mLooper->mCallbackData); + auto looperCb = mLooper->mCallback; + auto looperCbData = mLooper->mCallbackData; + looperCb(-1, -1, looperCbData); + + // Expecting the same bindToDataLoaderBindingWithNoDelay call. + mClock->advance(5s); + + // Use pending reads callback to trigger binding. + looperCb(-1, -1, looperCbData); + + // No retry callback. + ASSERT_EQ(mTimedQueue->mAfter, 0ms); + ASSERT_EQ(mTimedQueue->mWhat, nullptr); + + // Now we are out of 10m "retry" budget, let's finally bind. + ON_CALL(*mDataLoaderManager, bindToDataLoader(_, _, _, _, _)) + .WillByDefault(Invoke(mDataLoaderManager, &MockDataLoaderManager::bindToDataLoaderOk)); + mClock->advance(11min); + + // Use pending reads callback to trigger binding. + looperCb(-1, -1, looperCbData); + + // No retry callback. + ASSERT_EQ(mTimedQueue->mAfter, 0ms); + ASSERT_EQ(mTimedQueue->mWhat, nullptr); + + // And test the rest of the backoff. + // Simulated crash/other connection breakage. + ON_CALL(*mDataLoaderManager, bindToDataLoader(_, _, _, _, _)) + .WillByDefault(Invoke(mDataLoaderManager, + &MockDataLoaderManager::bindToDataLoaderOkWith10sDelay)); + mDataLoaderManager->setDataLoaderStatusDestroyed(); + + ON_CALL(*mDataLoaderManager, bindToDataLoader(_, _, _, _, _)) + .WillByDefault(Invoke(mDataLoaderManager, + &MockDataLoaderManager::bindToDataLoaderOkWith100sDelay)); + mDataLoaderManager->setDataLoaderStatusDestroyed(); + + ON_CALL(*mDataLoaderManager, bindToDataLoader(_, _, _, _, _)) + .WillByDefault(Invoke(mDataLoaderManager, + &MockDataLoaderManager::bindToDataLoaderOkWith1000sDelay)); + mDataLoaderManager->setDataLoaderStatusDestroyed(); + + ON_CALL(*mDataLoaderManager, bindToDataLoader(_, _, _, _, _)) + .WillByDefault(Invoke(mDataLoaderManager, + &MockDataLoaderManager::bindToDataLoaderOkWith10000sDelay)); + mDataLoaderManager->setDataLoaderStatusDestroyed(); + + ON_CALL(*mDataLoaderManager, bindToDataLoader(_, _, _, _, _)) + .WillByDefault(Invoke(mDataLoaderManager, + &MockDataLoaderManager::bindToDataLoaderOkWith10000sDelay)); + mDataLoaderManager->setDataLoaderStatusDestroyed(); +} + TEST_F(IncrementalServiceTest, testStartDataLoaderCreate) { mDataLoader->initializeCreateOkNoStatus(); EXPECT_CALL(*mDataLoaderManager, bindToDataLoader(_, _, _, _, _)).Times(1); diff --git a/services/smartspace/java/com/android/server/smartspace/SmartspaceManagerService.java b/services/smartspace/java/com/android/server/smartspace/SmartspaceManagerService.java index 169b85eb7e06..b07fe19393b2 100644 --- a/services/smartspace/java/com/android/server/smartspace/SmartspaceManagerService.java +++ b/services/smartspace/java/com/android/server/smartspace/SmartspaceManagerService.java @@ -19,6 +19,7 @@ package com.android.server.smartspace; import static android.Manifest.permission.MANAGE_SMARTSPACE; import static android.app.ActivityManagerInternal.ALLOW_NON_FULL; import static android.content.Context.SMARTSPACE_SERVICE; +import static android.content.pm.PackageManager.PERMISSION_GRANTED; import android.annotation.NonNull; import android.annotation.Nullable; @@ -161,11 +162,13 @@ public class SmartspaceManagerService extends Slog.d(TAG, "runForUserLocked:" + func + " from pid=" + Binder.getCallingPid() + ", uid=" + Binder.getCallingUid()); } - if (!(mServiceNameResolver.isTemporary(userId) + Context ctx = getContext(); + if (!(ctx.checkCallingPermission(MANAGE_SMARTSPACE) == PERMISSION_GRANTED + || mServiceNameResolver.isTemporary(userId) || mActivityTaskManagerInternal.isCallerRecents(Binder.getCallingUid()))) { - String msg = "Permission Denial: " + func + " from pid=" + Binder.getCallingPid() - + ", uid=" + Binder.getCallingUid(); + String msg = "Permission Denial: Cannot call " + func + " from pid=" + + Binder.getCallingPid() + ", uid=" + Binder.getCallingUid(); Slog.w(TAG, msg); throw new SecurityException(msg); } diff --git a/services/tests/servicestests/src/com/android/server/pm/AppsFilterTest.java b/services/tests/servicestests/src/com/android/server/pm/AppsFilterTest.java index 9a52643b57f2..9f428c7cbded 100644 --- a/services/tests/servicestests/src/com/android/server/pm/AppsFilterTest.java +++ b/services/tests/servicestests/src/com/android/server/pm/AppsFilterTest.java @@ -31,6 +31,7 @@ import android.content.Intent; import android.content.IntentFilter; import android.content.pm.ApplicationInfo; import android.content.pm.PackageParser; +import android.content.pm.PackageParser.SigningDetails; import android.content.pm.Signature; import android.content.pm.UserInfo; import android.content.pm.parsing.ParsingPackage; @@ -141,6 +142,10 @@ public class AppsFilterTest { return pkg(packageName).addReceiver(receiver); } + private static ParsingPackage pkgWithSharedLibrary(String packageName, String libName) { + return pkg(packageName).addLibraryName(libName); + } + private static ParsedActivity createActivity(String packageName, IntentFilter[] filters) { ParsedActivity activity = new ParsedActivity(); activity.setPackageName(packageName); @@ -413,6 +418,118 @@ public class AppsFilterTest { } @Test + public void testNoUsesLibrary_Filters() throws Exception { + final AppsFilter appsFilter = new AppsFilter(mStateProvider, mFeatureConfigMock, + new String[]{}, /* systemAppsQueryable */ false, /* overlayProvider */ null, + mMockExecutor); + + simulateAddBasicAndroid(appsFilter); + appsFilter.onSystemReady(); + + final Signature mockSignature = Mockito.mock(Signature.class); + final SigningDetails mockSigningDetails = new SigningDetails( + new Signature[]{mockSignature}, + SigningDetails.SignatureSchemeVersion.SIGNING_BLOCK_V2); + + final PackageSetting target = simulateAddPackage(appsFilter, + pkgWithSharedLibrary("com.some.package", "com.some.shared_library"), + DUMMY_TARGET_APPID, + setting -> setting.setSigningDetails(mockSigningDetails) + .setPkgFlags(ApplicationInfo.FLAG_SYSTEM)); + final PackageSetting calling = simulateAddPackage(appsFilter, + pkg("com.some.other.package"), DUMMY_CALLING_APPID); + + assertTrue(appsFilter.shouldFilterApplication(DUMMY_CALLING_APPID, calling, target, + SYSTEM_USER)); + } + + @Test + public void testUsesLibrary_DoesntFilter() throws Exception { + final AppsFilter appsFilter = new AppsFilter(mStateProvider, mFeatureConfigMock, + new String[]{}, /* systemAppsQueryable */ false, /* overlayProvider */ null, + mMockExecutor); + + simulateAddBasicAndroid(appsFilter); + appsFilter.onSystemReady(); + + final Signature mockSignature = Mockito.mock(Signature.class); + final SigningDetails mockSigningDetails = new SigningDetails( + new Signature[]{mockSignature}, + SigningDetails.SignatureSchemeVersion.SIGNING_BLOCK_V2); + + final PackageSetting target = simulateAddPackage(appsFilter, + pkgWithSharedLibrary("com.some.package", "com.some.shared_library"), + DUMMY_TARGET_APPID, + setting -> setting.setSigningDetails(mockSigningDetails) + .setPkgFlags(ApplicationInfo.FLAG_SYSTEM)); + final PackageSetting calling = simulateAddPackage(appsFilter, + pkg("com.some.other.package").addUsesLibrary("com.some.shared_library"), + DUMMY_CALLING_APPID); + + assertFalse(appsFilter.shouldFilterApplication(DUMMY_CALLING_APPID, calling, target, + SYSTEM_USER)); + } + + @Test + public void testUsesOptionalLibrary_DoesntFilter() throws Exception { + final AppsFilter appsFilter = new AppsFilter(mStateProvider, mFeatureConfigMock, + new String[]{}, /* systemAppsQueryable */ false, /* overlayProvider */ null, + mMockExecutor); + + simulateAddBasicAndroid(appsFilter); + appsFilter.onSystemReady(); + + final Signature mockSignature = Mockito.mock(Signature.class); + final SigningDetails mockSigningDetails = new SigningDetails( + new Signature[]{mockSignature}, + SigningDetails.SignatureSchemeVersion.SIGNING_BLOCK_V2); + + final PackageSetting target = simulateAddPackage(appsFilter, + pkgWithSharedLibrary("com.some.package", "com.some.shared_library"), + DUMMY_TARGET_APPID, + setting -> setting.setSigningDetails(mockSigningDetails) + .setPkgFlags(ApplicationInfo.FLAG_SYSTEM)); + final PackageSetting calling = simulateAddPackage(appsFilter, + pkg("com.some.other.package").addUsesOptionalLibrary("com.some.shared_library"), + DUMMY_CALLING_APPID); + + assertFalse(appsFilter.shouldFilterApplication(DUMMY_CALLING_APPID, calling, target, + SYSTEM_USER)); + } + + @Test + public void testUsesLibrary_ShareUid_DoesntFilter() throws Exception { + final AppsFilter appsFilter = new AppsFilter(mStateProvider, mFeatureConfigMock, + new String[]{}, /* systemAppsQueryable */ false, /* overlayProvider */ null, + mMockExecutor); + + simulateAddBasicAndroid(appsFilter); + appsFilter.onSystemReady(); + + final Signature mockSignature = Mockito.mock(Signature.class); + final SigningDetails mockSigningDetails = new SigningDetails( + new Signature[]{mockSignature}, + SigningDetails.SignatureSchemeVersion.SIGNING_BLOCK_V2); + + final PackageSetting target = simulateAddPackage(appsFilter, + pkgWithSharedLibrary("com.some.package", "com.some.shared_library"), + DUMMY_TARGET_APPID, + setting -> setting.setSigningDetails(mockSigningDetails) + .setPkgFlags(ApplicationInfo.FLAG_SYSTEM)); + final PackageSetting calling = simulateAddPackage(appsFilter, + pkg("com.some.other.package_a").setSharedUserId("com.some.uid"), + DUMMY_CALLING_APPID); + simulateAddPackage(appsFilter, pkg("com.some.other.package_b") + .setSharedUserId("com.some.uid").addUsesLibrary("com.some.shared_library"), + DUMMY_CALLING_APPID); + + // Although package_a doesn't use library, it should be granted visibility. It's because + // package_a shares userId with package_b, and package_b uses that shared library. + assertFalse(appsFilter.shouldFilterApplication(DUMMY_CALLING_APPID, calling, target, + SYSTEM_USER)); + } + + @Test public void testForceQueryable_SystemDoesntFilter() throws Exception { final AppsFilter appsFilter = new AppsFilter(mStateProvider, mFeatureConfigMock, new String[]{}, false, null, diff --git a/services/tests/servicestests/src/com/android/server/vibrator/FakeVibratorControllerProvider.java b/services/tests/servicestests/src/com/android/server/vibrator/FakeVibratorControllerProvider.java index 2a3c2c46ce4e..b54b6969e7df 100644 --- a/services/tests/servicestests/src/com/android/server/vibrator/FakeVibratorControllerProvider.java +++ b/services/tests/servicestests/src/com/android/server/vibrator/FakeVibratorControllerProvider.java @@ -49,6 +49,8 @@ final class FakeVibratorControllerProvider { private int mCapabilities; private int[] mSupportedEffects; private int[] mSupportedPrimitives; + private float mResonantFrequency; + private float mQFactor; private final class FakeNativeWrapper extends VibratorController.NativeWrapper { public int vibratorId; @@ -89,6 +91,14 @@ final class FakeVibratorControllerProvider { return mSupportedPrimitives; } + public float getResonantFrequency() { + return mResonantFrequency; + } + + public float getQFactor() { + return mQFactor; + } + public long perform(long effect, long strength, long vibrationId) { if (mSupportedEffects == null || Arrays.binarySearch(mSupportedEffects, (int) effect) < 0) { @@ -198,6 +208,16 @@ final class FakeVibratorControllerProvider { mSupportedPrimitives = primitives; } + /** Set the resonant frequency of the fake vibrator hardware. */ + public void setResonantFrequency(float resonantFrequency) { + mResonantFrequency = resonantFrequency; + } + + /** Set the Q factor of the fake vibrator hardware. */ + public void setQFactor(float qFactor) { + mQFactor = qFactor; + } + /** * Return the amplitudes set by this controller, including zeroes for each time the vibrator was * turned off. diff --git a/services/tests/servicestests/src/com/android/server/vibrator/VibratorManagerServiceTest.java b/services/tests/servicestests/src/com/android/server/vibrator/VibratorManagerServiceTest.java index a28d18fb74d3..ce6639c6b4aa 100644 --- a/services/tests/servicestests/src/com/android/server/vibrator/VibratorManagerServiceTest.java +++ b/services/tests/servicestests/src/com/android/server/vibrator/VibratorManagerServiceTest.java @@ -266,6 +266,8 @@ public class VibratorManagerServiceTest { vibrator.setCapabilities(IVibrator.CAP_COMPOSE_EFFECTS, IVibrator.CAP_AMPLITUDE_CONTROL); vibrator.setSupportedEffects(VibrationEffect.EFFECT_CLICK); vibrator.setSupportedPrimitives(VibrationEffect.Composition.PRIMITIVE_CLICK); + vibrator.setResonantFrequency(123.f); + vibrator.setQFactor(Float.NaN); VibratorInfo info = createSystemReadyService().getVibratorInfo(1); assertNotNull(info); @@ -279,6 +281,8 @@ public class VibratorManagerServiceTest { info.isEffectSupported(VibrationEffect.EFFECT_TICK)); assertTrue(info.isPrimitiveSupported(VibrationEffect.Composition.PRIMITIVE_CLICK)); assertFalse(info.isPrimitiveSupported(VibrationEffect.Composition.PRIMITIVE_TICK)); + assertEquals(123.f, info.getResonantFrequency(), 0.01 /*tolerance*/); + assertTrue(Float.isNaN(info.getQFactor())); } @Test diff --git a/services/tests/uiservicestests/src/com/android/server/notification/BuzzBeepBlinkTest.java b/services/tests/uiservicestests/src/com/android/server/notification/BuzzBeepBlinkTest.java index e510b4fbfdd5..5462f47e3a4c 100644 --- a/services/tests/uiservicestests/src/com/android/server/notification/BuzzBeepBlinkTest.java +++ b/services/tests/uiservicestests/src/com/android/server/notification/BuzzBeepBlinkTest.java @@ -61,6 +61,7 @@ import android.media.AudioAttributes; import android.media.AudioManager; import android.net.Uri; import android.os.Handler; +import android.os.Process; import android.os.RemoteException; import android.os.UserHandle; import android.os.VibrationEffect; @@ -81,10 +82,12 @@ import com.android.internal.logging.InstanceIdSequenceFake; import com.android.internal.util.IntPair; import com.android.server.UiServiceTestCase; import com.android.server.lights.LogicalLight; +import com.android.server.pm.PackageManagerService; import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; +import org.mockito.ArgumentCaptor; import org.mockito.ArgumentMatcher; import org.mockito.Mock; import org.mockito.Mockito; @@ -412,12 +415,16 @@ public class BuzzBeepBlinkTest extends UiServiceTestCase { } private void verifyVibrate() { + ArgumentCaptor<AudioAttributes> captor = ArgumentCaptor.forClass(AudioAttributes.class); verify(mVibrator, times(1)).vibrate(anyInt(), anyString(), argThat(mVibrateOnceMatcher), - anyString(), any(AudioAttributes.class)); + anyString(), captor.capture()); + assertEquals(0, (captor.getValue().getAllFlags() + & AudioAttributes.FLAG_BYPASS_INTERRUPTION_POLICY)); } private void verifyVibrate(int times) { - verify(mVibrator, times(times)).vibrate(anyInt(), anyString(), any(), anyString(), + verify(mVibrator, times(times)).vibrate(eq(Process.SYSTEM_UID), + eq(PackageManagerService.PLATFORM_PACKAGE_NAME), any(), anyString(), any(AudioAttributes.class)); } diff --git a/telecomm/java/android/telecom/CallDiagnosticService.java b/telecomm/java/android/telecom/CallDiagnosticService.java index 201c5db74e16..809f2bc1bb7d 100644 --- a/telecomm/java/android/telecom/CallDiagnosticService.java +++ b/telecomm/java/android/telecom/CallDiagnosticService.java @@ -19,9 +19,12 @@ package android.telecom; import android.annotation.NonNull; import android.annotation.Nullable; import android.annotation.SdkConstant; +import android.annotation.SuppressLint; import android.annotation.SystemApi; import android.app.Service; import android.content.Intent; +import android.os.Handler; +import android.os.HandlerExecutor; import android.os.IBinder; import android.os.RemoteException; import android.util.ArrayMap; @@ -30,6 +33,7 @@ import com.android.internal.telecom.ICallDiagnosticService; import com.android.internal.telecom.ICallDiagnosticServiceAdapter; import java.util.Map; +import java.util.concurrent.Executor; /** * The platform supports a single OEM provided {@link CallDiagnosticService}, as defined by the @@ -51,6 +55,11 @@ import java.util.Map; * </service> * } * </pre> + * <p> + * <h2>Threading Model</h2> + * By default, all incoming IPC from Telecom in this service and in the {@link DiagnosticCall} + * instances will take place on the main thread. You can override {@link #getExecutor()} in your + * implementation to provide your own {@link Executor}. * @hide */ @SystemApi @@ -83,7 +92,7 @@ public abstract class CallDiagnosticService extends Service { @Override public void updateCallAudioState(CallAudioState callAudioState) throws RemoteException { - onCallAudioStateChanged(callAudioState); + getExecutor().execute(() -> onCallAudioStateChanged(callAudioState)); } @Override @@ -133,8 +142,18 @@ public abstract class CallDiagnosticService extends Service { */ private final Map<String, Call.Details> mCallByTelecomCallId = new ArrayMap<>(); private final Map<String, DiagnosticCall> mDiagnosticCallByTelecomCallId = new ArrayMap<>(); + private final Object mLock = new Object(); private ICallDiagnosticServiceAdapter mAdapter; + /** + * Handles binding to the {@link CallDiagnosticService}. + * + * @param intent The Intent that was used to bind to this service, + * as given to {@link android.content.Context#bindService + * Context.bindService}. Note that any extras that were included with + * the Intent at that point will <em>not</em> be seen here. + * @return + */ @Nullable @Override public IBinder onBind(@NonNull Intent intent) { @@ -143,11 +162,29 @@ public abstract class CallDiagnosticService extends Service { } /** + * Returns the {@link Executor} to use for incoming IPS from Telecom into your service + * implementation. + * <p> + * Override this method in your {@link CallDiagnosticService} implementation to provide the + * executor you want to use for incoming IPC. + * + * @return the {@link Executor} to use for incoming IPC from Telecom to + * {@link CallDiagnosticService} and {@link DiagnosticCall}. + */ + @SuppressLint("OnNameExpected") + @NonNull public Executor getExecutor() { + return new HandlerExecutor(Handler.createAsync(getMainLooper())); + } + + /** * Telecom calls this method on the {@link CallDiagnosticService} with details about a new call * which was added to Telecom. * <p> * The {@link CallDiagnosticService} returns an implementation of {@link DiagnosticCall} to be * used for the lifespan of this call. + * <p> + * Calls to this method will use the {@link CallDiagnosticService}'s {@link Executor}; see + * {@link CallDiagnosticService#getExecutor()} for more information. * * @param call The details of the new call. * @return An instance of {@link DiagnosticCall} which the {@link CallDiagnosticService} @@ -160,6 +197,10 @@ public abstract class CallDiagnosticService extends Service { /** * Telecom calls this method when a previous created {@link DiagnosticCall} is no longer needed. * This happens when Telecom is no longer tracking the call in question. + * <p> + * Calls to this method will use the {@link CallDiagnosticService}'s {@link Executor}; see + * {@link CallDiagnosticService#getExecutor()} for more information. + * * @param call The diagnostic call which is no longer tracked by Telecom. */ public abstract void onRemoveDiagnosticCall(@NonNull DiagnosticCall call); @@ -169,6 +210,9 @@ public abstract class CallDiagnosticService extends Service { * changes. * <p> * Audio state is common to all calls. + * <p> + * Calls to this method will use the {@link CallDiagnosticService}'s {@link Executor}; see + * {@link CallDiagnosticService#getExecutor()} for more information. * * @param audioState The new audio state. */ @@ -178,6 +222,10 @@ public abstract class CallDiagnosticService extends Service { /** * Telecom calls this method when a {@link BluetoothCallQualityReport} is received from the * bluetooth stack. + * <p> + * Calls to this method will use the {@link CallDiagnosticService}'s {@link Executor}; see + * {@link CallDiagnosticService#getExecutor()} for more information. + * * @param qualityReport the {@link BluetoothCallQualityReport}. */ public abstract void onBluetoothCallQualityReportReceived( @@ -199,15 +247,22 @@ public abstract class CallDiagnosticService extends Service { String telecomCallId = parcelableCall.getId(); Log.i(this, "handleCallAdded: callId=%s - added", telecomCallId); Call.Details newCallDetails = Call.Details.createFromParcelableCall(parcelableCall); - mCallByTelecomCallId.put(telecomCallId, newCallDetails); - - DiagnosticCall diagnosticCall = onInitializeDiagnosticCall(newCallDetails); - if (diagnosticCall == null) { - throw new IllegalArgumentException("A valid DiagnosticCall instance was not provided."); + synchronized (mLock) { + mCallByTelecomCallId.put(telecomCallId, newCallDetails); } - diagnosticCall.setListener(mDiagnosticCallListener); - diagnosticCall.setCallId(telecomCallId); - mDiagnosticCallByTelecomCallId.put(telecomCallId, diagnosticCall); + + getExecutor().execute(() -> { + DiagnosticCall diagnosticCall = onInitializeDiagnosticCall(newCallDetails); + if (diagnosticCall == null) { + throw new IllegalArgumentException( + "A valid DiagnosticCall instance was not provided."); + } + synchronized (mLock) { + diagnosticCall.setListener(mDiagnosticCallListener); + diagnosticCall.setCallId(telecomCallId); + mDiagnosticCallByTelecomCallId.put(telecomCallId, diagnosticCall); + } + }); } /** @@ -220,10 +275,12 @@ public abstract class CallDiagnosticService extends Service { String telecomCallId = parcelableCall.getId(); Log.i(this, "handleCallUpdated: callId=%s - updated", telecomCallId); Call.Details newCallDetails = Call.Details.createFromParcelableCall(parcelableCall); - - DiagnosticCall diagnosticCall = mDiagnosticCallByTelecomCallId.get(telecomCallId); - mCallByTelecomCallId.put(telecomCallId, newCallDetails); - diagnosticCall.handleCallUpdated(newCallDetails); + DiagnosticCall diagnosticCall; + synchronized (mLock) { + diagnosticCall = mDiagnosticCallByTelecomCallId.get(telecomCallId); + mCallByTelecomCallId.put(telecomCallId, newCallDetails); + } + getExecutor().execute(() -> diagnosticCall.handleCallUpdated(newCallDetails)); } /** @@ -236,10 +293,19 @@ public abstract class CallDiagnosticService extends Service { if (mCallByTelecomCallId.containsKey(telecomCallId)) { mCallByTelecomCallId.remove(telecomCallId); } - if (mDiagnosticCallByTelecomCallId.containsKey(telecomCallId)) { - DiagnosticCall call = mDiagnosticCallByTelecomCallId.remove(telecomCallId); - // Inform the service of the removed call. - onRemoveDiagnosticCall(call); + + DiagnosticCall diagnosticCall; + synchronized (mLock) { + if (mDiagnosticCallByTelecomCallId.containsKey(telecomCallId)) { + diagnosticCall = mDiagnosticCallByTelecomCallId.remove(telecomCallId); + } else { + diagnosticCall = null; + } + } + + // Inform the service of the removed call. + if (diagnosticCall != null) { + getExecutor().execute(() -> onRemoveDiagnosticCall(diagnosticCall)); } } @@ -252,8 +318,14 @@ public abstract class CallDiagnosticService extends Service { */ private void handleReceivedD2DMessage(@NonNull String callId, int message, int value) { Log.i(this, "handleReceivedD2DMessage: callId=%s, msg=%d/%d", callId, message, value); - DiagnosticCall diagnosticCall = mDiagnosticCallByTelecomCallId.get(callId); - diagnosticCall.onReceiveDeviceToDeviceMessage(message, value); + DiagnosticCall diagnosticCall; + synchronized (mLock) { + diagnosticCall = mDiagnosticCallByTelecomCallId.get(callId); + } + if (diagnosticCall != null) { + getExecutor().execute( + () -> diagnosticCall.onReceiveDeviceToDeviceMessage(message, value)); + } } /** @@ -265,7 +337,7 @@ public abstract class CallDiagnosticService extends Service { private void handleBluetoothCallQualityReport(@NonNull BluetoothCallQualityReport qualityReport) { Log.i(this, "handleBluetoothCallQualityReport; report=%s", qualityReport); - onBluetoothCallQualityReportReceived(qualityReport); + getExecutor().execute(() -> onBluetoothCallQualityReportReceived(qualityReport)); } /** diff --git a/telecomm/java/android/telecom/DiagnosticCall.java b/telecomm/java/android/telecom/DiagnosticCall.java index a4952899eb46..af46b7759fb5 100644 --- a/telecomm/java/android/telecom/DiagnosticCall.java +++ b/telecomm/java/android/telecom/DiagnosticCall.java @@ -26,15 +26,27 @@ import android.telephony.ims.ImsReasonInfo; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; +import java.util.concurrent.Executor; /** * A {@link DiagnosticCall} provides a way for a {@link CallDiagnosticService} to receive diagnostic - * information about a mobile call on the device. The {@link CallDiagnosticService} can generate - * mid-call diagnostic messages using the {@link #displayDiagnosticMessage(int, CharSequence)} API - * which provides the user with valuable information about conditions impacting their call and - * corrective actions. For example, if the {@link CallDiagnosticService} determines that conditions - * on the call are degrading, it can inform the user that the call may soon drop and that they - * can try using a different calling method (e.g. VOIP or WIFI). + * information about a mobile call on the device. A {@link DiagnosticCall} is similar to a + * {@link Call}, however it does not expose call control capabilities and exposes extra diagnostic + * and messaging capabilities not present on a {@link Call}. The {@link CallDiagnosticService} + * creates a {@link DiagnosticCall} for each {@link Call} on the device. This means that for each + * in progress call on the device, the {@link CallDiagnosticService} will create an instance of + * {@link DiagnosticCall}. + * <p> + * The {@link CallDiagnosticService} can generate mid-call diagnostic messages using the + * {@link #displayDiagnosticMessage(int, CharSequence)} API which provides the user with valuable + * information about conditions impacting their call and corrective actions. For example, if the + * {@link CallDiagnosticService} determines that conditions on the call are degrading, it can inform + * the user that the call may soon drop and that they can try using a different calling method + * (e.g. VOIP or WIFI). + * <h2>Threading Model</h2> + * All incoming IPC from Telecom in this class will use the same {@link Executor} as the + * {@link CallDiagnosticService}. See {@link CallDiagnosticService#setExecutor(Executor)} for more + * information. * @hide */ @SystemApi @@ -53,15 +65,19 @@ public abstract class DiagnosticCall { /** * Device to device message sent via {@link #sendDeviceToDeviceMessage(int, int)} (received via * {@link #onReceiveDeviceToDeviceMessage(int, int)}) which communicates the radio access type - * used for the current call. Based loosely on the - * {@link android.telephony.TelephonyManager#getNetworkType(int)} for the call, provides a - * high level summary of the call radio access type. + * used for the current call. The call network type communicated here is an intentional + * simplification of the {@link android.telephony.TelephonyManager#getNetworkType(int)} which + * removes some of the resolution inherent in those values; the + * {@link android.telephony.TelephonyManager#NETWORK_TYPE_LTE_CA} value, for example is + * collapsed into the {@link android.telephony.TelephonyManager#NETWORK_TYPE_LTE} value for + * efficiency of transport. For a discussion on the necessity of this simplification, see + * {@link #sendDeviceToDeviceMessage(int, int)}. * <p> - * Valid values: + * Valid values are below: * <UL> - * <LI>{@link #NETWORK_TYPE_LTE}</LI> - * <LI>{@link #NETWORK_TYPE_IWLAN}</LI> - * <LI>{@link #NETWORK_TYPE_NR}</LI> + * <LI>{@link android.telephony.TelephonyManager#NETWORK_TYPE_LTE}</LI> + * <LI>{@link android.telephony.TelephonyManager#NETWORK_TYPE_IWLAN}</LI> + * <LI>{@link android.telephony.TelephonyManager#NETWORK_TYPE_NR}</LI> * </UL> */ public static final int MESSAGE_CALL_NETWORK_TYPE = 1; @@ -69,14 +85,21 @@ public abstract class DiagnosticCall { /** * Device to device message sent via {@link #sendDeviceToDeviceMessage(int, int)} (received via * {@link #onReceiveDeviceToDeviceMessage(int, int)}) which communicates the call audio codec - * used for the current call. Based loosely on the {@link Connection#EXTRA_AUDIO_CODEC} for a - * call. + * used for the current call. + * <p> + * The audio codec communicated here is an intentional simplification of the + * {@link Connection#EXTRA_AUDIO_CODEC} for a call and focuses on communicating the most common + * variants of these audio codecs. Other variants of these codecs are reported as the next + * closest variant. For example, the {@link Connection#AUDIO_CODEC_EVS_FB} full band codec + * is reported via device to device communication as {@link Connection#AUDIO_CODEC_EVS_WB}. + * For a discussion on the necessity of this simplification, see + * {@link #sendDeviceToDeviceMessage(int, int)}. * <p> * Valid values: * <UL> - * <LI>{@link #AUDIO_CODEC_EVS}</LI> - * <LI>{@link #AUDIO_CODEC_AMR_WB}</LI> - * <LI>{@link #AUDIO_CODEC_AMR_NB}</LI> + * <LI>{@link Connection#AUDIO_CODEC_EVS_WB}</LI> + * <LI>{@link Connection#AUDIO_CODEC_AMR_WB}</LI> + * <LI>{@link Connection#AUDIO_CODEC_AMR}</LI> * </UL> */ public static final int MESSAGE_CALL_AUDIO_CODEC = 2; @@ -122,41 +145,6 @@ public abstract class DiagnosticCall { public @interface MessageType {} /** - * Used with {@link #MESSAGE_CALL_NETWORK_TYPE} to indicate an LTE network is being used for the - * call. - */ - public static final int NETWORK_TYPE_LTE = 1; - - /** - * Used with {@link #MESSAGE_CALL_NETWORK_TYPE} to indicate WIFI calling is in use for the call. - */ - public static final int NETWORK_TYPE_IWLAN = 2; - - /** - * Used with {@link #MESSAGE_CALL_NETWORK_TYPE} to indicate a 5G NR (new radio) network is in - * used for the call. - */ - public static final int NETWORK_TYPE_NR = 3; - - /** - * Used with {@link #MESSAGE_CALL_AUDIO_CODEC} to indicate call audio is using the - * Enhanced Voice Services (EVS) codec for the call. - */ - public static final int AUDIO_CODEC_EVS = 1; - - /** - * Used with {@link #MESSAGE_CALL_AUDIO_CODEC} to indicate call audio is using the AMR - * (adaptive multi-rate) WB (wide band) audio codec. - */ - public static final int AUDIO_CODEC_AMR_WB = 2; - - /** - * Used with {@link #MESSAGE_CALL_AUDIO_CODEC} to indicate call audio is using the AMR - * (adaptive multi-rate) NB (narrow band) audio codec. - */ - public static final int AUDIO_CODEC_AMR_NB = 3; - - /** * Used with {@link #MESSAGE_DEVICE_BATTERY_STATE} to indicate that the battery is low. */ public static final int BATTERY_STATE_LOW = 1; @@ -183,7 +171,6 @@ public abstract class DiagnosticCall { private Listener mListener; private String mCallId; - private Call.Details mCallDetails; /** * @hide @@ -210,16 +197,10 @@ public abstract class DiagnosticCall { } /** - * Returns the latest {@link Call.Details} associated with this {@link DiagnosticCall} as - * reported by {@link #onCallDetailsChanged(Call.Details)}. - * @return The latest {@link Call.Details}. - */ - public @NonNull Call.Details getCallDetails() { - return mCallDetails; - } - - /** * Telecom calls this method when the details of a call changes. + * <p> + * Calls to this method will use the same {@link Executor} as the {@link CallDiagnosticService}; + * see {@link CallDiagnosticService#getExecutor()} for more information. */ public abstract void onCallDetailsChanged(@NonNull android.telecom.Call.Details details); @@ -234,6 +215,9 @@ public abstract class DiagnosticCall { * devices communicating are using a different version of the protocol, messages the recipient * are not aware of are silently discarded. This means an older client talking to a new client * will not receive newer messages and values sent by the new client. + * <p> + * Calls to this method will use the same {@link Executor} as the {@link CallDiagnosticService}; + * see {@link CallDiagnosticService#getExecutor()} for more information. */ public abstract void onReceiveDeviceToDeviceMessage( @MessageType int message, @@ -253,39 +237,19 @@ public abstract class DiagnosticCall { * platform due to the extreme bandwidth constraints inherent with underlying device to device * communication transports used by the telephony framework. Device to device communication is * either accomplished by adding RFC8285 compliant RTP header extensions to the audio packets - * for a call, or using the DTMF digits A-D as a communication pathway. Signalling requirements - * for DTMF digits place a significant limitation on the amount of information which can be - * communicated during a call. + * for a call, or using the DTMF digits A-D as a communication pathway. RTP header extension + * packets ride alongside a the audio for a call, and are thus limited to roughly a byte for + * a message. Signalling requirements for DTMF digits place even more significant limitations + * on the amount of information which can be communicated during a call, offering only a few + * bits of potential information per message. The messages and values are constrained in order + * to meet the limited bandwidth inherent with DTMF signalling. * <p> - * Allowed message types and values are: + * Allowed message types are: * <ul> - * <li>{@link #MESSAGE_CALL_NETWORK_TYPE} - * <ul> - * <li>{@link #NETWORK_TYPE_LTE}</li> - * <li>{@link #NETWORK_TYPE_IWLAN}</li> - * <li>{@link #NETWORK_TYPE_NR}</li> - * </ul> - * </li> - * <li>{@link #MESSAGE_CALL_AUDIO_CODEC} - * <ul> - * <li>{@link #AUDIO_CODEC_EVS}</li> - * <li>{@link #AUDIO_CODEC_AMR_WB}</li> - * <li>{@link #AUDIO_CODEC_AMR_NB}</li> - * </ul> - * </li> - * <li>{@link #MESSAGE_DEVICE_BATTERY_STATE} - * <ul> - * <li>{@link #BATTERY_STATE_LOW}</li> - * <li>{@link #BATTERY_STATE_GOOD}</li> - * <li>{@link #BATTERY_STATE_CHARGING}</li> - * </ul> - * </li> - * <li>{@link #MESSAGE_DEVICE_NETWORK_COVERAGE} - * <ul> - * <li>{@link #COVERAGE_POOR}</li> - * <li>{@link #COVERAGE_GOOD}</li> - * </ul> - * </li> + * <li>{@link #MESSAGE_CALL_NETWORK_TYPE}</LI> + * <li>{@link #MESSAGE_CALL_AUDIO_CODEC}</LI> + * <li>{@link #MESSAGE_DEVICE_BATTERY_STATE}</LI> + * <li>{@link #MESSAGE_DEVICE_NETWORK_COVERAGE}</LI> * </ul> * @param message The message type to send. * @param value The message value corresponding to the type. @@ -307,6 +271,9 @@ public abstract class DiagnosticCall { * @param preciseDisconnectCause the precise disconnect cause for the call. * @return the disconnect message to use in place of the default Telephony message, or * {@code null} if the default message will not be overridden. + * <p> + * Calls to this method will use the same {@link Executor} as the {@link CallDiagnosticService}; + * see {@link CallDiagnosticService#getExecutor()} for more information. */ // TODO: Wire in Telephony support for this. public abstract @Nullable CharSequence onCallDisconnected( @@ -323,6 +290,9 @@ public abstract class DiagnosticCall { * @param disconnectReason The {@link ImsReasonInfo} associated with the call disconnection. * @return A user-readable call disconnect message to use in place of the platform-generated * disconnect message, or {@code null} if the disconnect message should not be overridden. + * <p> + * Calls to this method will use the same {@link Executor} as the {@link CallDiagnosticService}; + * see {@link CallDiagnosticService#getExecutor()} for more information. */ // TODO: Wire in Telephony support for this. public abstract @Nullable CharSequence onCallDisconnected( @@ -332,6 +302,9 @@ public abstract class DiagnosticCall { * Telecom calls this method when a {@link CallQuality} report is received from the telephony * stack for a call. * @param callQuality The call quality report for this call. + * <p> + * Calls to this method will use the same {@link Executor} as the {@link CallDiagnosticService}; + * see {@link CallDiagnosticService#getExecutor()} for more information. */ public abstract void onCallQualityReceived(@NonNull CallQuality callQuality); @@ -375,7 +348,6 @@ public abstract class DiagnosticCall { * @hide */ public void handleCallUpdated(@NonNull Call.Details newDetails) { - mCallDetails = newDetails; onCallDetailsChanged(newDetails); } } diff --git a/telephony/java/android/telephony/SubscriptionManager.java b/telephony/java/android/telephony/SubscriptionManager.java index 2d5f5fb58306..f7580d77186d 100644 --- a/telephony/java/android/telephony/SubscriptionManager.java +++ b/telephony/java/android/telephony/SubscriptionManager.java @@ -602,6 +602,43 @@ public class SubscriptionManager { public @interface SimDisplayNameSource {} /** + * Device status is not shared to a remote party. + */ + public static final int D2D_SHARING_DISABLED = 0; + + /** + * Device status is shared with all numbers in the user's contacts. + */ + public static final int D2D_SHARING_ALL_CONTACTS = 1; + + /** + * Device status is shared with all starred contacts. + */ + public static final int D2D_SHARING_STARRED_CONTACTS = 2; + + /** + * Device status is shared whenever possible. + */ + public static final int D2D_SHARING_ALL = 3; + + /** @hide */ + @Retention(RetentionPolicy.SOURCE) + @IntDef(prefix = {"D2D_SHARING_"}, + value = { + D2D_SHARING_DISABLED, + D2D_SHARING_ALL_CONTACTS, + D2D_SHARING_STARRED_CONTACTS, + D2D_SHARING_ALL + }) + public @interface DeviceToDeviceStatusSharing {} + + /** + * TelephonyProvider column name for device to device sharing status. + * <P>Type: INTEGER (int)</P> + */ + public static final String D2D_STATUS_SHARING = SimInfo.COLUMN_D2D_STATUS_SHARING; + + /** * TelephonyProvider column name for the color of a SIM. * <P>Type: INTEGER (int)</P> */ @@ -3374,6 +3411,36 @@ public class SubscriptionManager { } /** + * Set the device to device status sharing user preference for a subscription ID. The setting + * app uses this method to indicate with whom they wish to share device to device status + * information. + * @param sharing the status sharing preference + * @param subId the unique Subscription ID in database + */ + @RequiresPermission(Manifest.permission.MODIFY_PHONE_STATE) + public void setDeviceToDeviceStatusSharing(@DeviceToDeviceStatusSharing int sharing, + int subId) { + if (VDBG) { + logd("[setDeviceToDeviceStatusSharing] + sharing: " + sharing + " subId: " + subId); + } + setSubscriptionPropertyHelper(subId, "setDeviceToDeviceSharingStatus", + (iSub)->iSub.setDeviceToDeviceStatusSharing(sharing, subId)); + } + + /** + * Returns the user-chosen device to device status sharing preference + * @param subId Subscription id of subscription + * @return The device to device status sharing preference + */ + public @DeviceToDeviceStatusSharing int getDeviceToDeviceStatusSharing(int subId) { + if (VDBG) { + logd("[getDeviceToDeviceStatusSharing] + subId: " + subId); + } + return getIntegerSubscriptionProperty(subId, D2D_STATUS_SHARING, D2D_SHARING_DISABLED, + mContext); + } + + /** * DO NOT USE. * This API is designed for features that are not finished at this point. Do not call this API. * @hide diff --git a/telephony/java/android/telephony/TelephonyManager.java b/telephony/java/android/telephony/TelephonyManager.java index 2546bbe5f5f6..4dc6c7ce35cf 100644 --- a/telephony/java/android/telephony/TelephonyManager.java +++ b/telephony/java/android/telephony/TelephonyManager.java @@ -139,6 +139,8 @@ import java.util.Objects; import java.util.UUID; import java.util.concurrent.Executor; import java.util.function.Consumer; +import java.util.stream.Collectors; +import java.util.stream.IntStream; /** * Provides access to information about the telephony services on @@ -3147,6 +3149,10 @@ public class TelephonyManager { return NETWORK_TYPE_BITMASK_LTE_CA; case NETWORK_TYPE_NR: return NETWORK_TYPE_BITMASK_NR; + case NETWORK_TYPE_IWLAN: + return NETWORK_TYPE_BITMASK_IWLAN; + case NETWORK_TYPE_IDEN: + return (1 << (NETWORK_TYPE_IDEN - 1)); default: return NETWORK_TYPE_BITMASK_UNKNOWN; } @@ -8642,8 +8648,8 @@ public class TelephonyManager { public static final int ALLOWED_NETWORK_TYPES_REASON_ENABLE_2G = 3; /** - * Set the allowed network types of the device and - * provide the reason triggering the allowed network change. + * Set the allowed network types of the device and provide the reason triggering the allowed + * network change. * This can be called for following reasons * <ol> * <li>Allowed network types control by USER {@link #ALLOWED_NETWORK_TYPES_REASON_USER} @@ -8655,10 +8661,15 @@ public class TelephonyManager { * </ol> * This API will result in allowing an intersection of allowed network types for all reasons, * including the configuration done through other reasons. + * + * The functionality of this API with the parameter + * {@link #ALLOWED_NETWORK_TYPES_REASON_CARRIER} is the same as the API + * {@link TelephonyManager#setAllowedNetworkTypes}. Use this API instead of + * {@link TelephonyManager#setAllowedNetworkTypes}. * <p> * If {@link android.telephony.TelephonyManager#isRadioInterfaceCapabilitySupported} * ({@link TelephonyManager#CAPABILITY_ALLOWED_NETWORK_TYPES_USED}) returns true, then - * setAllowedNetworkTypesBitmap is used on the radio interface. Otherwise, + * setAllowedNetworkTypesBitmap is used on the radio interface. Otherwise, * setPreferredNetworkTypesBitmap is used instead. * * @param reason the reason the allowed network type change is taking place @@ -8698,21 +8709,17 @@ public class TelephonyManager { * {@link #getAllowedNetworkTypesForReason} returns allowed network type for a * specific reason. * - * <p>Requires Permission: - * {@link android.Manifest.permission#READ_PRIVILEGED_PHONE_STATE READ_PRIVILEGED_PHONE_STATE} - * or that the calling app has carrier privileges (see {@link #hasCarrierPrivileges}). - * * @param reason the reason the allowed network type change is taking place * @return the allowed network type bitmask * @throws IllegalStateException if the Telephony process is not currently available. * @throws IllegalArgumentException if invalid AllowedNetworkTypesReason is passed. * @hide */ - @SystemApi @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) @RequiresFeature( enforcement = "android.telephony.TelephonyManager#isRadioInterfaceCapabilitySupported", value = TelephonyManager.CAPABILITY_ALLOWED_NETWORK_TYPES_USED) + @SystemApi public @NetworkTypeBitMask long getAllowedNetworkTypesForReason( @AllowedNetworkTypesReason int reason) { if (!isValidAllowedNetworkTypesReason(reason)) { @@ -8757,6 +8764,25 @@ public class TelephonyManager { } /** + * Returns a string representation of the allowed network types{@link NetworkTypeBitMask}. + * + * @param networkTypeBitmask The bitmask of allowed network types. + * @return the name of the allowed network types + * @hide + */ + public static String convertNetworkTypeBitmaskToString( + @NetworkTypeBitMask long networkTypeBitmask) { + String networkTypeName = IntStream.rangeClosed(NETWORK_TYPE_GPRS, NETWORK_TYPE_NR) + .filter(x -> { + return (networkTypeBitmask & getBitMaskForNetworkType(x)) + == getBitMaskForNetworkType(x); + }) + .mapToObj(x -> getNetworkTypeName(x)) + .collect(Collectors.joining("|")); + return TextUtils.isEmpty(networkTypeName) ? "UNKNOWN" : networkTypeName; + } + + /** * Set the preferred network type to global mode which includes LTE, CDMA, EvDo and GSM/WCDMA. * * <p>Requires that the calling app has carrier privileges (see {@link #hasCarrierPrivileges}). @@ -12577,6 +12603,7 @@ public class TelephonyManager { NETWORK_TYPE_BITMASK_LTE, NETWORK_TYPE_BITMASK_LTE_CA, NETWORK_TYPE_BITMASK_NR, + NETWORK_TYPE_BITMASK_IWLAN }) public @interface NetworkTypeBitMask {} @@ -15216,13 +15243,17 @@ public class TelephonyManager { * </ul> * @param appType icc application type, like {@link #APPTYPE_USIM} or {@link * #APPTYPE_ISIM} or {@link#APPTYPE_UNKNOWN} - * @param nafId Network Application Function(NAF) fully qualified domain name and - * the selected GBA mode. It shall contain two parts delimited by "@" sign. The first - * part is the constant string "3GPP-bootstrapping" (GBA_ME), - * "3GPP-bootstrapping-uicc" (GBA_ U), or "3GPP-bootstrapping-digest" (GBA_Digest), - * and the latter part shall be the FQDN of the NAF (e.g. - * "3GPP-bootstrapping@naf1.operator.com" or "3GPP-bootstrapping-uicc@naf1.operator.com", - * or "3GPP-bootstrapping-digest@naf1.operator.com"). + * @param nafId A URI to specify Network Application Function(NAF) fully qualified domain + * name (FQDN) and the selected GBA mode. The authority of the URI must contain two parts + * delimited by "@" sign. The first part is the constant string "3GPP-bootstrapping" (GBA_ME), + * "3GPP-bootstrapping-uicc" (GBA_ U), or "3GPP-bootstrapping-digest" (GBA_Digest). + * The second part shall be the FQDN of the NAF. The scheme of the URI is not actually used + * for the authentication, which may be set the same as the resource that the application is + * going to access. For example, the nafId can be + * "https://3GPP-bootstrapping@naf1.operator.com", + * "https://3GPP-bootstrapping-uicc@naf1.operator.com", + * "https://3GPP-bootstrapping-digest@naf1.operator.com", + * "ftps://3GPP-bootstrapping-digest@naf1.operator.com". * @param securityProtocol Security protocol identifier between UE and NAF. See * 3GPP TS 33.220 Annex H. Application can use * {@link UaSecurityProtocolIdentifier#createDefaultUaSpId}, diff --git a/telephony/java/android/telephony/data/DataCallResponse.java b/telephony/java/android/telephony/data/DataCallResponse.java index a76422977cb6..ffe5399e406b 100644 --- a/telephony/java/android/telephony/data/DataCallResponse.java +++ b/telephony/java/android/telephony/data/DataCallResponse.java @@ -18,6 +18,7 @@ package android.telephony.data; import android.annotation.IntDef; +import android.annotation.IntRange; import android.annotation.NonNull; import android.annotation.Nullable; import android.annotation.SystemApi; @@ -29,6 +30,7 @@ import android.telephony.DataFailCause; import android.telephony.data.ApnSetting.ProtocolType; import com.android.internal.annotations.VisibleForTesting; +import com.android.internal.util.Preconditions; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; @@ -812,11 +814,19 @@ public final class DataCallResponse implements Parcelable { /** * Set pdu session id. + * <p/> + * The id must be between 1 and 15 when linked to a pdu session. If no pdu session + * exists for the current data call, the id must be set to {@link PDU_SESSION_ID_NOT_SET}. * * @param pduSessionId Pdu Session Id of the data call. * @return The same instance of the builder. */ - public @NonNull Builder setPduSessionId(int pduSessionId) { + public @NonNull Builder setPduSessionId( + @IntRange(from = PDU_SESSION_ID_NOT_SET, to = 15) int pduSessionId) { + Preconditions.checkArgument(pduSessionId >= PDU_SESSION_ID_NOT_SET, + "pduSessionId must be greater than or equal to" + PDU_SESSION_ID_NOT_SET); + Preconditions.checkArgument(pduSessionId <= 15, + "pduSessionId must be less than or equal to 15."); mPduSessionId = pduSessionId; return this; } diff --git a/telephony/java/android/telephony/data/DataService.java b/telephony/java/android/telephony/data/DataService.java index f5f29c65b7cd..048b3297a1b4 100644 --- a/telephony/java/android/telephony/data/DataService.java +++ b/telephony/java/android/telephony/data/DataService.java @@ -41,6 +41,7 @@ import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import java.util.ArrayList; import java.util.List; +import java.util.Objects; /** * Base class of data service. Services that extend DataService must register the service in @@ -284,11 +285,11 @@ public abstract class DataService extends Service { * * Any resources being transferred cannot be released while a * handover is underway. - * + * <p/> * If a handover was unsuccessful, then the framework calls * {@link DataService#cancelHandover}. The target transport retains ownership over any of * the resources being transferred. - * + * <p/> * If a handover was successful, the framework calls {@link DataService#deactivateDataCall} * with reason {@link DataService.REQUEST_REASON_HANDOVER}. The target transport now owns * the transferred resources and is responsible for releasing them. @@ -299,21 +300,27 @@ public abstract class DataService extends Service { * @hide */ public void startHandover(int cid, @NonNull DataServiceCallback callback) { + Objects.requireNonNull(callback, "callback cannot be null"); // The default implementation is to return unsupported. - if (callback != null) { - Log.d(TAG, "startHandover: " + cid); - callback.onHandoverStarted(DataServiceCallback.RESULT_ERROR_UNSUPPORTED); - } else { - Log.e(TAG, "startHandover: " + cid + ", callback is null"); - } + Log.d(TAG, "startHandover: " + cid); + callback.onHandoverStarted(DataServiceCallback.RESULT_ERROR_UNSUPPORTED); } /** * Indicates that a handover was cancelled after a call to * {@link DataService#startHandover}. This is called on the source transport. - * + * <p/> * Since the handover was unsuccessful, the source transport retains ownership over any of * the resources being transferred and is still responsible for releasing them. + * <p/> + * The handover can be cancelled up until either: + * <ul><li> + * The handover was successful after receiving a successful response from + * {@link DataService#setupDataCall} on the target transport. + * </li><li> + * The data call on the source transport was lost. + * </li> + * </ul> * * @param cid The identifier of the data call which is provided in {@link DataCallResponse} * @param callback The result callback for this request. @@ -321,13 +328,10 @@ public abstract class DataService extends Service { * @hide */ public void cancelHandover(int cid, @NonNull DataServiceCallback callback) { + Objects.requireNonNull(callback, "callback cannot be null"); // The default implementation is to return unsupported. - if (callback != null) { - Log.d(TAG, "cancelHandover: " + cid); - callback.onHandoverCancelled(DataServiceCallback.RESULT_ERROR_UNSUPPORTED); - } else { - Log.e(TAG, "cancelHandover: " + cid + ", callback is null"); - } + Log.d(TAG, "cancelHandover: " + cid); + callback.onHandoverCancelled(DataServiceCallback.RESULT_ERROR_UNSUPPORTED); } /** diff --git a/telephony/java/android/telephony/ims/ProvisioningManager.java b/telephony/java/android/telephony/ims/ProvisioningManager.java index 85cd81bb4eb5..abc5606e6743 100644 --- a/telephony/java/android/telephony/ims/ProvisioningManager.java +++ b/telephony/java/android/telephony/ims/ProvisioningManager.java @@ -1010,6 +1010,16 @@ public class ProvisioningManager { } } + @Override + public void onPreProvisioningReceived(byte[] configXml) { + final long identity = Binder.clearCallingIdentity(); + try { + mExecutor.execute(() -> mLocalCallback.onPreProvisioningReceived(configXml)); + } finally { + Binder.restoreCallingIdentity(identity); + } + } + private void setExecutor(Executor executor) { mExecutor = executor; } @@ -1022,7 +1032,7 @@ public class ProvisioningManager { * due to various triggers defined in GSMA RCC.14 for ACS(auto configuration * server) or other operator defined triggers. If RCS provisioning is already * completed at the time of callback registration, then this method shall be - * invoked with the current configuration + * invoked with the current configuration. * @param configXml The RCS configuration XML received by OTA. It is defined * by GSMA RCC.07. */ @@ -1055,6 +1065,20 @@ public class ProvisioningManager { */ public void onRemoved() {} + /** + * Some carriers using ACS (auto configuration server) may send a carrier-specific + * pre-provisioning configuration XML if the user has not been provisioned for RCS + * services yet. When this provisioning XML is received, the framework will move + * into a "not provisioned" state for RCS. In order for provisioning to proceed, + * the application must parse this configuration XML and perform the carrier specific + * opt-in flow for RCS services. If the user accepts, {@link #triggerRcsReconfiguration} + * must be called in order for the device to move out of this state and try to fetch + * the RCS provisioning information. + * + * @param configXml the pre-provisioning config in carrier specified format. + */ + public void onPreProvisioningReceived(@NonNull byte[] configXml) {} + /**@hide*/ public final IRcsConfigCallback getBinder() { return mBinder; diff --git a/telephony/java/android/telephony/ims/RcsContactPresenceTuple.java b/telephony/java/android/telephony/ims/RcsContactPresenceTuple.java index cedf48b0b8e1..9c28c36521f5 100644 --- a/telephony/java/android/telephony/ims/RcsContactPresenceTuple.java +++ b/telephony/java/android/telephony/ims/RcsContactPresenceTuple.java @@ -25,7 +25,6 @@ import android.os.Build; import android.os.Parcel; import android.os.Parcelable; import android.text.TextUtils; -import android.util.Log; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; @@ -389,22 +388,6 @@ public final class RcsContactPresenceTuple implements Parcelable { * The optional timestamp indicating the data and time of the status change of this tuple. * Per RFC3863 section 4.1.7, the timestamp is formatted as an IMPP datetime format * string per RFC3339. - * @hide - */ - public @NonNull Builder setTimestamp(@NonNull String timestamp) { - try { - mPresenceTuple.mTimestamp = - DateTimeFormatter.ISO_OFFSET_DATE_TIME.parse(timestamp, Instant::from); - } catch (DateTimeParseException e) { - Log.d(LOG_TAG, "Parse timestamp failed " + e); - } - return this; - } - - /** - * The optional timestamp indicating the data and time of the status change of this tuple. - * Per RFC3863 section 4.1.7, the timestamp is formatted as an IMPP datetime format - * string per RFC3339. */ public @NonNull Builder setTime(@NonNull Instant timestamp) { mPresenceTuple.mTimestamp = timestamp; @@ -534,14 +517,6 @@ public final class RcsContactPresenceTuple implements Parcelable { return mContactUri; } - /** - * @return the timestamp element contained in the tuple if it exists - * @hide - */ - public @Nullable String getTimestamp() { - return (mTimestamp == null) ? null : mTimestamp.toString(); - } - /** @return the timestamp element contained in the tuple if it exists */ public @Nullable Instant getTime() { return mTimestamp; diff --git a/telephony/java/android/telephony/ims/RcsUceAdapter.java b/telephony/java/android/telephony/ims/RcsUceAdapter.java index 815c08d120c2..dd9102699529 100644 --- a/telephony/java/android/telephony/ims/RcsUceAdapter.java +++ b/telephony/java/android/telephony/ims/RcsUceAdapter.java @@ -439,8 +439,7 @@ public class RcsUceAdapter { /** * The pending request has resulted in an error and may need to be retried, depending on the - * error code. The callback {@link #onCapabilitiesReceived(List)} - * for each contacts is required to be called before {@link #onError} is called. + * error code. * @param errorCode The reason for the framework being unable to process the request. * @param retryIntervalMillis The time in milliseconds the requesting application should * wait before retrying, if non-zero. @@ -487,93 +486,6 @@ public class RcsUceAdapter { * becomes inactive. See {@link ImsException#getCode()} for more information on the error codes. * @hide */ - @RequiresPermission(allOf = {Manifest.permission.ACCESS_RCS_USER_CAPABILITY_EXCHANGE, - Manifest.permission.READ_CONTACTS}) - public void requestCapabilities(@NonNull List<Uri> contactNumbers, - @NonNull @CallbackExecutor Executor executor, - @NonNull CapabilitiesCallback c) throws ImsException { - if (c == null) { - throw new IllegalArgumentException("Must include a non-null CapabilitiesCallback."); - } - if (executor == null) { - throw new IllegalArgumentException("Must include a non-null Executor."); - } - if (contactNumbers == null) { - throw new IllegalArgumentException("Must include non-null contact number list."); - } - - IImsRcsController imsRcsController = getIImsRcsController(); - if (imsRcsController == null) { - Log.e(TAG, "requestCapabilities: IImsRcsController is null"); - throw new ImsException("Can not find remote IMS service", - ImsException.CODE_ERROR_SERVICE_UNAVAILABLE); - } - - IRcsUceControllerCallback internalCallback = new IRcsUceControllerCallback.Stub() { - @Override - public void onCapabilitiesReceived(List<RcsContactUceCapability> contactCapabilities) { - final long callingIdentity = Binder.clearCallingIdentity(); - try { - executor.execute(() -> c.onCapabilitiesReceived(contactCapabilities)); - } finally { - restoreCallingIdentity(callingIdentity); - } - } - @Override - public void onComplete() { - final long callingIdentity = Binder.clearCallingIdentity(); - try { - executor.execute(() -> c.onComplete()); - } finally { - restoreCallingIdentity(callingIdentity); - } - } - @Override - public void onError(int errorCode, long retryAfterMilliseconds) { - final long callingIdentity = Binder.clearCallingIdentity(); - try { - executor.execute(() -> c.onError(errorCode, retryAfterMilliseconds)); - } finally { - restoreCallingIdentity(callingIdentity); - } - } - }; - - try { - imsRcsController.requestCapabilities(mSubId, mContext.getOpPackageName(), - mContext.getAttributionTag(), contactNumbers, internalCallback); - } catch (ServiceSpecificException e) { - throw new ImsException(e.toString(), e.errorCode); - } catch (RemoteException e) { - Log.e(TAG, "Error calling IImsRcsController#requestCapabilities", e); - throw new ImsException("Remote IMS Service is not available", - ImsException.CODE_ERROR_SERVICE_UNAVAILABLE); - } - } - - /** - * Request the User Capability Exchange capabilities for one or more contacts. - * <p> - * This will return the cached capabilities of the contact and will not perform a capability - * poll on the network unless there are contacts being queried with stale information. - * <p> - * Be sure to check the availability of this feature using - * {@link ImsRcsManager#isAvailable(int, int)} and ensuring - * {@link RcsFeature.RcsImsCapabilities#CAPABILITY_TYPE_OPTIONS_UCE} or - * {@link RcsFeature.RcsImsCapabilities#CAPABILITY_TYPE_PRESENCE_UCE} is enabled or else - * this operation will fail with {@link #ERROR_NOT_AVAILABLE} or {@link #ERROR_NOT_ENABLED}. - * - * @param contactNumbers A list of numbers that the capabilities are being requested for. - * @param executor The executor that will be used when the request is completed and the - * {@link CapabilitiesCallback} is called. - * @param c A one-time callback for when the request for capabilities completes or there is an - * error processing the request. - * @throws ImsException if the subscription associated with this instance of - * {@link RcsUceAdapter} is valid, but the ImsService associated with the subscription is not - * available. This can happen if the ImsService has crashed, for example, or if the subscription - * becomes inactive. See {@link ImsException#getCode()} for more information on the error codes. - * @hide - */ @SystemApi @RequiresPermission(allOf = {Manifest.permission.ACCESS_RCS_USER_CAPABILITY_EXCHANGE, Manifest.permission.READ_CONTACTS}) diff --git a/telephony/java/android/telephony/ims/aidl/IRcsConfigCallback.aidl b/telephony/java/android/telephony/ims/aidl/IRcsConfigCallback.aidl index 5a8973e37bce..d0853d1846ac 100644 --- a/telephony/java/android/telephony/ims/aidl/IRcsConfigCallback.aidl +++ b/telephony/java/android/telephony/ims/aidl/IRcsConfigCallback.aidl @@ -25,5 +25,6 @@ oneway interface IRcsConfigCallback { void onAutoConfigurationErrorReceived(int errorCode, String errorString); void onConfigurationReset(); void onRemoved(); + void onPreProvisioningReceived(in byte[] config); } diff --git a/telephony/java/android/telephony/ims/stub/ImsConfigImplBase.java b/telephony/java/android/telephony/ims/stub/ImsConfigImplBase.java index 21aeb64bb417..d75da9035124 100644 --- a/telephony/java/android/telephony/ims/stub/ImsConfigImplBase.java +++ b/telephony/java/android/telephony/ims/stub/ImsConfigImplBase.java @@ -552,11 +552,34 @@ public class ImsConfigImplBase { } mRcsCallbacks.broadcastAction(c -> { try { - //TODO compressed by default? c.onAutoConfigurationErrorReceived(errorCode, errorString); } catch (RemoteException e) { Log.w(TAG, "dead binder in notifyAutoConfigurationErrorReceived, skipping."); } }); } + + /** + * Notifies application that pre-provisioning config is received. + * + * <p>Some carriers using ACS (auto configuration server) may send a carrier-specific + * pre-provisioning configuration XML if the user has not been provisioned for RCS + * services yet. When such provisioning XML is received, ACS client must call this + * method to notify the application with the XML. + * + * @param configXml the pre-provisioning config in carrier specified format. + */ + public final void notifyPreProvisioningReceived(@NonNull byte[] configXml) { + // can be null in testing + if (mRcsCallbacks == null) { + return; + } + mRcsCallbacks.broadcastAction(c -> { + try { + c.onPreProvisioningReceived(configXml); + } catch (RemoteException e) { + Log.w(TAG, "dead binder in notifyPreProvisioningReceived, skipping."); + } + }); + } } diff --git a/telephony/java/android/telephony/ims/stub/RcsCapabilityExchangeImplBase.java b/telephony/java/android/telephony/ims/stub/RcsCapabilityExchangeImplBase.java index 00c91681d9ea..03e17fbc2c0d 100644 --- a/telephony/java/android/telephony/ims/stub/RcsCapabilityExchangeImplBase.java +++ b/telephony/java/android/telephony/ims/stub/RcsCapabilityExchangeImplBase.java @@ -386,41 +386,6 @@ public class RcsCapabilityExchangeImplBase { * {@link SubscribeResponseCallback#onTerminated(String, long)} must be called for the * framework to finish listening for NOTIFY responses. * - * @param uris A {@link List} of the {@link Uri}s that the framework is requesting the UCE - * capabilities for. - * @param cb The callback of the subscribe request. - * @hide - */ - // executor used is defined in the constructor. - @SuppressLint("ExecutorRegistration") - public void subscribeForCapabilities(@NonNull List<Uri> uris, - @NonNull SubscribeResponseCallback cb) { - // Stub - to be implemented by service - Log.w(LOG_TAG, "subscribeForCapabilities called with no implementation."); - try { - cb.onCommandError(COMMAND_CODE_NOT_SUPPORTED); - } catch (ImsException e) { - // Do not do anything, this is a stub implementation. - } - } - - /** - * The user capabilities of one or multiple contacts have been requested by the framework. - * <p> - * The implementer must follow up this call with an - * {@link SubscribeResponseCallback#onCommandError} call to indicate this operation has failed. - * The response from the network to the SUBSCRIBE request must be sent back to the framework - * using {@link SubscribeResponseCallback#onNetworkResponse(int, String)}. - * As NOTIFY requests come in from the network, the requested contact’s capabilities should be - * sent back to the framework using - * {@link SubscribeResponseCallback#onNotifyCapabilitiesUpdate(List<String>}) and - * {@link SubscribeResponseCallback#onResourceTerminated(List<Pair<Uri, String>>)} - * should be called with the presence information for the contacts specified. - * <p> - * Once the subscription is terminated, - * {@link SubscribeResponseCallback#onTerminated(String, long)} must be called for the - * framework to finish listening for NOTIFY responses. - * * @param uris A {@link Collection} of the {@link Uri}s that the framework is requesting the * UCE capabilities for. * @param cb The callback of the subscribe request. diff --git a/telephony/java/com/android/internal/telephony/ISub.aidl b/telephony/java/com/android/internal/telephony/ISub.aidl index 571efcee0e15..9493c76d9a57 100755 --- a/telephony/java/com/android/internal/telephony/ISub.aidl +++ b/telephony/java/com/android/internal/telephony/ISub.aidl @@ -300,4 +300,6 @@ interface ISub { boolean canDisablePhysicalSubscription(); int setUiccApplicationsEnabled(boolean enabled, int subscriptionId); + + int setDeviceToDeviceStatusSharing(int sharing, int subId); } diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/ime/CloseImeAutoOpenWindowToAppTest.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/ime/CloseImeAutoOpenWindowToAppTest.kt index 17aa1d14a447..47eaddfa1f3a 100644 --- a/tests/FlickerTests/src/com/android/server/wm/flicker/ime/CloseImeAutoOpenWindowToAppTest.kt +++ b/tests/FlickerTests/src/com/android/server/wm/flicker/ime/CloseImeAutoOpenWindowToAppTest.kt @@ -17,6 +17,7 @@ package com.android.server.wm.flicker.ime import android.app.Instrumentation +import android.platform.test.annotations.Postsubmit import android.platform.test.annotations.Presubmit import android.view.Surface import androidx.test.filters.FlakyTest @@ -88,40 +89,40 @@ class CloseImeAutoOpenWindowToAppTest(private val testSpec: FlickerTestParameter } } - @Presubmit + @Postsubmit @Test fun navBarWindowIsAlwaysVisible() = testSpec.navBarWindowIsAlwaysVisible() - @Presubmit + @Postsubmit @Test fun statusBarWindowIsAlwaysVisible() = testSpec.statusBarWindowIsAlwaysVisible() - @Presubmit + @Postsubmit @Test fun visibleWindowsShownMoreThanOneConsecutiveEntry() = testSpec.visibleWindowsShownMoreThanOneConsecutiveEntry(listOf(IME_WINDOW_TITLE)) - @Presubmit + @Postsubmit @Test fun imeAppWindowIsAlwaysVisible() = testSpec.imeAppWindowIsAlwaysVisible(testApp) - @Presubmit + @Postsubmit @Test fun navBarLayerIsAlwaysVisible() = testSpec.navBarLayerIsAlwaysVisible() - @Presubmit + @Postsubmit @Test fun statusBarLayerIsAlwaysVisible() = testSpec.statusBarLayerIsAlwaysVisible() - @Presubmit + @Postsubmit @Test fun noUncoveredRegions() = testSpec.noUncoveredRegions(testSpec.config.startRotation) - @Presubmit + @Postsubmit @Test fun imeLayerBecomesInvisible() = testSpec.imeLayerBecomesInvisible() - @Presubmit + @Postsubmit @Test fun imeAppLayerIsAlwaysVisible() = testSpec.imeAppLayerIsAlwaysVisible(testApp) diff --git a/tests/Input/Android.bp b/tests/Input/Android.bp index 335c8d0127eb..eacf5b287a2e 100644 --- a/tests/Input/Android.bp +++ b/tests/Input/Android.bp @@ -9,14 +9,17 @@ package { android_test { name: "InputTests", - srcs: ["src/**/*.kt"], + srcs: [ + "src/**/*.java", + "src/**/*.kt", + ], platform_apis: true, certificate: "platform", static_libs: [ - "androidx.test.ext.junit", - "androidx.test.rules", - "truth-prebuilt", - "ub-uiautomator", - ], + "androidx.test.ext.junit", + "androidx.test.rules", + "truth-prebuilt", + "ub-uiautomator", + ], test_suites: ["device-tests"], } diff --git a/tests/Input/src/com/android/test/input/InputDeviceTest.java b/tests/Input/src/com/android/test/input/InputDeviceTest.java new file mode 100644 index 000000000000..63500774816a --- /dev/null +++ b/tests/Input/src/com/android/test/input/InputDeviceTest.java @@ -0,0 +1,98 @@ +/* + * Copyright (C) 2021 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package android.view; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertTrue; + +import android.os.Parcel; + +import androidx.test.ext.junit.runners.AndroidJUnit4; +import androidx.test.filters.SmallTest; + +import org.junit.Test; +import org.junit.runner.RunWith; + +@SmallTest +@RunWith(AndroidJUnit4.class) +public class InputDeviceTest { + private static final float DELTA = 0.01f; + private static final int DEVICE_ID = 1000; + + private void assertMotionRangeEquals(InputDevice.MotionRange range, + InputDevice.MotionRange outRange) { + assertEquals(range.getAxis(), outRange.getAxis()); + assertEquals(range.getSource(), outRange.getSource()); + assertEquals(range.getMin(), outRange.getMin(), DELTA); + assertEquals(range.getMax(), outRange.getMax(), DELTA); + assertEquals(range.getFlat(), outRange.getFlat(), DELTA); + assertEquals(range.getFuzz(), outRange.getFuzz(), DELTA); + assertEquals(range.getResolution(), outRange.getResolution(), DELTA); + } + + private void assertDeviceEquals(InputDevice device, InputDevice outDevice) { + assertEquals(device.getId(), outDevice.getId()); + assertEquals(device.getGeneration(), outDevice.getGeneration()); + assertEquals(device.getControllerNumber(), outDevice.getControllerNumber()); + assertEquals(device.getName(), outDevice.getName()); + assertEquals(device.getVendorId(), outDevice.getVendorId()); + assertEquals(device.getProductId(), outDevice.getProductId()); + assertEquals(device.getDescriptor(), outDevice.getDescriptor()); + assertEquals(device.isExternal(), outDevice.isExternal()); + assertEquals(device.getSources(), outDevice.getSources()); + assertEquals(device.getKeyboardType(), outDevice.getKeyboardType()); + assertEquals(device.getMotionRanges().size(), outDevice.getMotionRanges().size()); + + KeyCharacterMap keyCharacterMap = device.getKeyCharacterMap(); + KeyCharacterMap outKeyCharacterMap = outDevice.getKeyCharacterMap(); + assertTrue("keyCharacterMap not equal", keyCharacterMap.equals(outKeyCharacterMap)); + + for (int j = 0; j < device.getMotionRanges().size(); j++) { + assertMotionRangeEquals(device.getMotionRanges().get(j), + outDevice.getMotionRanges().get(j)); + } + } + + private void assertInputDeviceParcelUnparcel(KeyCharacterMap keyCharacterMap) { + final InputDevice device = + new InputDevice(DEVICE_ID, 0 /* generation */, 0 /* controllerNumber */, "name", + 0 /* vendorId */, 0 /* productId */, "descriptor", true /* isExternal */, + 0 /* sources */, 0 /* keyboardType */, keyCharacterMap, + false /* hasVibrator */, false /* hasMicrophone */, false /* hasButtonUnderpad */, + true /* hasSensor */, false /* hasBattery */); + + Parcel parcel = Parcel.obtain(); + device.writeToParcel(parcel, 0); + parcel.setDataPosition(0); + + InputDevice outDevice = InputDevice.CREATOR.createFromParcel(parcel); + assertDeviceEquals(device, outDevice); + } + + @Test + public void testParcelUnparcelInputDevice_VirtualCharacterMap() { + final KeyCharacterMap keyCharacterMap = + KeyCharacterMap.load(KeyCharacterMap.VIRTUAL_KEYBOARD); + assertInputDeviceParcelUnparcel(keyCharacterMap); + } + + @Test + public void testParcelUnparcelInputDevice_EmptyCharacterMap() { + final KeyCharacterMap keyCharacterMap = KeyCharacterMap.obtainEmptyMap(DEVICE_ID); + assertInputDeviceParcelUnparcel(keyCharacterMap); + } +} diff --git a/tests/vcn/java/com/android/server/VcnManagementServiceTest.java b/tests/vcn/java/com/android/server/VcnManagementServiceTest.java index 11498dec8165..a02002752c38 100644 --- a/tests/vcn/java/com/android/server/VcnManagementServiceTest.java +++ b/tests/vcn/java/com/android/server/VcnManagementServiceTest.java @@ -593,6 +593,16 @@ public class VcnManagementServiceTest { mVcnMgmtSvc.removeVcnUnderlyingNetworkPolicyListener(mMockPolicyListener); } + @Test(expected = SecurityException.class) + public void testRemoveVcnUnderlyingNetworkPolicyListenerInvalidPermission() { + doThrow(new SecurityException()) + .when(mMockContext) + .enforceCallingOrSelfPermission( + eq(android.Manifest.permission.NETWORK_FACTORY), any()); + + mVcnMgmtSvc.removeVcnUnderlyingNetworkPolicyListener(mMockPolicyListener); + } + @Test public void testRemoveVcnUnderlyingNetworkPolicyListenerNeverRegistered() { mVcnMgmtSvc.removeVcnUnderlyingNetworkPolicyListener(mMockPolicyListener); |