diff options
68 files changed, 930 insertions, 423 deletions
diff --git a/core/api/current.txt b/core/api/current.txt index ba5f62396025..5fcafc7104bc 100644 --- a/core/api/current.txt +++ b/core/api/current.txt @@ -6943,6 +6943,7 @@ package android.app.admin { method @Nullable public String onChoosePrivateKeyAlias(@NonNull android.content.Context, @NonNull android.content.Intent, int, @Nullable android.net.Uri, @Nullable String); method public void onNetworkLogsAvailable(@NonNull android.content.Context, @NonNull android.content.Intent, long, @IntRange(from=1) int); method public final void onReceive(@NonNull android.content.Context, @NonNull android.content.Intent); + method public void onSecurityLogsAvailable(@NonNull android.content.Context, @NonNull android.content.Intent); } public final class DeviceAdminInfo implements android.os.Parcelable { @@ -7020,6 +7021,7 @@ package android.app.admin { field public static final String ACTION_PASSWORD_FAILED = "android.app.action.ACTION_PASSWORD_FAILED"; field public static final String ACTION_PASSWORD_SUCCEEDED = "android.app.action.ACTION_PASSWORD_SUCCEEDED"; field public static final String ACTION_PROFILE_PROVISIONING_COMPLETE = "android.app.action.PROFILE_PROVISIONING_COMPLETE"; + field public static final String ACTION_SECURITY_LOGS_AVAILABLE = "android.app.action.SECURITY_LOGS_AVAILABLE"; field public static final int BUGREPORT_FAILURE_FAILED_COMPLETING = 0; // 0x0 field public static final int BUGREPORT_FAILURE_FILE_NO_LONGER_AVAILABLE = 1; // 0x1 field public static final String DEVICE_ADMIN_META_DATA = "android.app.device_admin"; @@ -7315,6 +7317,7 @@ package android.app.admin { field public static final String DELEGATION_NETWORK_LOGGING = "delegation-network-logging"; field public static final String DELEGATION_PACKAGE_ACCESS = "delegation-package-access"; field public static final String DELEGATION_PERMISSION_GRANT = "delegation-permission-grant"; + field public static final String DELEGATION_SECURITY_LOGGING = "delegation-security-logging"; field public static final int ENCRYPTION_STATUS_ACTIVATING = 2; // 0x2 field public static final int ENCRYPTION_STATUS_ACTIVE = 3; // 0x3 field public static final int ENCRYPTION_STATUS_ACTIVE_DEFAULT_KEY = 4; // 0x4 @@ -41803,7 +41806,7 @@ package android.telephony { method @NonNull public android.os.Bundle getCarrierConfigValues(); method @Deprecated public static android.telephony.SmsManager getDefault(); method public static int getDefaultSmsSubscriptionId(); - method @RequiresPermission(android.Manifest.permission.READ_PHONE_STATE) public int getSmsCapacityOnIcc(); + method @IntRange(from=0) @RequiresPermission(anyOf={android.Manifest.permission.READ_PHONE_STATE, "android.permission.READ_PRIVILEGED_PHONE_STATE"}) public int getSmsCapacityOnIcc(); method @Deprecated public static android.telephony.SmsManager getSmsManagerForSubscriptionId(int); method @RequiresPermission(android.Manifest.permission.SMS_FINANCIAL_TRANSACTIONS) public void getSmsMessagesForFinancialApp(android.os.Bundle, @NonNull java.util.concurrent.Executor, @NonNull android.telephony.SmsManager.FinancialSmsCallback); method @Nullable @RequiresPermission("android.permission.READ_PRIVILEGED_PHONE_STATE") public String getSmscAddress(); diff --git a/core/java/android/app/ActivityManagerInternal.java b/core/java/android/app/ActivityManagerInternal.java index c812e8e1782a..f7a35143916e 100644 --- a/core/java/android/app/ActivityManagerInternal.java +++ b/core/java/android/app/ActivityManagerInternal.java @@ -450,6 +450,21 @@ public abstract class ActivityManagerInternal { public abstract boolean hasRunningForegroundService(int uid, int foregroundServiceType); /** + * Returns {@code true} if the given notification channel currently has a + * notification associated with a foreground service. This is an AMS check + * because that is the source of truth for the FGS state. + */ + public abstract boolean hasForegroundServiceNotification(String pkg, @UserIdInt int userId, + String channelId); + + /** + * If the given app has any FGSs whose notifications are in the given channel, + * stop them. + */ + public abstract void stopForegroundServicesForChannel(String pkg, @UserIdInt int userId, + String channelId); + + /** * Registers the specified {@code processObserver} to be notified of future changes to * process state. */ diff --git a/core/java/android/app/admin/DelegatedAdminReceiver.java b/core/java/android/app/admin/DelegatedAdminReceiver.java index 25b8eab452bf..36097c928bb0 100644 --- a/core/java/android/app/admin/DelegatedAdminReceiver.java +++ b/core/java/android/app/admin/DelegatedAdminReceiver.java @@ -18,6 +18,7 @@ package android.app.admin; import static android.app.admin.DeviceAdminReceiver.ACTION_CHOOSE_PRIVATE_KEY_ALIAS; import static android.app.admin.DeviceAdminReceiver.ACTION_NETWORK_LOGS_AVAILABLE; +import static android.app.admin.DeviceAdminReceiver.ACTION_SECURITY_LOGS_AVAILABLE; import static android.app.admin.DeviceAdminReceiver.EXTRA_CHOOSE_PRIVATE_KEY_ALIAS; import static android.app.admin.DeviceAdminReceiver.EXTRA_CHOOSE_PRIVATE_KEY_SENDER_UID; import static android.app.admin.DeviceAdminReceiver.EXTRA_CHOOSE_PRIVATE_KEY_URI; @@ -115,6 +116,29 @@ public class DelegatedAdminReceiver extends BroadcastReceiver { } /** + * Called each time a new batch of security logs can be retrieved. This callback method will + * only ever be called when security logging is enabled. The logs can only be retrieved while + * security logging is enabled. + * + * <p>If a secondary user or profile is created, this callback won't be received until all users + * become affiliated again (even if security logging is enabled). It will also no longer be + * possible to retrieve the security logs. See {@link DevicePolicyManager#setAffiliationIds}. + * + * <p> This callback is only applicable if the delegated app has + * {@link DevicePolicyManager#DELEGATION_SECURITY_LOGGING} capability. Additionally, it must + * declare an intent filter for {@link DeviceAdminReceiver#ACTION_SECURITY_LOGS_AVAILABLE} in + * the receiver's manifest in order to receive this callback. The default implementation + * simply throws {@link UnsupportedOperationException}. + * + * @param context The running context as per {@link #onReceive}. + * @param intent The received intent as per {@link #onReceive}. + * @see DevicePolicyManager#retrieveSecurityLogs + */ + public void onSecurityLogsAvailable(@NonNull Context context, @NonNull Intent intent) { + throw new UnsupportedOperationException("onSecurityLogsAvailable should be implemented"); + } + + /** * Intercept delegated device administrator broadcasts. Implementations should not override * this method; implement the convenience callbacks for each action instead. */ @@ -132,6 +156,8 @@ public class DelegatedAdminReceiver extends BroadcastReceiver { long batchToken = intent.getLongExtra(EXTRA_NETWORK_LOGS_TOKEN, -1); int networkLogsCount = intent.getIntExtra(EXTRA_NETWORK_LOGS_COUNT, 0); onNetworkLogsAvailable(context, intent, batchToken, networkLogsCount); + } else if (ACTION_SECURITY_LOGS_AVAILABLE.equals(action)) { + onSecurityLogsAvailable(context, intent); } else { Log.w(TAG, "Unhandled broadcast: " + action); } diff --git a/core/java/android/app/admin/DeviceAdminReceiver.java b/core/java/android/app/admin/DeviceAdminReceiver.java index cccc9294c2d5..747a2de80db0 100644 --- a/core/java/android/app/admin/DeviceAdminReceiver.java +++ b/core/java/android/app/admin/DeviceAdminReceiver.java @@ -290,7 +290,6 @@ public class DeviceAdminReceiver extends BroadcastReceiver { /** * Broadcast action: notify that a new batch of security logs is ready to be collected. - * @hide */ @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION) @BroadcastBehavior(explicitOnly = true) diff --git a/core/java/android/app/admin/DevicePolicyManager.java b/core/java/android/app/admin/DevicePolicyManager.java index 594b0051a113..426159f43095 100644 --- a/core/java/android/app/admin/DevicePolicyManager.java +++ b/core/java/android/app/admin/DevicePolicyManager.java @@ -1905,6 +1905,20 @@ public class DevicePolicyManager { public static final String DELEGATION_CERT_SELECTION = "delegation-cert-selection"; /** + * Grants access to {@link #setSecurityLoggingEnabled}, {@link #isSecurityLoggingEnabled}, + * {@link #retrieveSecurityLogs}, and {@link #retrievePreRebootSecurityLogs}. Once granted the + * delegated app will start receiving {@link DelegatedAdminReceiver#onSecurityLogsAvailable} + * callback, and Device owner or Profile Owner will no longer receive the + * {@link DeviceAdminReceiver#onSecurityLogsAvailable} callback. There can be at most one app + * that has this delegation. If another app already had delegated security logging access, it + * will lose the delegation when a new app is delegated. + * + * <p> Can only be granted by Device Owner or Profile Owner of an organnization owned and + * managed profile. + */ + public static final String DELEGATION_SECURITY_LOGGING = "delegation-security-logging"; + + /** * No management for current user in-effect. This is the default. * @hide */ @@ -11241,7 +11255,7 @@ public class DevicePolicyManager { public void setSecurityLoggingEnabled(@NonNull ComponentName admin, boolean enabled) { throwIfParentInstance("setSecurityLoggingEnabled"); try { - mService.setSecurityLoggingEnabled(admin, enabled); + mService.setSecurityLoggingEnabled(admin, mContext.getPackageName(), enabled); } catch (RemoteException re) { throw re.rethrowFromSystemServer(); } @@ -11260,7 +11274,7 @@ public class DevicePolicyManager { public boolean isSecurityLoggingEnabled(@Nullable ComponentName admin) { throwIfParentInstance("isSecurityLoggingEnabled"); try { - return mService.isSecurityLoggingEnabled(admin); + return mService.isSecurityLoggingEnabled(admin, mContext.getPackageName()); } catch (RemoteException re) { throw re.rethrowFromSystemServer(); } @@ -11285,10 +11299,12 @@ public class DevicePolicyManager { * @see #isAffiliatedUser * @see DeviceAdminReceiver#onSecurityLogsAvailable */ + @SuppressLint("NullableCollection") public @Nullable List<SecurityEvent> retrieveSecurityLogs(@NonNull ComponentName admin) { throwIfParentInstance("retrieveSecurityLogs"); try { - ParceledListSlice<SecurityEvent> list = mService.retrieveSecurityLogs(admin); + ParceledListSlice<SecurityEvent> list = mService.retrieveSecurityLogs( + admin, mContext.getPackageName()); if (list != null) { return list.getList(); } else { @@ -11438,11 +11454,13 @@ public class DevicePolicyManager { * @see #isAffiliatedUser * @see #retrieveSecurityLogs */ + @SuppressLint("NullableCollection") public @Nullable List<SecurityEvent> retrievePreRebootSecurityLogs( @NonNull ComponentName admin) { throwIfParentInstance("retrievePreRebootSecurityLogs"); try { - ParceledListSlice<SecurityEvent> list = mService.retrievePreRebootSecurityLogs(admin); + ParceledListSlice<SecurityEvent> list = mService.retrievePreRebootSecurityLogs( + admin, mContext.getPackageName()); if (list != null) { return list.getList(); } else { diff --git a/core/java/android/app/admin/IDevicePolicyManager.aidl b/core/java/android/app/admin/IDevicePolicyManager.aidl index e98720c0d96c..7901791fc7d4 100644 --- a/core/java/android/app/admin/IDevicePolicyManager.aidl +++ b/core/java/android/app/admin/IDevicePolicyManager.aidl @@ -386,10 +386,10 @@ interface IDevicePolicyManager { List<String> getAffiliationIds(in ComponentName admin); boolean isAffiliatedUser(); - void setSecurityLoggingEnabled(in ComponentName admin, boolean enabled); - boolean isSecurityLoggingEnabled(in ComponentName admin); - ParceledListSlice retrieveSecurityLogs(in ComponentName admin); - ParceledListSlice retrievePreRebootSecurityLogs(in ComponentName admin); + void setSecurityLoggingEnabled(in ComponentName admin, String packageName, boolean enabled); + boolean isSecurityLoggingEnabled(in ComponentName admin, String packageName); + ParceledListSlice retrieveSecurityLogs(in ComponentName admin, String packageName); + ParceledListSlice retrievePreRebootSecurityLogs(in ComponentName admin, String packageName); long forceNetworkLogs(); long forceSecurityLogs(); diff --git a/core/java/android/appwidget/AppWidgetHostView.java b/core/java/android/appwidget/AppWidgetHostView.java index 8fd0de7dbb39..a6b4b47f0db2 100644 --- a/core/java/android/appwidget/AppWidgetHostView.java +++ b/core/java/android/appwidget/AppWidgetHostView.java @@ -520,9 +520,7 @@ public class AppWidgetHostView extends FrameLayout { return; } int layoutId = rvToApply.getLayoutId(); - // If our stale view has been prepared to match active, and the new - // layout matches, try recycling it - if (content == null && layoutId == mLayoutId) { + if (rvToApply.canRecycleView(mView)) { try { rvToApply.reapply(mContext, mView, mInteractionHandler, mCurrentSize, mColorResources); diff --git a/core/java/android/hardware/biometrics/ComponentInfoInternal.java b/core/java/android/hardware/biometrics/ComponentInfoInternal.java index fa34e0b4f0f2..3b61a56bd9f1 100644 --- a/core/java/android/hardware/biometrics/ComponentInfoInternal.java +++ b/core/java/android/hardware/biometrics/ComponentInfoInternal.java @@ -27,11 +27,11 @@ import android.os.Parcelable; */ public class ComponentInfoInternal implements Parcelable { - public final String componentId; - public final String hardwareVersion; - public final String firmwareVersion; - public final String serialNumber; - public final String softwareVersion; + @NonNull public final String componentId; + @NonNull public final String hardwareVersion; + @NonNull public final String firmwareVersion; + @NonNull public final String serialNumber; + @NonNull public final String softwareVersion; /** * Constructs a {@link ComponentInfoInternal} from another instance. @@ -45,8 +45,9 @@ public class ComponentInfoInternal implements Parcelable { /** * @hide */ - public ComponentInfoInternal(String componentId, String hardwareVersion, - String firmwareVersion, String serialNumber, String softwareVersion) { + public ComponentInfoInternal(@NonNull String componentId, @NonNull String hardwareVersion, + @NonNull String firmwareVersion, @NonNull String serialNumber, + @NonNull String softwareVersion) { this.componentId = componentId; this.hardwareVersion = hardwareVersion; this.firmwareVersion = firmwareVersion; diff --git a/core/java/android/hardware/biometrics/SensorPropertiesInternal.java b/core/java/android/hardware/biometrics/SensorPropertiesInternal.java index eda0ded42cdd..17b2abf9f5d1 100644 --- a/core/java/android/hardware/biometrics/SensorPropertiesInternal.java +++ b/core/java/android/hardware/biometrics/SensorPropertiesInternal.java @@ -34,7 +34,7 @@ public class SensorPropertiesInternal implements Parcelable { public final int sensorId; @SensorProperties.Strength public final int sensorStrength; public final int maxEnrollmentsPerUser; - public final List<ComponentInfoInternal> componentInfo; + @NonNull public final List<ComponentInfoInternal> componentInfo; public final boolean resetLockoutRequiresHardwareAuthToken; public final boolean resetLockoutRequiresChallenge; diff --git a/core/java/android/hardware/camera2/CameraManager.java b/core/java/android/hardware/camera2/CameraManager.java index a3c6f2f1eafd..b7b1a147c822 100644 --- a/core/java/android/hardware/camera2/CameraManager.java +++ b/core/java/android/hardware/camera2/CameraManager.java @@ -2030,7 +2030,9 @@ public final class CameraManager { // Tell listeners that the cameras and torch modes are unavailable and schedule a // reconnection to camera service. When camera service is reconnected, the camera // and torch statuses will be updated. - for (int i = 0; i < mDeviceStatus.size(); i++) { + // Iterate from the end to the beginning befcause onStatusChangedLocked removes + // entries from the ArrayMap. + for (int i = mDeviceStatus.size() - 1; i >= 0; i--) { String cameraId = mDeviceStatus.keyAt(i); onStatusChangedLocked(ICameraServiceListener.STATUS_NOT_PRESENT, cameraId); } diff --git a/core/java/android/hardware/face/FaceSensorProperties.java b/core/java/android/hardware/face/FaceSensorProperties.java index 6ddea5017088..f61312785919 100644 --- a/core/java/android/hardware/face/FaceSensorProperties.java +++ b/core/java/android/hardware/face/FaceSensorProperties.java @@ -17,6 +17,7 @@ package android.hardware.face; import android.annotation.IntDef; +import android.annotation.NonNull; import android.hardware.biometrics.ComponentInfoInternal; import android.hardware.biometrics.SensorProperties; @@ -74,7 +75,8 @@ public class FaceSensorProperties extends SensorProperties { * @hide */ public FaceSensorProperties(int sensorId, int sensorStrength, - List<ComponentInfo> componentInfo, @FaceSensorProperties.SensorType int sensorType) { + @NonNull List<ComponentInfo> componentInfo, + @FaceSensorProperties.SensorType int sensorType) { super(sensorId, sensorStrength, componentInfo); mSensorType = sensorType; } diff --git a/core/java/android/hardware/face/FaceSensorPropertiesInternal.java b/core/java/android/hardware/face/FaceSensorPropertiesInternal.java index 50ea60a2ff57..44dffb207731 100644 --- a/core/java/android/hardware/face/FaceSensorPropertiesInternal.java +++ b/core/java/android/hardware/face/FaceSensorPropertiesInternal.java @@ -16,6 +16,7 @@ package android.hardware.face; +import android.annotation.NonNull; import android.hardware.biometrics.ComponentInfoInternal; import android.hardware.biometrics.SensorProperties; import android.hardware.biometrics.SensorPropertiesInternal; @@ -48,7 +49,7 @@ public class FaceSensorPropertiesInternal extends SensorPropertiesInternal { * Initializes SensorProperties with specified values */ public FaceSensorPropertiesInternal(int sensorId, @SensorProperties.Strength int strength, - int maxEnrollmentsPerUser, List<ComponentInfoInternal> componentInfo, + int maxEnrollmentsPerUser, @NonNull List<ComponentInfoInternal> componentInfo, @FaceSensorProperties.SensorType int sensorType, boolean supportsFaceDetection, boolean supportsSelfIllumination, boolean resetLockoutRequiresChallenge) { // resetLockout is managed by the HAL and requires a HardwareAuthToken for all face diff --git a/core/java/android/hardware/fingerprint/FingerprintSensorProperties.java b/core/java/android/hardware/fingerprint/FingerprintSensorProperties.java index a3385752aaf3..71b705faba79 100644 --- a/core/java/android/hardware/fingerprint/FingerprintSensorProperties.java +++ b/core/java/android/hardware/fingerprint/FingerprintSensorProperties.java @@ -17,6 +17,7 @@ package android.hardware.fingerprint; import android.annotation.IntDef; +import android.annotation.NonNull; import android.hardware.biometrics.ComponentInfoInternal; import android.hardware.biometrics.SensorProperties; @@ -94,7 +95,7 @@ public class FingerprintSensorProperties extends SensorProperties { * @hide */ public FingerprintSensorProperties(int sensorId, int sensorStrength, - List<ComponentInfo> componentInfo, @SensorType int sensorType) { + @NonNull List<ComponentInfo> componentInfo, @SensorType int sensorType) { super(sensorId, sensorStrength, componentInfo); mSensorType = sensorType; } diff --git a/core/java/android/hardware/fingerprint/FingerprintSensorPropertiesInternal.java b/core/java/android/hardware/fingerprint/FingerprintSensorPropertiesInternal.java index 1b1337072f5e..58f6e62af320 100644 --- a/core/java/android/hardware/fingerprint/FingerprintSensorPropertiesInternal.java +++ b/core/java/android/hardware/fingerprint/FingerprintSensorPropertiesInternal.java @@ -62,7 +62,7 @@ public class FingerprintSensorPropertiesInternal extends SensorPropertiesInterna public FingerprintSensorPropertiesInternal(int sensorId, @SensorProperties.Strength int strength, int maxEnrollmentsPerUser, - List<ComponentInfoInternal> componentInfo, + @NonNull List<ComponentInfoInternal> componentInfo, @FingerprintSensorProperties.SensorType int sensorType, boolean resetLockoutRequiresHardwareAuthToken, int sensorLocationX, int sensorLocationY, int sensorRadius) { @@ -83,7 +83,7 @@ public class FingerprintSensorPropertiesInternal extends SensorPropertiesInterna */ public FingerprintSensorPropertiesInternal(int sensorId, @SensorProperties.Strength int strength, int maxEnrollmentsPerUser, - List<ComponentInfoInternal> componentInfo, + @NonNull List<ComponentInfoInternal> componentInfo, @FingerprintSensorProperties.SensorType int sensorType, boolean resetLockoutRequiresHardwareAuthToken) { // TODO(b/179175438): Value should be provided from the HAL @@ -99,7 +99,7 @@ public class FingerprintSensorPropertiesInternal extends SensorPropertiesInterna // TODO(b/179175438): Remove this constructor once all HALs move to AIDL. public FingerprintSensorPropertiesInternal(@NonNull Context context, int sensorId, @SensorProperties.Strength int strength, int maxEnrollmentsPerUser, - List<ComponentInfoInternal> componentInfo, + @NonNull List<ComponentInfoInternal> componentInfo, @FingerprintSensorProperties.SensorType int sensorType, boolean resetLockoutRequiresHardwareAuthToken) { super(sensorId, strength, maxEnrollmentsPerUser, componentInfo, diff --git a/core/java/android/hardware/location/ContextHubManager.java b/core/java/android/hardware/location/ContextHubManager.java index eaa8bd403e24..f69a7d7e5f16 100644 --- a/core/java/android/hardware/location/ContextHubManager.java +++ b/core/java/android/hardware/location/ContextHubManager.java @@ -60,8 +60,8 @@ public final class ContextHubManager { private static final String TAG = "ContextHubManager"; /** - * An extra containing an int from {@link AuthorizationState} describing the client's - * authorization state. + * An extra containing one of the {@code AUTHORIZATION_*} constants such as + * {@link #AUTHORIZATION_GRANTED} describing the client's authorization state. */ public static final String EXTRA_CLIENT_AUTHORIZATION_STATE = "android.hardware.location.extra.CLIENT_AUTHORIZATION_STATE"; diff --git a/core/java/android/util/Slog.java b/core/java/android/util/Slog.java index f61ab2985163..d3eaeae993e6 100644 --- a/core/java/android/util/Slog.java +++ b/core/java/android/util/Slog.java @@ -30,11 +30,11 @@ import java.util.Locale; */ public final class Slog { - @GuardedBy("sMessageBuilder") - private static final StringBuilder sMessageBuilder = new StringBuilder(); + @GuardedBy("Slog.class") + private static StringBuilder sMessageBuilder; - @GuardedBy("sMessageBuilder") - private static final Formatter sFormatter = new Formatter(sMessageBuilder, Locale.ENGLISH); + @GuardedBy("Slog.class") + private static Formatter sFormatter; private Slog() { } @@ -226,7 +226,12 @@ public final class Slog { } private static String getMessage(String format, @Nullable Object... args) { - synchronized (sMessageBuilder) { + synchronized (Slog.class) { + if (sMessageBuilder == null) { + // Lazy load so they're not created if not used by the process + sMessageBuilder = new StringBuilder(); + sFormatter = new Formatter(sMessageBuilder, Locale.ENGLISH); + } sFormatter.format(format, args); String message = sMessageBuilder.toString(); sMessageBuilder.setLength(0); diff --git a/core/java/android/view/View.java b/core/java/android/view/View.java index 35d5d8ec6c3d..7455b8bc3cf3 100644 --- a/core/java/android/view/View.java +++ b/core/java/android/view/View.java @@ -17,6 +17,7 @@ package android.view; import static android.content.res.Resources.ID_NULL; +import static android.view.ContentInfo.SOURCE_DRAG_AND_DROP; import static android.view.accessibility.AccessibilityEvent.CONTENT_CHANGE_TYPE_UNDEFINED; import static android.view.displayhash.DisplayHashResultCallback.DISPLAY_HASH_ERROR_INVALID_BOUNDS; import static android.view.displayhash.DisplayHashResultCallback.DISPLAY_HASH_ERROR_MISSING_WINDOW; @@ -26747,6 +26748,21 @@ public class View implements Drawable.Callback, KeyEvent.Callback, * {@link android.view.DragEvent#getAction()} returns one of the action type constants defined * in DragEvent. The method uses these to determine what is happening in the drag and drop * operation. + * </p> + * <p> + * The default implementation returns false, except if an {@link OnReceiveContentListener} + * is {@link #setOnReceiveContentListener set} for this view. If an + * {@link OnReceiveContentListener} is set, the default implementation... + * <ul> + * <li>returns true for an + * {@link android.view.DragEvent#ACTION_DRAG_STARTED ACTION_DRAG_STARTED} event + * <li>calls {@link #performReceiveContent} for an + * {@link android.view.DragEvent#ACTION_DROP ACTION_DROP} event + * <li>returns true for an {@link android.view.DragEvent#ACTION_DROP ACTION_DROP} event, if + * the listener consumed some or all of the content + * </ul> + * </p> + * * @param event The {@link android.view.DragEvent} sent by the system. * The {@link android.view.DragEvent#getAction()} method returns an action type constant defined * in DragEvent, indicating the type of drag event represented by this object. @@ -26766,6 +26782,24 @@ public class View implements Drawable.Callback, KeyEvent.Callback, * </p> */ public boolean onDragEvent(DragEvent event) { + if (mListenerInfo == null || mListenerInfo.mOnReceiveContentListener == null) { + return false; + } + // Accept drag events by default if there's an OnReceiveContentListener set. + if (event.getAction() == DragEvent.ACTION_DRAG_STARTED) { + return true; + } + if (event.getAction() == DragEvent.ACTION_DROP) { + final DragAndDropPermissions permissions = DragAndDropPermissions.obtain(event); + if (permissions != null) { + permissions.takeTransient(); + } + final ContentInfo payload = new ContentInfo.Builder( + event.getClipData(), SOURCE_DRAG_AND_DROP).build(); + ContentInfo remainingPayload = performReceiveContent(payload); + // Return true unless none of the payload was consumed. + return remainingPayload != payload; + } return false; } diff --git a/core/java/android/widget/EdgeEffect.java b/core/java/android/widget/EdgeEffect.java index 5f55887d6019..58dfc0df3573 100644 --- a/core/java/android/widget/EdgeEffect.java +++ b/core/java/android/widget/EdgeEffect.java @@ -117,12 +117,12 @@ public class EdgeEffect { /** * The natural frequency of the stretch spring. */ - private static final double NATURAL_FREQUENCY = 14.4222; + private static final double NATURAL_FREQUENCY = 17.55; /** * The damping ratio of the stretch spring. */ - private static final double DAMPING_RATIO = 0.875; + private static final double DAMPING_RATIO = 0.92; /** @hide */ @IntDef({TYPE_GLOW, TYPE_STRETCH}) diff --git a/core/java/android/widget/RemoteViews.java b/core/java/android/widget/RemoteViews.java index 2b73923fc5f4..319e78807684 100644 --- a/core/java/android/widget/RemoteViews.java +++ b/core/java/android/widget/RemoteViews.java @@ -2196,7 +2196,7 @@ public class RemoteViews implements Parcelable, Filter { int recycledViewIndex = findViewIndexToRecycle(target, rvToApply); if (recycledViewIndex >= 0) { View child = target.getChildAt(recycledViewIndex); - if (getViewLayoutId(child) == rvToApply.getLayoutId()) { + if (rvToApply.canRecycleView(child)) { if (nextChild < recycledViewIndex) { target.removeViews(nextChild, recycledViewIndex - nextChild); } @@ -2254,7 +2254,7 @@ public class RemoteViews implements Parcelable, Filter { // application are placed before. ViewTree recycled = target.mChildren.get(recycledViewIndex); // We can only recycle the view if the layout id is the same. - if (getViewLayoutId(recycled.mRoot) == rvToApply.getLayoutId()) { + if (rvToApply.canRecycleView(recycled.mRoot)) { if (recycledViewIndex > nextChild) { target.removeChildren(nextChild, recycledViewIndex - nextChild); } @@ -3726,7 +3726,8 @@ public class RemoteViews implements Parcelable, Filter { * * The {@code stableId} will be used to identify a potential view to recycled when the remote * view is inflated. Views can be re-used if inserted in the same order, potentially with - * some views appearing / disappearing. + * some views appearing / disappearing. To be recycled the view must not change the layout + * used to inflate it or its view id (see {@link RemoteViews#setViewId}). * * Note: if a view is re-used, all the actions will be re-applied on it. However, its properties * are not reset, so what was applied in previous round will have an effect. As a view may be @@ -5116,6 +5117,7 @@ public class RemoteViews implements Parcelable, Filter { View v = inflater.inflate(rv.getLayoutId(), parent, false); if (mViewId != View.NO_ID) { v.setId(mViewId); + v.setTagInternal(R.id.remote_views_override_id, mViewId); } v.setTagInternal(R.id.widget_frame, rv.getLayoutId()); return v; @@ -5335,6 +5337,24 @@ public class RemoteViews implements Parcelable, Filter { reapply(context, v, handler, size, colorResources, true); } + /** @hide */ + public boolean canRecycleView(@Nullable View v) { + if (v == null) { + return false; + } + Integer previousLayoutId = (Integer) v.getTag(R.id.widget_frame); + if (previousLayoutId == null) { + return false; + } + Integer overrideIdTag = (Integer) v.getTag(R.id.remote_views_override_id); + int overrideId = overrideIdTag == null ? View.NO_ID : overrideIdTag; + // If mViewId is View.NO_ID, we only recycle if overrideId is also View.NO_ID. + // Otherwise, it might be that, on a previous iteration, the view's ID was set to + // something else, and it should now be reset to the ID defined in the XML layout file, + // whatever it is. + return previousLayoutId == getLayoutId() && mViewId == overrideId; + } + // Note: topLevel should be true only for calls on the topLevel RemoteViews, internal calls // should set it to false. private void reapply(Context context, View v, InteractionHandler handler, SizeF size, @@ -5347,7 +5367,7 @@ public class RemoteViews implements Parcelable, Filter { // (orientation or size), we throw an exception, since the layouts may be completely // unrelated. if (hasMultipleLayouts()) { - if ((Integer) v.getTag(R.id.widget_frame) != rvToApply.getLayoutId()) { + if (!rvToApply.canRecycleView(v)) { throw new RuntimeException("Attempting to re-apply RemoteViews to a view that" + " that does not share the same root layout id."); } diff --git a/core/java/android/widget/TextView.java b/core/java/android/widget/TextView.java index dba7fa915f35..940a3c9cccdf 100644 --- a/core/java/android/widget/TextView.java +++ b/core/java/android/widget/TextView.java @@ -13071,11 +13071,37 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener return getLayout().getOffsetForHorizontal(line, x); } + /** + * Handles drag events sent by the system following a call to + * {@link android.view.View#startDragAndDrop(ClipData,DragShadowBuilder,Object,int) + * startDragAndDrop()}. + * + * <p>If this text view is not editable, delegates to the default {@link View#onDragEvent} + * implementation. + * + * <p>If this text view is editable, accepts all drag actions (returns true for an + * {@link android.view.DragEvent#ACTION_DRAG_STARTED ACTION_DRAG_STARTED} event and all + * subsequent drag events). While the drag is in progress, updates the cursor position + * to follow the touch location. Once a drop event is received, handles content insertion + * via {@link #performReceiveContent}. + * + * @param event The {@link android.view.DragEvent} sent by the system. + * The {@link android.view.DragEvent#getAction()} method returns an action type constant + * defined in DragEvent, indicating the type of drag event represented by this object. + * @return Returns true if this text view is editable and delegates to super otherwise. + * See {@link View#onDragEvent}. + */ @Override public boolean onDragEvent(DragEvent event) { + if (mEditor == null || !mEditor.hasInsertionController()) { + // If this TextView is not editable, defer to the default View implementation. This + // will check for the presence of an OnReceiveContentListener and accept/reject + // drag events depending on whether the listener is/isn't set. + return super.onDragEvent(event); + } switch (event.getAction()) { case DragEvent.ACTION_DRAG_STARTED: - return mEditor != null && mEditor.hasInsertionController(); + return true; case DragEvent.ACTION_DRAG_ENTERED: TextView.this.requestFocus(); diff --git a/core/java/com/android/internal/app/OWNERS b/core/java/com/android/internal/app/OWNERS index 7ade05cc6de1..e6c911e5b41d 100644 --- a/core/java/com/android/internal/app/OWNERS +++ b/core/java/com/android/internal/app/OWNERS @@ -3,6 +3,9 @@ per-file *Resolver* = file:/packages/SystemUI/OWNERS per-file *Chooser* = file:/packages/SystemUI/OWNERS per-file SimpleIconFactory.java = file:/packages/SystemUI/OWNERS per-file NetInitiatedActivity.java = file:/location/java/android/location/OWNERS -per-file IVoice* = file:/core/java/android/service/voice/OWNERS -per-file *Hotword* = file:/core/java/android/service/voice/OWNERS per-file *BatteryStats* = file:/BATTERY_STATS_OWNERS + +# Voice Interaction +per-file *Assist* = file:/core/java/android/service/voice/OWNERS +per-file *Hotword* = file:/core/java/android/service/voice/OWNERS +per-file *Voice* = file:/core/java/android/service/voice/OWNERS diff --git a/core/java/com/android/internal/widget/ViewPager.java b/core/java/com/android/internal/widget/ViewPager.java index 6f377b9b228a..93cde3ddb72d 100644 --- a/core/java/com/android/internal/widget/ViewPager.java +++ b/core/java/com/android/internal/widget/ViewPager.java @@ -353,8 +353,8 @@ public class ViewPager extends ViewGroup { mTouchSlop = configuration.getScaledPagingTouchSlop(); mMinimumVelocity = (int) (MIN_FLING_VELOCITY * density); mMaximumVelocity = configuration.getScaledMaximumFlingVelocity(); - mLeftEdge = new EdgeEffect(context); - mRightEdge = new EdgeEffect(context); + mLeftEdge = new EdgeEffect(context, attrs); + mRightEdge = new EdgeEffect(context, attrs); mFlingDistance = (int) (MIN_DISTANCE_FOR_FLING * density); mCloseEnough = (int) (CLOSE_ENOUGH * density); @@ -387,6 +387,28 @@ public class ViewPager extends ViewGroup { } /** + * Returns the {@link EdgeEffect#getType()} for the edge effects. + * @return the {@link EdgeEffect#getType()} for the edge effects. + * @attr ref android.R.styleable#EdgeEffect_edgeEffectType + */ + @EdgeEffect.EdgeEffectType + public int getEdgeEffectType() { + // Both left and right edge have the same edge effect type + return mLeftEdge.getType(); + } + + /** + * Sets the {@link EdgeEffect#setType(int)} for the edge effects. + * @param type The edge effect type to use for the edge effects. + * @attr ref android.R.styleable#EdgeEffect_edgeEffectType + */ + public void setEdgeEffectType(@EdgeEffect.EdgeEffectType int type) { + mLeftEdge.setType(type); + mRightEdge.setType(type); + invalidate(); + } + + /** * Set a PagerAdapter that will supply views for this pager as needed. * * @param adapter Adapter to use @@ -1891,7 +1913,7 @@ public class ViewPager extends ViewGroup { } if (mIsBeingDragged) { // Scroll to follow the motion event - if (performDrag(x)) { + if (performDrag(x, y)) { postInvalidateOnAnimation(); } } @@ -1918,6 +1940,17 @@ public class ViewPager extends ViewGroup { mIsBeingDragged = true; requestParentDisallowInterceptTouchEvent(true); setScrollState(SCROLL_STATE_DRAGGING); + } else if (mLeftEdge.getDistance() != 0 + || mRightEdge.getDistance() != 0) { + // Caught the edge glow animation + mIsBeingDragged = true; + setScrollState(SCROLL_STATE_DRAGGING); + if (mLeftEdge.getDistance() != 0) { + mLeftEdge.onPullDistance(0f, 1 - mLastMotionY / getHeight()); + } + if (mRightEdge.getDistance() != 0) { + mRightEdge.onPullDistance(0f, mLastMotionY / getHeight()); + } } else { completeScroll(false); mIsBeingDragged = false; @@ -2009,7 +2042,7 @@ public class ViewPager extends ViewGroup { // Scroll to follow the motion event final int activePointerIndex = ev.findPointerIndex(mActivePointerId); final float x = ev.getX(activePointerIndex); - needsInvalidate |= performDrag(x); + needsInvalidate |= performDrag(x, ev.getY(activePointerIndex)); } break; case MotionEvent.ACTION_UP: @@ -2080,12 +2113,43 @@ public class ViewPager extends ViewGroup { } } - private boolean performDrag(float x) { + /** + * If either of the horizontal edge glows are currently active, this consumes part or all of + * deltaX on the edge glow. + * + * @param deltaX The pointer motion, in pixels, in the horizontal direction, positive + * for moving down and negative for moving up. + * @param y The vertical position of the pointer. + * @return The amount of <code>deltaX</code> that has been consumed by the + * edge glow. + */ + private float releaseHorizontalGlow(float deltaX, float y) { + // First allow releasing existing overscroll effect: + float consumed = 0; + float displacement = y / getHeight(); + float pullDistance = (float) deltaX / getWidth(); + if (mLeftEdge.getDistance() != 0) { + consumed = -mLeftEdge.onPullDistance(-pullDistance, 1 - displacement); + } else if (mRightEdge.getDistance() != 0) { + consumed = mRightEdge.onPullDistance(pullDistance, displacement); + } + return consumed * getWidth(); + } + + private boolean performDrag(float x, float y) { boolean needsInvalidate = false; + final float dX = mLastMotionX - x; final int width = getPaddedWidth(); - final float deltaX = mLastMotionX - x; mLastMotionX = x; + final float releaseConsumed = releaseHorizontalGlow(dX, y); + final float deltaX = dX - releaseConsumed; + if (releaseConsumed != 0) { + needsInvalidate = true; + } + if (Math.abs(deltaX) < 0.0001f) { // ignore rounding errors from releaseHorizontalGlow() + return needsInvalidate; + } final EdgeEffect startEdge; final EdgeEffect endEdge; @@ -2128,14 +2192,14 @@ public class ViewPager extends ViewGroup { if (scrollStart < startBound) { if (startAbsolute) { final float over = startBound - scrollStart; - startEdge.onPull(Math.abs(over) / width); + startEdge.onPullDistance(over / width, 1 - y / getHeight()); needsInvalidate = true; } clampedScrollStart = startBound; } else if (scrollStart > endBound) { if (endAbsolute) { final float over = scrollStart - endBound; - endEdge.onPull(Math.abs(over) / width); + endEdge.onPullDistance(over / width, y / getHeight()); needsInvalidate = true; } clampedScrollStart = endBound; @@ -2228,7 +2292,9 @@ public class ViewPager extends ViewGroup { */ private int determineTargetPage(int currentPage, float pageOffset, int velocity, int deltaX) { int targetPage; - if (Math.abs(deltaX) > mFlingDistance && Math.abs(velocity) > mMinimumVelocity) { + if (Math.abs(deltaX) > mFlingDistance && Math.abs(velocity) > mMinimumVelocity + && mLeftEdge.getDistance() == 0 // don't fling while stretched + && mRightEdge.getDistance() == 0) { targetPage = currentPage - (velocity < 0 ? mLeftIncr : 0); } else { final float truncator = currentPage >= mCurItem ? 0.4f : 0.6f; diff --git a/core/res/AndroidManifest.xml b/core/res/AndroidManifest.xml index d88f259be70d..45fd96a02ce4 100644 --- a/core/res/AndroidManifest.xml +++ b/core/res/AndroidManifest.xml @@ -4824,7 +4824,7 @@ TODO(159952358): STOPSHIP: This must be updated to the new "internal" protectionLevel --> <permission android:name="android.permission.DOMAIN_VERIFICATION_AGENT" - android:protectionLevel="signature|privileged" /> + android:protectionLevel="internal|privileged" /> <!-- @SystemApi @hide Must be required by the domain verification agent's intent BroadcastReceiver, to ensure that only the system can interact with it. diff --git a/core/res/res/values/ids.xml b/core/res/res/values/ids.xml index 7bc4663d1070..c3b35c81cb66 100644 --- a/core/res/res/values/ids.xml +++ b/core/res/res/values/ids.xml @@ -252,5 +252,8 @@ <item type="id" name="remote_views_next_child" /> <!-- View tag associating a view with its stable id for potential recycling. --> - <item type="id" name = "remote_views_stable_id" /> + <item type="id" name="remote_views_stable_id" /> + + <!-- View tag associating a view with its overridden id, to ensure valid recycling only. --> + <item type="id" name="remote_views_override_id" /> </resources> diff --git a/core/res/res/values/symbols.xml b/core/res/res/values/symbols.xml index 541c18cc715e..cdeb71c7f162 100644 --- a/core/res/res/values/symbols.xml +++ b/core/res/res/values/symbols.xml @@ -4324,8 +4324,11 @@ <java-symbol type="bool" name="config_cecRcProfileSourceMediaContextSensitiveMenuNotHandled_allowed" /> <java-symbol type="bool" name="config_cecRcProfileSourceMediaContextSensitiveMenuNotHandled_default" /> + <!-- Ids for RemoteViews --> <java-symbol type="id" name="remote_views_next_child" /> <java-symbol type="id" name="remote_views_stable_id" /> + <java-symbol type="id" name="remote_views_override_id" /> + <!-- View and control prompt --> <java-symbol type="drawable" name="ic_accessibility_24dp" /> <java-symbol type="string" name="view_and_control_notification_title" /> diff --git a/core/tests/coretests/BstatsTestApp/AndroidManifest.xml b/core/tests/coretests/BstatsTestApp/AndroidManifest.xml index 1e6bdc6c29a0..fcb1e71cc3f5 100644 --- a/core/tests/coretests/BstatsTestApp/AndroidManifest.xml +++ b/core/tests/coretests/BstatsTestApp/AndroidManifest.xml @@ -19,7 +19,7 @@ <uses-permission android:name="android.permission.SYSTEM_ALERT_WINDOW" /> - <uses-sdk android:minSdkVersion="19" android:targetSdkVersion="25"/> + <uses-sdk android:minSdkVersion="19" android:targetSdkVersion="26"/> <application> <activity android:name=".TestActivity" diff --git a/core/tests/coretests/src/com/android/internal/os/BstatsCpuTimesValidationTest.java b/core/tests/coretests/src/com/android/internal/os/BstatsCpuTimesValidationTest.java index 4fe7d70e86ff..13d529cfed26 100644 --- a/core/tests/coretests/src/com/android/internal/os/BstatsCpuTimesValidationTest.java +++ b/core/tests/coretests/src/com/android/internal/os/BstatsCpuTimesValidationTest.java @@ -124,6 +124,7 @@ public class BstatsCpuTimesValidationTest { sContext.getPackageManager().setApplicationEnabledSetting(TEST_PKG, PackageManager.COMPONENT_ENABLED_STATE_ENABLED, 0); sTestPkgUid = sContext.getPackageManager().getPackageUid(TEST_PKG, 0); + executeCmd("cmd deviceidle whitelist +" + TEST_PKG); final ArrayMap<String, String> desiredConstants = new ArrayMap<>(); desiredConstants.put(KEY_TRACK_CPU_TIMES_BY_PROC_STATE, Boolean.toString(true)); @@ -134,6 +135,7 @@ public class BstatsCpuTimesValidationTest { @AfterClass public static void tearDownOnce() throws Exception { + executeCmd("cmd deviceidle whitelist -" + TEST_PKG); if (sBatteryStatsConstsUpdated) { Settings.Global.putString(sContext.getContentResolver(), Settings.Global.BATTERY_STATS_CONSTANTS, sOriginalBatteryStatsConsts); @@ -382,7 +384,7 @@ public class BstatsCpuTimesValidationTest { } @Test - @SkipPresubmit("b/180015146 flakey") + @SkipPresubmit("b/183225190 flaky") public void testCpuFreqTimes_stateFgService() throws Exception { if (!sCpuFreqTimesAvailable || !sPerProcStateTimesAvailable) { Log.w(TAG, "Skipping " + testName.getMethodName() @@ -515,7 +517,6 @@ public class BstatsCpuTimesValidationTest { } @Test - @SkipPresubmit("b/180015146") public void testCpuFreqTimes_trackingDisabled() throws Exception { if (!sCpuFreqTimesAvailable || !sPerProcStateTimesAvailable) { Log.w(TAG, "Skipping " + testName.getMethodName() @@ -625,7 +626,7 @@ public class BstatsCpuTimesValidationTest { splitter.setString(settingsDump); String next; while (splitter.hasNext()) { - next = splitter.next(); + next = splitter.next().trim(); if (next.startsWith(key)) { return next.split("=")[1]; } diff --git a/graphics/java/android/graphics/drawable/RippleAnimationSession.java b/graphics/java/android/graphics/drawable/RippleAnimationSession.java index b57f7af14a0e..94d5c2265372 100644 --- a/graphics/java/android/graphics/drawable/RippleAnimationSession.java +++ b/graphics/java/android/graphics/drawable/RippleAnimationSession.java @@ -26,8 +26,8 @@ import android.graphics.CanvasProperty; import android.graphics.Paint; import android.graphics.RecordingCanvas; import android.graphics.animation.RenderNodeAnimator; -import android.util.ArraySet; import android.view.animation.AnimationUtils; +import android.view.animation.Interpolator; import android.view.animation.LinearInterpolator; import android.view.animation.PathInterpolator; @@ -41,8 +41,8 @@ public final class RippleAnimationSession { private static final int ENTER_ANIM_DURATION = 450; private static final int EXIT_ANIM_DURATION = 300; private static final TimeInterpolator LINEAR_INTERPOLATOR = new LinearInterpolator(); - private static final TimeInterpolator PATH_INTERPOLATOR = - new PathInterpolator(.2f, 0, 0, 1f); + private static final Interpolator FAST_OUT_LINEAR_IN = + new PathInterpolator(0.4f, 0f, 1f, 1f); private Consumer<RippleAnimationSession> mOnSessionEnd; private final AnimationProperties<Float, Paint> mProperties; private AnimationProperties<CanvasProperty<Float>, CanvasProperty<Paint>> mCanvasProperties; @@ -59,7 +59,7 @@ public final class RippleAnimationSession { mSparkle.addUpdateListener(anim -> { final long now = AnimationUtils.currentAnimationTimeMillis(); final long elapsed = now - mStartTime - ENTER_ANIM_DURATION; - final float phase = (float) elapsed / 30000f; + final float phase = (float) elapsed / 800; mProperties.getShader().setNoisePhase(phase); notifyUpdate(); }); @@ -174,7 +174,7 @@ public final class RippleAnimationSession { private void startAnimation(Animator expand) { expand.setDuration(ENTER_ANIM_DURATION); expand.addListener(new AnimatorListener(this)); - expand.setInterpolator(LINEAR_INTERPOLATOR); + expand.setInterpolator(FAST_OUT_LINEAR_IN); expand.start(); if (!mSparkle.isRunning()) { mSparkle.start(); diff --git a/graphics/java/android/graphics/drawable/RippleDrawable.java b/graphics/java/android/graphics/drawable/RippleDrawable.java index fb2b9b343f0a..d5711c8cc450 100644 --- a/graphics/java/android/graphics/drawable/RippleDrawable.java +++ b/graphics/java/android/graphics/drawable/RippleDrawable.java @@ -914,7 +914,7 @@ public class RippleDrawable extends LayerDrawable { shader.setColor(color); shader.setOrigin(w / 2, y / 2); shader.setTouch(x, y); - shader.setResolution(w, h); + shader.setResolution(w, h, mState.mDensity); shader.setNoisePhase(0); shader.setRadius(radius); shader.setProgress(.0f); diff --git a/graphics/java/android/graphics/drawable/RippleShader.java b/graphics/java/android/graphics/drawable/RippleShader.java index ea9ba325a826..5dd250c8239e 100644 --- a/graphics/java/android/graphics/drawable/RippleShader.java +++ b/graphics/java/android/graphics/drawable/RippleShader.java @@ -20,13 +20,15 @@ import android.annotation.ColorInt; import android.graphics.Color; import android.graphics.RuntimeShader; import android.graphics.Shader; +import android.util.DisplayMetrics; final class RippleShader extends RuntimeShader { private static final String SHADER_UNIFORMS = "uniform vec2 in_origin;\n" + "uniform vec2 in_touch;\n" + "uniform float in_progress;\n" + "uniform float in_maxRadius;\n" - + "uniform vec2 in_resolution;\n" + + "uniform vec2 in_resolutionScale;\n" + + "uniform vec2 in_noiseScale;\n" + "uniform float in_hasMask;\n" + "uniform float in_noisePhase;\n" + "uniform vec4 in_color;\n" @@ -40,18 +42,15 @@ final class RippleShader extends RuntimeShader { + "}" + "const float PI = 3.1415926535897932384626;\n" + "\n" - + "float threshold(float v, float l, float h) {\n" - + " return step(l, v) * (1.0 - step(h, v));\n" - + "}\n" - + "\n" + "float sparkles(vec2 uv, float t) {\n" + " float n = triangleNoise(uv);\n" + " float s = 0.0;\n" + " for (float i = 0; i < 4; i += 1) {\n" - + " float l = i * 0.25;\n" - + " float h = l + 0.005;\n" - + " float o = abs(sin(0.1 * PI * (t + i)));\n" - + " s += threshold(n + o, l, h);\n" + + " float l = i * 0.01;\n" + + " float h = l + 0.1;\n" + + " float o = smoothstep(n - l, h, n);\n" + + " o *= abs(sin(PI * o * (t + 0.55 * i)));\n" + + " s += o;\n" + " }\n" + " return saturate(s);\n" + "}\n" @@ -83,7 +82,9 @@ final class RippleShader extends RuntimeShader { + " vec2 center = mix(in_touch, in_origin, fadeIn);\n" + " float ring = getRingMask(p, center, in_maxRadius, fadeIn);\n" + " float alpha = min(fadeIn, 1. - fadeOutNoise);\n" - + " float sparkle = sparkles(p, in_noisePhase) * ring * alpha;\n" + + " vec2 uv = p * in_resolutionScale;\n" + + " vec2 densityUv = uv - mod(uv, in_noiseScale);\n" + + " float sparkle = sparkles(densityUv, in_noisePhase) * ring * alpha;\n" + " float fade = min(fadeIn, 1. - fadeOutRipple);\n" + " vec4 circle = in_color * (softCircle(p, center, in_maxRadius " + " * fadeIn, 0.2) * fade);\n" @@ -135,7 +136,10 @@ final class RippleShader extends RuntimeShader { color.green(), color.blue(), color.alpha()}); } - public void setResolution(float w, float h) { - setUniform("in_resolution", w, h); + public void setResolution(float w, float h, int density) { + float noiseScale = 0.8f; + float densityScale = density * DisplayMetrics.DENSITY_DEFAULT_SCALE * 0.5f * noiseScale; + setUniform("in_resolutionScale", new float[] {1f / w, 1f / h}); + setUniform("in_noiseScale", new float[] {densityScale / w, densityScale / h}); } } diff --git a/packages/SettingsLib/TwoTargetPreference/Android.bp b/packages/SettingsLib/TwoTargetPreference/Android.bp index f2e79b9ab53b..078e8c3388ef 100644 --- a/packages/SettingsLib/TwoTargetPreference/Android.bp +++ b/packages/SettingsLib/TwoTargetPreference/Android.bp @@ -1,3 +1,12 @@ +package { + // See: http://go/android-license-faq + // A large-scale-change added 'default_applicable_licenses' to import + // all of the 'license_kinds' from "frameworks_base_license" + // to get the below license kinds: + // SPDX-license-identifier-Apache-2.0 + default_applicable_licenses: ["frameworks_base_license"], +} + android_library { name: "SettingsLibTwoTargetPreference", diff --git a/packages/SystemUI/AndroidManifest.xml b/packages/SystemUI/AndroidManifest.xml index 338aa3a2c979..3904201d2ee8 100644 --- a/packages/SystemUI/AndroidManifest.xml +++ b/packages/SystemUI/AndroidManifest.xml @@ -336,7 +336,7 @@ </receiver> <activity android:name=".screenshot.LongScreenshotActivity" - android:theme="@android:style/Theme.DeviceDefault.NoActionBar" + android:theme="@style/LongScreenshotActivity" android:process=":screenshot" android:exported="false" android:finishOnTaskLaunch="true" /> diff --git a/packages/SystemUI/res/layout/long_screenshot.xml b/packages/SystemUI/res/layout/long_screenshot.xml index 7ba28a8483c3..19bcf95922c2 100644 --- a/packages/SystemUI/res/layout/long_screenshot.xml +++ b/packages/SystemUI/res/layout/long_screenshot.xml @@ -24,51 +24,27 @@ <Button android:id="@+id/save" + style="@android:style/Widget.DeviceDefault.Button.Colored" android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="@string/save" - app:layout_constraintEnd_toStartOf="@id/cancel" - app:layout_constraintHorizontal_chainStyle="packed" + android:layout_marginLeft="8dp" app:layout_constraintStart_toStartOf="parent" app:layout_constraintTop_toTopOf="parent" - app:layout_constraintBottom_toTopOf="@id/guideline" /> + app:layout_constraintBottom_toTopOf="@id/preview" /> - <Button - android:id="@+id/cancel" - android:layout_width="wrap_content" - android:layout_height="wrap_content" - android:text="@string/cancel" - app:layout_constraintEnd_toStartOf="@id/edit" - app:layout_constraintStart_toEndOf="@id/save" - app:layout_constraintTop_toTopOf="parent" - app:layout_constraintBottom_toTopOf="@id/guideline" /> - - <Button - android:id="@+id/edit" - android:layout_width="wrap_content" - android:layout_height="wrap_content" - android:text="@string/screenshot_edit_label" - app:layout_constraintEnd_toStartOf="@id/share" - app:layout_constraintStart_toEndOf="@id/cancel" - app:layout_constraintTop_toTopOf="parent" - app:layout_constraintBottom_toTopOf="@id/guideline" /> - - <Button + <ImageButton android:id="@+id/share" - android:layout_width="wrap_content" - android:layout_height="wrap_content" - android:text="@*android:string/share" + style="@android:style/Widget.Material.Button.Borderless" + android:tint="?android:textColorPrimary" + android:layout_width="48dp" + android:layout_height="48dp" + android:padding="6dp" + android:src="@drawable/ic_screenshot_share" + android:layout_marginRight="8dp" app:layout_constraintEnd_toEndOf="parent" - app:layout_constraintStart_toEndOf="@+id/edit" app:layout_constraintTop_toTopOf="parent" - app:layout_constraintBottom_toTopOf="@id/guideline" /> - - <androidx.constraintlayout.widget.Guideline - android:id="@+id/guideline" - android:layout_width="wrap_content" - android:layout_height="wrap_content" - android:orientation="horizontal" - app:layout_constraintGuide_percent="0.1" /> + app:layout_constraintBottom_toTopOf="@id/preview" /> <ImageView android:id="@+id/preview" @@ -78,7 +54,7 @@ android:layout_marginHorizontal="48dp" app:layout_constrainedHeight="true" app:layout_constrainedWidth="true" - app:layout_constraintTop_toBottomOf="@id/guideline" + app:layout_constraintTop_toBottomOf="@id/save" app:layout_constraintEnd_toEndOf="parent" app:layout_constraintStart_toStartOf="parent" app:layout_constraintBottom_toBottomOf="parent" @@ -93,7 +69,7 @@ android:layout_marginBottom="42dp" app:layout_constrainedHeight="true" app:layout_constrainedWidth="true" - app:layout_constraintTop_toBottomOf="@id/guideline" + app:layout_constraintTop_toTopOf="@id/preview" app:layout_constraintEnd_toEndOf="parent" app:layout_constraintStart_toStartOf="parent" app:layout_constraintBottom_toBottomOf="parent" @@ -110,7 +86,7 @@ android:layout_width="200dp" android:layout_height="200dp" android:elevation="2dp" - app:layout_constraintTop_toBottomOf="@id/guideline" + app:layout_constraintTop_toTopOf="@id/preview" app:layout_constraintLeft_toLeftOf="parent" app:handleThickness="@dimen/screenshot_crop_handle_thickness" app:handleColor="@*android:color/accent_device_default" @@ -119,5 +95,24 @@ app:borderColor="#fff" /> + <Button + android:id="@+id/edit" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:layout_marginBottom="8dp" + style="@android:style/Widget.DeviceDefault.Button.Colored" + android:backgroundTint="?android:colorBackground" + android:drawableStart="@drawable/ic_screenshot_edit" + android:drawableTint="?android:textColorPrimary" + android:paddingStart="16dp" + android:paddingEnd="8dp" + android:paddingVertical="8dp" + android:textColor="?android:textColorPrimary" + android:text="@string/screenshot_edit_label" + app:layout_constraintBottom_toBottomOf="parent" + app:layout_constraintLeft_toLeftOf="parent" + app:layout_constraintRight_toRightOf="parent" + /> + </androidx.constraintlayout.widget.ConstraintLayout> diff --git a/packages/SystemUI/res/values/styles.xml b/packages/SystemUI/res/values/styles.xml index ff9ea0175ec0..4a661dcecce8 100644 --- a/packages/SystemUI/res/values/styles.xml +++ b/packages/SystemUI/res/values/styles.xml @@ -610,6 +610,11 @@ <item name="android:windowCloseOnTouchOutside">true</item> </style> + <!-- Screenshots --> + <style name="LongScreenshotActivity" parent="@android:style/Theme.DeviceDefault.DayNight"> + <item name="android:windowNoTitle">true</item> + </style> + <!-- Privacy dialog --> <style name="PrivacyDialog" parent="ScreenRecord"> <item name="android:windowAnimationStyle">@android:style/Animation.Dialog</item> diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsController.java b/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsController.java index b9f9b1bc85dd..98b3fe46ff57 100644 --- a/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsController.java +++ b/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsController.java @@ -321,6 +321,7 @@ public class UdfpsController implements DozeReceiver, HbmCallback { mSensorProps = findFirstUdfps(); // At least one UDFPS sensor exists checkArgument(mSensorProps != null); + mStatusBar.setSensorRect(getSensorLocation()); mCoreLayoutParams = new WindowManager.LayoutParams( // TODO(b/152419866): Use the UDFPS window type when it becomes available. @@ -367,7 +368,8 @@ public class UdfpsController implements DozeReceiver, HbmCallback { */ public RectF getSensorLocation() { // This is currently used to calculate the amount of space available for notifications - // on lockscreen. Keyguard is only shown in portrait mode for now, so this will need to + // on lockscreen and for the udfps light reveal animation on keyguard. + // Keyguard is only shown in portrait mode for now, so this will need to // be updated if that ever changes. return new RectF(mSensorProps.sensorLocationX - mSensorProps.sensorRadius, mSensorProps.sensorLocationY - mSensorProps.sensorRadius, diff --git a/packages/SystemUI/src/com/android/systemui/screenshot/LongScreenshotActivity.java b/packages/SystemUI/src/com/android/systemui/screenshot/LongScreenshotActivity.java index 31cdadab070d..6a004c2c01dc 100644 --- a/packages/SystemUI/src/com/android/systemui/screenshot/LongScreenshotActivity.java +++ b/packages/SystemUI/src/com/android/systemui/screenshot/LongScreenshotActivity.java @@ -76,7 +76,6 @@ public class LongScreenshotActivity extends Activity { private ImageView mPreview; private View mSave; - private View mCancel; private View mEdit; private View mShare; private CropView mCropView; @@ -117,7 +116,6 @@ public class LongScreenshotActivity extends Activity { mPreview = requireViewById(R.id.preview); mSave = requireViewById(R.id.save); - mCancel = requireViewById(R.id.cancel); mEdit = requireViewById(R.id.edit); mShare = requireViewById(R.id.share); mCropView = requireViewById(R.id.crop_view); @@ -125,7 +123,6 @@ public class LongScreenshotActivity extends Activity { mCropView.setCropInteractionListener(mMagnifierView); mSave.setOnClickListener(this::onClicked); - mCancel.setOnClickListener(this::onClicked); mEdit.setOnClickListener(this::onClicked); mShare.setOnClickListener(this::onClicked); @@ -313,7 +310,6 @@ public class LongScreenshotActivity extends Activity { private void setButtonsEnabled(boolean enabled) { mSave.setEnabled(enabled); - mCancel.setEnabled(enabled); mEdit.setEnabled(enabled); mShare.setEnabled(enabled); } @@ -350,8 +346,6 @@ public class LongScreenshotActivity extends Activity { setButtonsEnabled(false); if (id == R.id.save) { startExport(PendingAction.SAVE); - } else if (id == R.id.cancel) { - finishAndRemoveTask(); } else if (id == R.id.edit) { mUiEventLogger.log(ScreenshotEvent.SCREENSHOT_LONG_SCREENSHOT_EDIT); startExport(PendingAction.EDIT); diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/LightRevealScrim.kt b/packages/SystemUI/src/com/android/systemui/statusbar/LightRevealScrim.kt index c1feacaba440..563470d1a260 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/LightRevealScrim.kt +++ b/packages/SystemUI/src/com/android/systemui/statusbar/LightRevealScrim.kt @@ -82,6 +82,31 @@ object LiftReveal : LightRevealEffect { } } +class CircleReveal( + /** X-value of the circle center of the reveal. */ + val centerX: Float, + /** Y-value of the circle center of the reveal. */ + val centerY: Float, + /** Radius of initial state of circle reveal */ + val startRadius: Float, + /** Radius of end state of circle reveal */ + val endRadius: Float +) : LightRevealEffect { + override fun setRevealAmountOnScrim(amount: Float, scrim: LightRevealScrim) { + val interpolatedAmount = Interpolators.FAST_OUT_SLOW_IN.getInterpolation(amount) + val fadeAmount = + LightRevealEffect.getPercentPastThreshold(interpolatedAmount, 0.75f) + val radius = startRadius + ((endRadius - startRadius) * interpolatedAmount) + scrim.revealGradientEndColorAlpha = 1f - fadeAmount + scrim.setRevealGradientBounds( + centerX - radius /* left */, + centerY - radius /* top */, + centerX + radius /* right */, + centerY + radius /* bottom */ + ) + } +} + class PowerButtonReveal( /** Approximate Y-value of the center of the power button on the physical device. */ val powerButtonY: Float diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationShelf.java b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationShelf.java index e1199077efb9..3daa2b3e1e64 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationShelf.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationShelf.java @@ -132,6 +132,7 @@ public class NotificationShelf extends ActivatableNotificationView implements mHiddenShelfIconSize = res.getDimensionPixelOffset(R.dimen.hidden_shelf_icon_size); mGapHeight = res.getDimensionPixelSize(R.dimen.qs_notification_padding); + mShelfIcons.setInNotificationIconShelf(true); if (!mShowNotificationShelf) { setVisibility(GONE); } diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationIconContainer.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationIconContainer.java index 6b144c652c56..25de551d2699 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationIconContainer.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationIconContainer.java @@ -152,6 +152,7 @@ public class NotificationIconContainer extends AlphaOptimizedFrameLayout { private boolean mDozing; private boolean mOnLockScreen; private int mLockScreenMode = KeyguardUpdateMonitor.LOCK_SCREEN_MODE_NORMAL; + private boolean mInNotificationIconShelf; private boolean mChangingViewPositions; private int mAddAnimationStartIndex = -1; private int mCannedAnimationStartIndex = -1; @@ -702,6 +703,10 @@ public class NotificationIconContainer extends AlphaOptimizedFrameLayout { mLockScreenMode = lockScreenMode; } + public void setInNotificationIconShelf(boolean inShelf) { + mInNotificationIconShelf = inShelf; + } + public class IconState extends ViewState { public static final int NO_VALUE = NotificationIconContainer.NO_VALUE; public float iconAppearAmount = 1.0f; @@ -813,7 +818,7 @@ public class NotificationIconContainer extends AlphaOptimizedFrameLayout { } } icon.setVisibleState(visibleState, animationsAllowed); - icon.setIconColor(mThemedTextColorPrimary, + icon.setIconColor(mInNotificationIconShelf ? mThemedTextColorPrimary : iconColor, needsCannedAnimation && animationsAllowed); if (animate) { animateTo(icon, animationProperties); diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java index 427df5ebbbab..0e1fe22b2454 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java @@ -22,6 +22,7 @@ import static android.app.StatusBarManager.WindowType; import static android.app.StatusBarManager.WindowVisibleState; import static android.app.StatusBarManager.windowStateToString; import static android.app.WindowConfiguration.WINDOWING_MODE_FULLSCREEN_OR_SPLIT_SCREEN_SECONDARY; +import static android.hardware.biometrics.BiometricSourceType.FINGERPRINT; import static android.view.InsetsState.ITYPE_STATUS_BAR; import static android.view.InsetsState.containsType; import static android.view.WindowInsetsController.APPEARANCE_LOW_PROFILE_BARS; @@ -46,6 +47,7 @@ import static com.android.systemui.statusbar.phone.BarTransitions.MODE_WARNING; import static com.android.systemui.statusbar.phone.BarTransitions.TransitionMode; import static com.android.wm.shell.bubbles.BubbleController.TASKBAR_CHANGED_BROADCAST; +import android.animation.ValueAnimator; import android.annotation.NonNull; import android.annotation.Nullable; import android.app.ActivityManager; @@ -74,6 +76,7 @@ import android.content.pm.ResolveInfo; import android.content.res.Configuration; import android.graphics.Point; import android.graphics.PointF; +import android.graphics.RectF; import android.media.AudioAttributes; import android.metrics.LogMaker; import android.net.Uri; @@ -179,6 +182,7 @@ import com.android.systemui.settings.brightness.BrightnessSlider; import com.android.systemui.shared.plugins.PluginManager; import com.android.systemui.statusbar.AutoHideUiElement; import com.android.systemui.statusbar.BackDropView; +import com.android.systemui.statusbar.CircleReveal; import com.android.systemui.statusbar.CommandQueue; import com.android.systemui.statusbar.CrossFadeHelper; import com.android.systemui.statusbar.FeatureFlags; @@ -382,6 +386,8 @@ public class StatusBar extends SystemUI implements DemoMode, private ChargingRippleView mChargingRipple; private WiredChargingRippleController mChargingRippleAnimationController; private PowerButtonReveal mPowerButtonReveal; + private CircleReveal mCircleReveal; + private ValueAnimator mCircleRevealAnimator = ValueAnimator.ofFloat(0f, 1f); private final Object mQueueLock = new Object(); @@ -1206,7 +1212,9 @@ public class StatusBar extends SystemUI implements DemoMode, mLightRevealScrim = mNotificationShadeWindowView.findViewById(R.id.light_reveal_scrim); mChargingRippleAnimationController.setViewHost(mNotificationShadeWindowView); - if (mFeatureFlags.useNewLockscreenAnimations() && mDozeParameters.getAlwaysOn()) { + + if (mFeatureFlags.useNewLockscreenAnimations() + && (mDozeParameters.getAlwaysOn() || mDozeParameters.isQuickPickupEnabled())) { mLightRevealScrim.setVisibility(View.VISIBLE); mLightRevealScrim.setRevealEffect(LiftReveal.INSTANCE); } else { @@ -3353,6 +3361,9 @@ public class StatusBar extends SystemUI implements DemoMode, mNotificationPanelViewController.fadeOut(0, FADE_KEYGUARD_DURATION_PULSING, ()-> { hideKeyguard(); + if (shouldShowCircleReveal()) { + startCircleReveal(); + } mStatusBarKeyguardViewManager.onKeyguardFadedAway(); }).start(); } @@ -3666,15 +3677,16 @@ public class StatusBar extends SystemUI implements DemoMode, updateQsExpansionEnabled(); mKeyguardViewMediator.setDozing(mDozing); - final boolean usePowerButtonEffect = - (isDozing && mWakefulnessLifecycle.getLastSleepReason() - == PowerManager.GO_TO_SLEEP_REASON_POWER_BUTTON) - || (!isDozing && mWakefulnessLifecycle.getLastWakeReason() - == PowerManager.WAKE_REASON_POWER_BUTTON); - - mLightRevealScrim.setRevealEffect(usePowerButtonEffect - ? mPowerButtonReveal - : LiftReveal.INSTANCE); + if (!isDozing && shouldShowCircleReveal()) { + startCircleReveal(); + } else if ((isDozing && mWakefulnessLifecycle.getLastSleepReason() + == PowerManager.GO_TO_SLEEP_REASON_POWER_BUTTON) + || (!isDozing && mWakefulnessLifecycle.getLastWakeReason() + == PowerManager.WAKE_REASON_POWER_BUTTON)) { + mLightRevealScrim.setRevealEffect(mPowerButtonReveal); + } else if (!mCircleRevealAnimator.isRunning()) { + mLightRevealScrim.setRevealEffect(LiftReveal.INSTANCE); + } mNotificationsController.requestNotificationUpdate("onDozingChanged"); updateDozingState(); @@ -3684,6 +3696,22 @@ public class StatusBar extends SystemUI implements DemoMode, Trace.endSection(); } + private void startCircleReveal() { + mLightRevealScrim.setRevealEffect(mCircleReveal); + mCircleRevealAnimator.cancel(); + mCircleRevealAnimator.addUpdateListener(animation -> + mLightRevealScrim.setRevealAmount( + (float) mCircleRevealAnimator.getAnimatedValue())); + mCircleRevealAnimator.setDuration(900); + mCircleRevealAnimator.start(); + } + + private boolean shouldShowCircleReveal() { + return mCircleReveal != null && !mCircleRevealAnimator.isRunning() + && mKeyguardUpdateMonitor.isUdfpsEnrolled() + && mBiometricUnlockController.getBiometricType() == FINGERPRINT; + } + private void updateKeyguardState() { mKeyguardStateController.notifyKeyguardState(mStatusBarKeyguardViewManager.isShowing(), mStatusBarKeyguardViewManager.isOccluded()); @@ -4170,6 +4198,15 @@ public class StatusBar extends SystemUI implements DemoMode, mBiometricUnlockController.getBiometricType()); } + /** + * Set the location of the sensor on UDFPS if existent. + */ + public void setSensorRect(RectF rect) { + final float startRadius = (rect.right - rect.left) / 2f; + mCircleReveal = new CircleReveal(rect.centerX(), rect.centerY(), + startRadius, rect.centerY() - startRadius); + } + @VisibleForTesting public void updateScrimController() { Trace.beginSection("StatusBar#updateScrimController"); diff --git a/services/api/Android.bp b/services/api/Android.bp index b8ca5488c5cd..bbc8c72b2eef 100644 --- a/services/api/Android.bp +++ b/services/api/Android.bp @@ -14,6 +14,12 @@ package { default_visibility: ["//visibility:private"], + // See: http://go/android-license-faq + // A large-scale-change added 'default_applicable_licenses' to import + // all of the 'license_kinds' from "frameworks_base_license" + // to get the below license kinds: + // SPDX-license-identifier-Apache-2.0 + default_applicable_licenses: ["frameworks_base_license"], } filegroup { @@ -26,4 +32,4 @@ filegroup { name: "non-updatable-system-server-removed.txt", srcs: ["non-updatable-removed.txt"], visibility: ["//frameworks/base/api"], -}
\ No newline at end of file +} diff --git a/services/core/java/com/android/server/am/ActiveServices.java b/services/core/java/com/android/server/am/ActiveServices.java index 3c445ae4b667..1b352c728554 100644 --- a/services/core/java/com/android/server/am/ActiveServices.java +++ b/services/core/java/com/android/server/am/ActiveServices.java @@ -160,6 +160,7 @@ import java.text.SimpleDateFormat; import java.util.ArrayList; import java.util.Comparator; import java.util.List; +import java.util.Objects; import java.util.Set; import java.util.function.Predicate; @@ -559,6 +560,45 @@ public final class ActiveServices { return smap != null ? smap.mStartingBackground.size() >= mMaxStartingBackground : false; } + boolean hasForegroundServiceNotificationLocked(String pkg, int userId, String channelId) { + final ServiceMap smap = mServiceMap.get(userId); + if (smap != null) { + for (int i = 0; i < smap.mServicesByInstanceName.size(); i++) { + final ServiceRecord sr = smap.mServicesByInstanceName.valueAt(i); + if (sr.appInfo.packageName.equals(pkg) && sr.isForeground) { + if (Objects.equals(sr.foregroundNoti.getChannelId(), channelId)) { + if (DEBUG_FOREGROUND_SERVICE) { + Slog.d(TAG_SERVICE, "Channel u" + userId + "/pkg=" + pkg + + "/channelId=" + channelId + + " has fg service notification"); + } + return true; + } + } + } + } + return false; + } + + void stopForegroundServicesForChannelLocked(String pkg, int userId, String channelId) { + final ServiceMap smap = mServiceMap.get(userId); + if (smap != null) { + for (int i = 0; i < smap.mServicesByInstanceName.size(); i++) { + final ServiceRecord sr = smap.mServicesByInstanceName.valueAt(i); + if (sr.appInfo.packageName.equals(pkg) && sr.isForeground) { + if (Objects.equals(sr.foregroundNoti.getChannelId(), channelId)) { + if (DEBUG_FOREGROUND_SERVICE) { + Slog.d(TAG_SERVICE, "Stopping FGS u" + userId + "/pkg=" + pkg + + "/channelId=" + channelId + + " for conversation channel clear"); + } + stopServiceLocked(sr, false); + } + } + } + } + } + private ServiceMap getServiceMapLocked(int callingUser) { ServiceMap smap = mServiceMap.get(callingUser); if (smap == null) { diff --git a/services/core/java/com/android/server/am/ActivityManagerService.java b/services/core/java/com/android/server/am/ActivityManagerService.java index 0e8644a6569e..c4548a3070a7 100644 --- a/services/core/java/com/android/server/am/ActivityManagerService.java +++ b/services/core/java/com/android/server/am/ActivityManagerService.java @@ -15911,6 +15911,22 @@ public class ActivityManagerService extends IActivityManager.Stub } @Override + public boolean hasForegroundServiceNotification(String pkg, int userId, + String channelId) { + synchronized (ActivityManagerService.this) { + return mServices.hasForegroundServiceNotificationLocked(pkg, userId, channelId); + } + } + + @Override + public void stopForegroundServicesForChannel(String pkg, int userId, + String channelId) { + synchronized (ActivityManagerService.this) { + mServices.stopForegroundServicesForChannelLocked(pkg, userId, channelId); + } + } + + @Override public void registerProcessObserver(IProcessObserver processObserver) { ActivityManagerService.this.registerProcessObserver(processObserver); } diff --git a/services/core/java/com/android/server/am/OWNERS b/services/core/java/com/android/server/am/OWNERS index 9e79b02f8c96..273b9c3430b7 100644 --- a/services/core/java/com/android/server/am/OWNERS +++ b/services/core/java/com/android/server/am/OWNERS @@ -30,6 +30,10 @@ per-file BatteryExternalStats* = file:/BATTERY_STATS_OWNERS michaelwr@google.com narayan@google.com +# Voice Interaction +per-file *Assist* = file:/core/java/android/service/voice/OWNERS +per-file *Voice* = file:/core/java/android/service/voice/OWNERS + per-file SettingsToPropertiesMapper.java = omakoto@google.com, svetoslavganov@google.com, yamasani@google.com per-file CarUserSwitchingDialog.java = keunyoung@google.com, felipeal@google.com, gurunagarajan@google.com diff --git a/services/core/java/com/android/server/biometrics/AuthSession.java b/services/core/java/com/android/server/biometrics/AuthSession.java index 5083c5ecd1ec..6017e92afc1c 100644 --- a/services/core/java/com/android/server/biometrics/AuthSession.java +++ b/services/core/java/com/android/server/biometrics/AuthSession.java @@ -597,7 +597,8 @@ public final class AuthSession implements IBinder.DeathRecipient { mPreAuthInfo.confirmationRequested, FrameworkStatsLog.BIOMETRIC_AUTHENTICATED__STATE__CONFIRMED, latency, - mDebugEnabled); + mDebugEnabled, + -1 /* sensorId */); } else { final long latency = System.currentTimeMillis() - mStartTimeMs; @@ -625,7 +626,8 @@ public final class AuthSession implements IBinder.DeathRecipient { error, 0 /* vendorCode */, mDebugEnabled, - latency); + latency, + -1 /* sensorId */); } } diff --git a/services/core/java/com/android/server/biometrics/sensors/InternalCleanupClient.java b/services/core/java/com/android/server/biometrics/sensors/InternalCleanupClient.java index de571863dbd4..282261e6556f 100644 --- a/services/core/java/com/android/server/biometrics/sensors/InternalCleanupClient.java +++ b/services/core/java/com/android/server/biometrics/sensors/InternalCleanupClient.java @@ -127,7 +127,8 @@ public abstract class InternalCleanupClient<S extends BiometricAuthenticator.Ide getContext().getPackageName(), mBiometricUtils, getSensorId(), mAuthenticatorIds); FrameworkStatsLog.write(FrameworkStatsLog.BIOMETRIC_SYSTEM_HEALTH_ISSUE_DETECTED, mStatsModality, - BiometricsProtoEnums.ISSUE_UNKNOWN_TEMPLATE_ENROLLED_HAL); + BiometricsProtoEnums.ISSUE_UNKNOWN_TEMPLATE_ENROLLED_HAL, + -1 /* sensorId */); mCurrentTask.start(mRemoveCallback); } diff --git a/services/core/java/com/android/server/biometrics/sensors/InternalEnumerateClient.java b/services/core/java/com/android/server/biometrics/sensors/InternalEnumerateClient.java index e3feb74248ec..7f6903a17b32 100644 --- a/services/core/java/com/android/server/biometrics/sensors/InternalEnumerateClient.java +++ b/services/core/java/com/android/server/biometrics/sensors/InternalEnumerateClient.java @@ -118,7 +118,8 @@ public abstract class InternalEnumerateClient<T> extends HalClientMonitor<T> getTargetUserId(), identifier.getBiometricId()); FrameworkStatsLog.write(FrameworkStatsLog.BIOMETRIC_SYSTEM_HEALTH_ISSUE_DETECTED, mStatsModality, - BiometricsProtoEnums.ISSUE_UNKNOWN_TEMPLATE_ENROLLED_FRAMEWORK); + BiometricsProtoEnums.ISSUE_UNKNOWN_TEMPLATE_ENROLLED_FRAMEWORK, + -1 /* sensorId */); } mEnrolledList.clear(); } diff --git a/services/core/java/com/android/server/biometrics/sensors/LoggableMonitor.java b/services/core/java/com/android/server/biometrics/sensors/LoggableMonitor.java index edde3d496e7c..4da644d23dec 100644 --- a/services/core/java/com/android/server/biometrics/sensors/LoggableMonitor.java +++ b/services/core/java/com/android/server/biometrics/sensors/LoggableMonitor.java @@ -126,7 +126,8 @@ public abstract class LoggableMonitor { mStatsClient, acquiredInfo, vendorCode, - Utils.isDebugEnabled(context, targetUserId)); + Utils.isDebugEnabled(context, targetUserId), + -1 /* sensorId */); } protected final void logOnError(Context context, int error, int vendorCode, int targetUserId) { @@ -164,7 +165,8 @@ public abstract class LoggableMonitor { error, vendorCode, Utils.isDebugEnabled(context, targetUserId), - sanitizeLatency(latency)); + sanitizeLatency(latency), + -1 /* sensorId */); } protected final void logOnAuthenticated(Context context, boolean authenticated, @@ -214,7 +216,8 @@ public abstract class LoggableMonitor { requireConfirmation, authState, sanitizeLatency(latency), - Utils.isDebugEnabled(context, targetUserId)); + Utils.isDebugEnabled(context, targetUserId), + -1 /* sensorId */); } protected final void logOnEnrolled(int targetUserId, long latency, boolean enrollSuccessful) { @@ -240,7 +243,8 @@ public abstract class LoggableMonitor { mStatsModality, targetUserId, sanitizeLatency(latency), - enrollSuccessful); + enrollSuccessful, + -1 /* sensorId */); } private long sanitizeLatency(long latency) { diff --git a/services/core/java/com/android/server/biometrics/sensors/face/aidl/FaceProvider.java b/services/core/java/com/android/server/biometrics/sensors/face/aidl/FaceProvider.java index b6c50487ace6..ca29057c9888 100644 --- a/services/core/java/com/android/server/biometrics/sensors/face/aidl/FaceProvider.java +++ b/services/core/java/com/android/server/biometrics/sensors/face/aidl/FaceProvider.java @@ -27,6 +27,7 @@ import android.hardware.biometrics.ComponentInfoInternal; import android.hardware.biometrics.IInvalidationCallback; import android.hardware.biometrics.ITestSession; import android.hardware.biometrics.ITestSessionCallback; +import android.hardware.biometrics.common.ComponentInfo; import android.hardware.biometrics.face.IFace; import android.hardware.biometrics.face.SensorProps; import android.hardware.face.Face; @@ -137,8 +138,7 @@ public class FaceProvider implements IBinder.DeathRecipient, ServiceProvider { final List<ComponentInfoInternal> componentInfo = new ArrayList<>(); if (prop.commonProps.componentInfo != null) { - for (android.hardware.biometrics.common.ComponentInfo info - : prop.commonProps.componentInfo) { + for (ComponentInfo info : prop.commonProps.componentInfo) { componentInfo.add(new ComponentInfoInternal(info.componentId, info.hardwareVersion, info.firmwareVersion, info.serialNumber, info.softwareVersion)); diff --git a/services/core/java/com/android/server/biometrics/sensors/face/aidl/Sensor.java b/services/core/java/com/android/server/biometrics/sensors/face/aidl/Sensor.java index c7d2f0f87b6c..c6f39aa07f26 100644 --- a/services/core/java/com/android/server/biometrics/sensors/face/aidl/Sensor.java +++ b/services/core/java/com/android/server/biometrics/sensors/face/aidl/Sensor.java @@ -546,7 +546,8 @@ public class Sensor { FrameworkStatsLog.write(FrameworkStatsLog.BIOMETRIC_SYSTEM_HEALTH_ISSUE_DETECTED, BiometricsProtoEnums.MODALITY_FACE, - BiometricsProtoEnums.ISSUE_HAL_DEATH); + BiometricsProtoEnums.ISSUE_HAL_DEATH, + -1 /* sensorId */); } mScheduler.recordCrashState(); diff --git a/services/core/java/com/android/server/biometrics/sensors/face/hidl/Face10.java b/services/core/java/com/android/server/biometrics/sensors/face/hidl/Face10.java index d8aaa22e8300..50756c89613c 100644 --- a/services/core/java/com/android/server/biometrics/sensors/face/hidl/Face10.java +++ b/services/core/java/com/android/server/biometrics/sensors/face/hidl/Face10.java @@ -387,7 +387,8 @@ public class Face10 implements IHwBinder.DeathRecipient, ServiceProvider { FrameworkStatsLog.write(FrameworkStatsLog.BIOMETRIC_SYSTEM_HEALTH_ISSUE_DETECTED, BiometricsProtoEnums.MODALITY_FACE, - BiometricsProtoEnums.ISSUE_HAL_DEATH); + BiometricsProtoEnums.ISSUE_HAL_DEATH, + -1 /* sensorId */); } mScheduler.recordCrashState(); diff --git a/services/core/java/com/android/server/biometrics/sensors/fingerprint/aidl/FingerprintProvider.java b/services/core/java/com/android/server/biometrics/sensors/fingerprint/aidl/FingerprintProvider.java index f8af650ab25b..1b5def6c7063 100644 --- a/services/core/java/com/android/server/biometrics/sensors/fingerprint/aidl/FingerprintProvider.java +++ b/services/core/java/com/android/server/biometrics/sensors/fingerprint/aidl/FingerprintProvider.java @@ -29,6 +29,7 @@ import android.hardware.biometrics.ComponentInfoInternal; import android.hardware.biometrics.IInvalidationCallback; import android.hardware.biometrics.ITestSession; import android.hardware.biometrics.ITestSessionCallback; +import android.hardware.biometrics.common.ComponentInfo; import android.hardware.biometrics.fingerprint.IFingerprint; import android.hardware.biometrics.fingerprint.SensorProps; import android.hardware.fingerprint.Fingerprint; @@ -141,8 +142,7 @@ public class FingerprintProvider implements IBinder.DeathRecipient, ServiceProvi final List<ComponentInfoInternal> componentInfo = new ArrayList<>(); if (prop.commonProps.componentInfo != null) { - for (android.hardware.biometrics.common.ComponentInfo info - : prop.commonProps.componentInfo) { + for (ComponentInfo info : prop.commonProps.componentInfo) { componentInfo.add(new ComponentInfoInternal(info.componentId, info.hardwareVersion, info.firmwareVersion, info.serialNumber, info.softwareVersion)); diff --git a/services/core/java/com/android/server/biometrics/sensors/fingerprint/aidl/Sensor.java b/services/core/java/com/android/server/biometrics/sensors/fingerprint/aidl/Sensor.java index b9dee7d1e321..5631647816ec 100644 --- a/services/core/java/com/android/server/biometrics/sensors/fingerprint/aidl/Sensor.java +++ b/services/core/java/com/android/server/biometrics/sensors/fingerprint/aidl/Sensor.java @@ -526,7 +526,8 @@ class Sensor { FrameworkStatsLog.write(FrameworkStatsLog.BIOMETRIC_SYSTEM_HEALTH_ISSUE_DETECTED, BiometricsProtoEnums.MODALITY_FINGERPRINT, - BiometricsProtoEnums.ISSUE_HAL_DEATH); + BiometricsProtoEnums.ISSUE_HAL_DEATH, + -1 /* sensorId */); } mScheduler.recordCrashState(); diff --git a/services/core/java/com/android/server/biometrics/sensors/fingerprint/hidl/Fingerprint21.java b/services/core/java/com/android/server/biometrics/sensors/fingerprint/hidl/Fingerprint21.java index 136caeb12111..f2992cccbe09 100644 --- a/services/core/java/com/android/server/biometrics/sensors/fingerprint/hidl/Fingerprint21.java +++ b/services/core/java/com/android/server/biometrics/sensors/fingerprint/hidl/Fingerprint21.java @@ -390,7 +390,8 @@ public class Fingerprint21 implements IHwBinder.DeathRecipient, ServiceProvider FrameworkStatsLog.write(FrameworkStatsLog.BIOMETRIC_SYSTEM_HEALTH_ISSUE_DETECTED, BiometricsProtoEnums.MODALITY_FINGERPRINT, - BiometricsProtoEnums.ISSUE_HAL_DEATH); + BiometricsProtoEnums.ISSUE_HAL_DEATH, + -1 /* sensorId */); } mScheduler.recordCrashState(); diff --git a/services/core/java/com/android/server/display/DisplayManagerService.java b/services/core/java/com/android/server/display/DisplayManagerService.java index f8a913aeb7cd..c0109065fea4 100644 --- a/services/core/java/com/android/server/display/DisplayManagerService.java +++ b/services/core/java/com/android/server/display/DisplayManagerService.java @@ -1134,8 +1134,13 @@ public final class DisplayManagerService extends SystemService { recordStableDisplayStatsIfNeededLocked(display); recordTopInsetLocked(display); } - addDisplayPowerControllerLocked(display); - mDisplayStates.append(displayId, Display.STATE_UNKNOWN); + final int groupId = mLogicalDisplayMapper.getDisplayGroupIdFromDisplayIdLocked(displayId); + if (groupId != Display.INVALID_DISPLAY_GROUP) { + addDisplayPowerControllerLocked(display); + mDisplayStates.append(displayId, Display.STATE_UNKNOWN); + } else { + mDisplayStates.append(displayId, Display.STATE_ON); + } mDisplayBrightnesses.append(displayId, display.getDisplayInfoLocked().brightnessDefault); DisplayManagerGlobal.invalidateLocalDisplayInfoCaches(); @@ -1214,8 +1219,7 @@ public final class DisplayManagerService extends SystemService { final int displayId = display.getDisplayIdLocked(); final int state = mDisplayStates.get(displayId); - // Only send a request for display state if the display state has already been - // initialized by DisplayPowercontroller. + // Only send a request for display state if display state has already been initialized. if (state != Display.STATE_UNKNOWN) { final float brightness = mDisplayBrightnesses.get(displayId); return device.requestDisplayStateLocked(state, brightness); diff --git a/services/core/java/com/android/server/display/LogicalDisplayMapper.java b/services/core/java/com/android/server/display/LogicalDisplayMapper.java index fcfa674dcc4e..6c2e6ebf91ea 100644 --- a/services/core/java/com/android/server/display/LogicalDisplayMapper.java +++ b/services/core/java/com/android/server/display/LogicalDisplayMapper.java @@ -433,31 +433,37 @@ class LogicalDisplayMapper implements DisplayDeviceRepository.Listener { final int displayId = display.getDisplayIdLocked(); // Get current display group data - int groupId = getDisplayGroupIdFromDisplayIdLocked(displayId); + final int groupId = getDisplayGroupIdFromDisplayIdLocked(displayId); final DisplayGroup oldGroup = getDisplayGroupLocked(groupId); // Get the new display group if a change is needed final DisplayInfo info = display.getDisplayInfoLocked(); final boolean needsOwnDisplayGroup = (info.flags & Display.FLAG_OWN_DISPLAY_GROUP) != 0; final boolean hasOwnDisplayGroup = groupId != Display.DEFAULT_DISPLAY_GROUP; + final boolean needsDisplayGroup = needsOwnDisplayGroup || info.type == Display.TYPE_INTERNAL + || info.type == Display.TYPE_EXTERNAL; + if (!needsDisplayGroup) { + if (oldGroup != null) { + oldGroup.removeDisplayLocked(display); + } + return; + } if (groupId == Display.INVALID_DISPLAY_GROUP || hasOwnDisplayGroup != needsOwnDisplayGroup) { - groupId = assignDisplayGroupIdLocked(needsOwnDisplayGroup); - } - - // Create a new group if needed - DisplayGroup newGroup = getDisplayGroupLocked(groupId); - if (newGroup == null) { - newGroup = new DisplayGroup(groupId); - mDisplayGroups.append(groupId, newGroup); - } - if (oldGroup != newGroup) { if (oldGroup != null) { oldGroup.removeDisplayLocked(display); } + + final int newGroupId = assignDisplayGroupIdLocked(needsOwnDisplayGroup); + // Create a new group if needed + DisplayGroup newGroup = getDisplayGroupLocked(newGroupId); + if (newGroup == null) { + newGroup = new DisplayGroup(newGroupId); + mDisplayGroups.append(newGroupId, newGroup); + } newGroup.addDisplayLocked(display); - display.updateDisplayGroupIdLocked(groupId); - Slog.i(TAG, "Setting new display group " + groupId + " for display " + display.updateDisplayGroupIdLocked(newGroupId); + Slog.i(TAG, "Setting new display group " + newGroupId + " for display " + displayId + ", from previous group: " + (oldGroup != null ? oldGroup.getGroupId() : "null")); } diff --git a/services/core/java/com/android/server/notification/NotificationManagerService.java b/services/core/java/com/android/server/notification/NotificationManagerService.java index e58836659189..eb4f9d305a27 100755 --- a/services/core/java/com/android/server/notification/NotificationManagerService.java +++ b/services/core/java/com/android/server/notification/NotificationManagerService.java @@ -3576,15 +3576,30 @@ public class NotificationManagerService extends SystemService { pkg, uid, channelId, conversationId, true, includeDeleted); } + // Returns 'true' if the given channel has a notification associated + // with an active foreground service. + private void enforceDeletingChannelHasNoFgService(String pkg, int userId, + String channelId) { + if (mAmi.hasForegroundServiceNotification(pkg, userId, channelId)) { + Slog.w(TAG, "Package u" + userId + "/" + pkg + + " may not delete notification channel '" + + channelId + "' with fg service"); + throw new SecurityException("Not allowed to delete channel " + channelId + + " with a foreground service"); + } + } + @Override public void deleteNotificationChannel(String pkg, String channelId) { checkCallerIsSystemOrSameApp(pkg); final int callingUid = Binder.getCallingUid(); + final int callingUser = UserHandle.getUserId(callingUid); if (NotificationChannel.DEFAULT_CHANNEL_ID.equals(channelId)) { throw new IllegalArgumentException("Cannot delete default channel"); } + enforceDeletingChannelHasNoFgService(pkg, callingUser, channelId); cancelAllNotificationsInt(MY_UID, MY_PID, pkg, channelId, 0, 0, true, - UserHandle.getUserId(callingUid), REASON_CHANNEL_BANNED, null); + callingUser, REASON_CHANNEL_BANNED, null); mPreferencesHelper.deleteNotificationChannel(pkg, callingUid, channelId); mListeners.notifyNotificationChannelChanged(pkg, UserHandle.getUserHandleForUid(callingUid), @@ -3597,19 +3612,23 @@ public class NotificationManagerService extends SystemService { public void deleteConversationNotificationChannels(String pkg, int uid, String conversationId) { checkCallerIsSystem(); - final int callingUid = Binder.getCallingUid(); List<NotificationChannel> channels = mPreferencesHelper.getNotificationChannelsByConversationId( pkg, uid, conversationId); if (!channels.isEmpty()) { + // Preflight for fg service notifications in these channels: do nothing + // unless they're all eligible + final int appUserId = UserHandle.getUserId(uid); for (NotificationChannel nc : channels) { + final String channelId = nc.getId(); + mAmi.stopForegroundServicesForChannel(pkg, appUserId, channelId); cancelAllNotificationsInt(MY_UID, MY_PID, pkg, nc.getId(), 0, 0, true, - UserHandle.getUserId(callingUid), REASON_CHANNEL_BANNED, null); - mPreferencesHelper.deleteNotificationChannel(pkg, callingUid, nc.getId()); + appUserId, REASON_CHANNEL_BANNED, null); + mPreferencesHelper.deleteNotificationChannel(pkg, uid, channelId); mListeners.notifyNotificationChannelChanged(pkg, - UserHandle.getUserHandleForUid(callingUid), + UserHandle.getUserHandleForUid(uid), mPreferencesHelper.getNotificationChannel( - pkg, callingUid, nc.getId(), true), + pkg, uid, channelId, true), NOTIFICATION_CHANNEL_OR_GROUP_DELETED); } handleSavePolicyFile(); @@ -3640,13 +3659,20 @@ public class NotificationManagerService extends SystemService { NotificationChannelGroup groupToDelete = mPreferencesHelper.getNotificationChannelGroup(groupId, pkg, callingUid); if (groupToDelete != null) { + // Preflight for allowability + final int userId = UserHandle.getUserId(callingUid); + List<NotificationChannel> groupChannels = groupToDelete.getChannels(); + for (int i = 0; i < groupChannels.size(); i++) { + enforceDeletingChannelHasNoFgService(pkg, userId, + groupChannels.get(i).getId()); + } List<NotificationChannel> deletedChannels = mPreferencesHelper.deleteNotificationChannelGroup(pkg, callingUid, groupId); for (int i = 0; i < deletedChannels.size(); i++) { final NotificationChannel deletedChannel = deletedChannels.get(i); cancelAllNotificationsInt(MY_UID, MY_PID, pkg, deletedChannel.getId(), 0, 0, true, - UserHandle.getUserId(Binder.getCallingUid()), REASON_CHANNEL_BANNED, + userId, REASON_CHANNEL_BANNED, null); mListeners.notifyNotificationChannelChanged(pkg, UserHandle.getUserHandleForUid(callingUid), diff --git a/services/core/java/com/android/server/om/OverlayManagerService.java b/services/core/java/com/android/server/om/OverlayManagerService.java index dbd121137b57..27b164830572 100644 --- a/services/core/java/com/android/server/om/OverlayManagerService.java +++ b/services/core/java/com/android/server/om/OverlayManagerService.java @@ -103,7 +103,6 @@ import java.util.HashSet; import java.util.List; import java.util.Map; import java.util.Objects; -import java.util.Optional; import java.util.Set; /** @@ -312,7 +311,7 @@ public final class OverlayManagerService extends SystemService { // Initialize any users that can't be switched to, as their state would // never be setup in onSwitchUser(). We will switch to the system user right // after this, and its state will be setup there. - updatePackageManager(mImpl.updateOverlaysForUser(users.get(i).id)); + updatePackageManagerLocked(mImpl.updateOverlaysForUser(users.get(i).id)); } } } @@ -329,9 +328,8 @@ public final class OverlayManagerService extends SystemService { // ensure overlays in the settings are up-to-date, and propagate // any asset changes to the rest of the system synchronized (mLock) { - updateActivityManager(updatePackageManager(mImpl.updateOverlaysForUser(newUserId))); + updateTargetPackagesLocked(mImpl.updateOverlaysForUser(newUserId)); } - persistSettings(); } finally { traceEnd(TRACE_TAG_RRO); } @@ -415,7 +413,8 @@ public final class OverlayManagerService extends SystemService { packageName, userId); if (pkg != null && !mPackageManager.isInstantApp(packageName, userId)) { try { - updateTargetPackages(mImpl.onPackageAdded(packageName, userId)); + updateTargetPackagesLocked( + mImpl.onPackageAdded(packageName, userId)); } catch (OperationFailedException e) { Slog.e(TAG, "onPackageAdded internal error", e); } @@ -437,7 +436,8 @@ public final class OverlayManagerService extends SystemService { packageName, userId); if (pkg != null && !mPackageManager.isInstantApp(packageName, userId)) { try { - updateTargetPackages(mImpl.onPackageChanged(packageName, userId)); + updateTargetPackagesLocked( + mImpl.onPackageChanged(packageName, userId)); } catch (OperationFailedException e) { Slog.e(TAG, "onPackageChanged internal error", e); } @@ -459,7 +459,8 @@ public final class OverlayManagerService extends SystemService { packageName, userId); if (pkg != null && !mPackageManager.isInstantApp(packageName, userId)) { try { - updateTargetPackages(mImpl.onPackageReplacing(packageName, userId)); + updateTargetPackagesLocked( + mImpl.onPackageReplacing(packageName, userId)); } catch (OperationFailedException e) { Slog.e(TAG, "onPackageReplacing internal error", e); } @@ -481,7 +482,8 @@ public final class OverlayManagerService extends SystemService { packageName, userId); if (pkg != null && !mPackageManager.isInstantApp(packageName, userId)) { try { - updateTargetPackages(mImpl.onPackageReplaced(packageName, userId)); + updateTargetPackagesLocked( + mImpl.onPackageReplaced(packageName, userId)); } catch (OperationFailedException e) { Slog.e(TAG, "onPackageReplaced internal error", e); } @@ -500,7 +502,7 @@ public final class OverlayManagerService extends SystemService { for (int userId : userIds) { synchronized (mLock) { mPackageManager.onPackageRemoved(packageName, userId); - updateTargetPackages(mImpl.onPackageRemoved(packageName, userId)); + updateTargetPackagesLocked(mImpl.onPackageRemoved(packageName, userId)); } } } finally { @@ -519,7 +521,7 @@ public final class OverlayManagerService extends SystemService { try { traceBegin(TRACE_TAG_RRO, "OMS ACTION_USER_ADDED"); synchronized (mLock) { - updatePackageManager(mImpl.updateOverlaysForUser(userId)); + updatePackageManagerLocked(mImpl.updateOverlaysForUser(userId)); } } finally { traceEnd(TRACE_TAG_RRO); @@ -624,7 +626,8 @@ public final class OverlayManagerService extends SystemService { try { synchronized (mLock) { try { - updateTargetPackages(mImpl.setEnabled(overlay, enable, realUserId)); + updateTargetPackagesLocked( + mImpl.setEnabled(overlay, enable, realUserId)); return true; } catch (OperationFailedException e) { return false; @@ -656,9 +659,10 @@ public final class OverlayManagerService extends SystemService { try { synchronized (mLock) { try { - mImpl.setEnabledExclusive(overlay, - false /* withinCategory */, realUserId) - .ifPresent(OverlayManagerService.this::updateTargetPackages); + mImpl.setEnabledExclusive( + overlay, false /* withinCategory */, realUserId) + .ifPresent( + OverlayManagerService.this::updateTargetPackagesLocked); return true; } catch (OperationFailedException e) { return false; @@ -693,7 +697,7 @@ public final class OverlayManagerService extends SystemService { try { mImpl.setEnabledExclusive(overlay, true /* withinCategory */, realUserId) - .ifPresent(OverlayManagerService.this::updateTargetPackages); + .ifPresent(OverlayManagerService.this::updateTargetPackagesLocked); return true; } catch (OperationFailedException e) { return false; @@ -728,7 +732,7 @@ public final class OverlayManagerService extends SystemService { synchronized (mLock) { try { mImpl.setPriority(overlay, parentOverlay, realUserId) - .ifPresent(OverlayManagerService.this::updateTargetPackages); + .ifPresent(OverlayManagerService.this::updateTargetPackagesLocked); return true; } catch (OperationFailedException e) { return false; @@ -759,7 +763,8 @@ public final class OverlayManagerService extends SystemService { try { synchronized (mLock) { try { - updateTargetPackages(mImpl.setHighestPriority(overlay, realUserId)); + updateTargetPackagesLocked( + mImpl.setHighestPriority(overlay, realUserId)); return true; } catch (OperationFailedException e) { return false; @@ -791,7 +796,7 @@ public final class OverlayManagerService extends SystemService { synchronized (mLock) { try { mImpl.setLowestPriority(overlay, realUserId) - .ifPresent(OverlayManagerService.this::updateTargetPackages); + .ifPresent(OverlayManagerService.this::updateTargetPackagesLocked); return true; } catch (OperationFailedException e) { return false; @@ -945,27 +950,12 @@ public final class OverlayManagerService extends SystemService { throw new IllegalArgumentException("null transaction"); } - // map: userId -> set<package-name>: target packages of overlays in - // this transaction - final SparseArray<Set<String>> transactionTargets = new SparseArray<>(); - - // map: userId -> set<package-name>: packages that need to reload - // their resources due to changes to the overlays in this - // transaction - final SparseArray<List<String>> affectedPackagesToUpdate = new SparseArray<>(); - synchronized (mLock) { // execute the requests (as calling user) + Set<PackageAndUser> affectedPackagesToUpdate = null; for (final OverlayManagerTransaction.Request request : transaction) { - executeRequest(request).forEach( - target -> { - Set<String> userTargets = transactionTargets.get(target.userId); - if (userTargets == null) { - userTargets = new ArraySet<>(); - transactionTargets.put(target.userId, userTargets); - } - userTargets.add(target.packageName); - }); + affectedPackagesToUpdate = CollectionUtils.addAll(affectedPackagesToUpdate, + executeRequest(request)); } // past the point of no return: the entire transaction has been @@ -973,37 +963,11 @@ public final class OverlayManagerService extends SystemService { // system_server final long ident = Binder.clearCallingIdentity(); try { - persistSettings(); - - // inform the package manager about the new paths - for (int index = 0; index < transactionTargets.size(); index++) { - final int userId = transactionTargets.keyAt(index); - final List<String> affectedTargets = - updatePackageManager(transactionTargets.valueAt(index), userId); - affectedPackagesToUpdate.put(userId, affectedTargets); - } - } finally { - Binder.restoreCallingIdentity(ident); - } - } // synchronized (mLock) - - FgThread.getHandler().post(() -> { - final long ident = Binder.clearCallingIdentity(); - try { - // schedule apps to refresh - updateActivityManager(affectedPackagesToUpdate); - - // broadcast the ACTION_OVERLAY_CHANGED intents - for (int index = 0; index < transactionTargets.size(); index++) { - final int userId = transactionTargets.keyAt(index); - for (String pkg: transactionTargets.valueAt(index)) { - broadcastActionOverlayChanged(pkg, userId); - } - } + updateTargetPackagesLocked(affectedPackagesToUpdate); } finally { Binder.restoreCallingIdentity(ident); } - }); + } } @Override @@ -1382,32 +1346,37 @@ public final class OverlayManagerService extends SystemService { } } - private void updateTargetPackages(@Nullable PackageAndUser updatedTarget) { + private void updateTargetPackagesLocked(@Nullable PackageAndUser updatedTarget) { if (updatedTarget != null) { - updateTargetPackages(Set.of(updatedTarget)); + updateTargetPackagesLocked(Set.of(updatedTarget)); } } - private void updateTargetPackages(@Nullable Set<PackageAndUser> updatedTargets) { + private void updateTargetPackagesLocked(@Nullable Set<PackageAndUser> updatedTargets) { if (CollectionUtils.isEmpty(updatedTargets)) { return; } - persistSettings(); + persistSettingsLocked(); final SparseArray<ArraySet<String>> userTargets = groupTargetsByUserId(updatedTargets); - FgThread.getHandler().post(() -> { - for (int i = 0, n = userTargets.size(); i < n; i++) { - final ArraySet<String> targets = userTargets.valueAt(i); - final int userId = userTargets.keyAt(i); + for (int i = 0, n = userTargets.size(); i < n; i++) { + final ArraySet<String> targets = userTargets.valueAt(i); + final int userId = userTargets.keyAt(i); + final List<String> affectedPackages = updatePackageManagerLocked(targets, userId); + if (affectedPackages.isEmpty()) { + // The package manager paths are already up-to-date. + continue; + } - // Update the overlay paths in package manager. - final List<String> affectedPackages = updatePackageManager(targets, userId); + FgThread.getHandler().post(() -> { + // Send configuration changed events for all target packages that have been affected + // by overlay state changes. updateActivityManager(affectedPackages, userId); - // Overlays targeting shared libraries may cause more packages to need to be - // refreshed. + // Do not send broadcasts for all affected targets. Overlays targeting the framework + // or shared libraries may cause too many broadcasts to be sent at once. broadcastActionOverlayChanged(targets, userId); - } - }); + }); + } } @Nullable @@ -1430,20 +1399,17 @@ public final class OverlayManagerService extends SystemService { private static void broadcastActionOverlayChanged(@NonNull final Set<String> targetPackages, final int userId) { - CollectionUtils.forEach(targetPackages, - target -> broadcastActionOverlayChanged(target, userId)); - } - - private static void broadcastActionOverlayChanged(String targetPackage, final int userId) { - final Intent intent = new Intent(ACTION_OVERLAY_CHANGED, - Uri.fromParts("package", targetPackage, null)); - intent.setFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT); - try { - ActivityManager.getService().broadcastIntent(null, intent, null, null, 0, null, null, - null, android.app.AppOpsManager.OP_NONE, null, false, false, userId); - } catch (RemoteException e) { - // Intentionally left empty. - } + CollectionUtils.forEach(targetPackages, target -> { + final Intent intent = new Intent(ACTION_OVERLAY_CHANGED, + Uri.fromParts("package", target, null)); + intent.setFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT); + try { + ActivityManager.getService().broadcastIntent(null, intent, null, null, 0, null, + null, null, android.app.AppOpsManager.OP_NONE, null, false, false, userId); + } catch (RemoteException e) { + Slog.e(TAG, "broadcastActionOverlayChanged remote exception", e); + } + }); } /** @@ -1455,18 +1421,13 @@ public final class OverlayManagerService extends SystemService { try { am.scheduleApplicationInfoChanged(targetPackageNames, userId); } catch (RemoteException e) { - // Intentionally left empty. - } - } - - private void updateActivityManager(@NonNull SparseArray<List<String>> targetPackageNames) { - for (int i = 0, n = targetPackageNames.size(); i < n; i++) { - updateActivityManager(targetPackageNames.valueAt(i), targetPackageNames.keyAt(i)); + Slog.e(TAG, "updateActivityManager remote exception", e); } } @NonNull - private SparseArray<List<String>> updatePackageManager(@Nullable Set<PackageAndUser> targets) { + private SparseArray<List<String>> updatePackageManagerLocked( + @Nullable Set<PackageAndUser> targets) { if (CollectionUtils.isEmpty(targets)) { return new SparseArray<>(); } @@ -1474,7 +1435,7 @@ public final class OverlayManagerService extends SystemService { final SparseArray<ArraySet<String>> userTargets = groupTargetsByUserId(targets); for (int i = 0, n = userTargets.size(); i < n; i++) { final int userId = userTargets.keyAt(i); - affectedTargets.put(userId, updatePackageManager(userTargets.valueAt(i), userId)); + affectedTargets.put(userId, updatePackageManagerLocked(userTargets.valueAt(i), userId)); } return affectedTargets; } @@ -1485,10 +1446,10 @@ public final class OverlayManagerService extends SystemService { * targetPackageNames: the target themselves and shared libraries) */ @NonNull - private List<String> updatePackageManager(@NonNull Collection<String> targetPackageNames, + private List<String> updatePackageManagerLocked(@NonNull Collection<String> targetPackageNames, final int userId) { try { - traceBegin(TRACE_TAG_RRO, "OMS#updatePackageManager " + targetPackageNames); + traceBegin(TRACE_TAG_RRO, "OMS#updatePackageManagerLocked " + targetPackageNames); if (DEBUG) { Slog.d(TAG, "Update package manager about changed overlays"); } @@ -1535,20 +1496,18 @@ public final class OverlayManagerService extends SystemService { } } - private void persistSettings() { + private void persistSettingsLocked() { if (DEBUG) { Slog.d(TAG, "Writing overlay settings"); } - synchronized (mLock) { - FileOutputStream stream = null; - try { - stream = mSettingsFile.startWrite(); - mSettings.persist(stream); - mSettingsFile.finishWrite(stream); - } catch (IOException | XmlPullParserException e) { - mSettingsFile.failWrite(stream); - Slog.e(TAG, "failed to persist overlay state", e); - } + FileOutputStream stream = null; + try { + stream = mSettingsFile.startWrite(); + mSettings.persist(stream); + mSettingsFile.finishWrite(stream); + } catch (IOException | XmlPullParserException e) { + mSettingsFile.failWrite(stream); + Slog.e(TAG, "failed to persist overlay state", e); } } diff --git a/services/core/java/com/android/server/pm/UserManagerService.java b/services/core/java/com/android/server/pm/UserManagerService.java index 8283ac668d5e..fe19956ce8ce 100644 --- a/services/core/java/com/android/server/pm/UserManagerService.java +++ b/services/core/java/com/android/server/pm/UserManagerService.java @@ -2861,6 +2861,100 @@ public class UserManagerService extends IUserManager.Stub { } } + @GuardedBy("mUsersLock") + @VisibleForTesting + void upgradeUserTypesLU(@NonNull List<UserTypeFactory.UserTypeUpgrade> upgradeOps, + @NonNull ArrayMap<String, UserTypeDetails> userTypes, + final int formerUserTypeVersion, + @NonNull Set<Integer> userIdsToWrite) { + for (UserTypeFactory.UserTypeUpgrade userTypeUpgrade : upgradeOps) { + if (DBG) { + Slog.i(LOG_TAG, "Upgrade: " + userTypeUpgrade.getFromType() + " to: " + + userTypeUpgrade.getToType() + " maxVersion: " + + userTypeUpgrade.getUpToVersion()); + } + + // upgrade user type if version up to getUpToVersion() + if (formerUserTypeVersion <= userTypeUpgrade.getUpToVersion()) { + for (int i = 0; i < mUsers.size(); i++) { + UserData userData = mUsers.valueAt(i); + if (userTypeUpgrade.getFromType().equals(userData.info.userType)) { + final UserTypeDetails newUserType = userTypes.get( + userTypeUpgrade.getToType()); + + if (newUserType == null) { + throw new IllegalStateException( + "Upgrade destination user type not defined: " + + userTypeUpgrade.getToType()); + } + + upgradeProfileToTypeLU(userData.info, newUserType); + userIdsToWrite.add(userData.info.id); + } + } + } + } + } + + /** + * Changes the user type of a profile to a new user type. + * @param userInfo The user to be updated. + * @param newUserType The new user type. + */ + @GuardedBy("mUsersLock") + @VisibleForTesting + void upgradeProfileToTypeLU(@NonNull UserInfo userInfo, @NonNull UserTypeDetails newUserType) { + Slog.i(LOG_TAG, "Upgrading user " + userInfo.id + + " from " + userInfo.userType + + " to " + newUserType.getName()); + + if (!userInfo.isProfile()) { + throw new IllegalStateException( + "Can only upgrade profile types. " + userInfo.userType + + " is not a profile type."); + } + + // Exceeded maximum profiles for parent user: log error, but allow upgrade + if (!canAddMoreProfilesToUser(newUserType.getName(), userInfo.profileGroupId, false)) { + Slog.w(LOG_TAG, + "Exceeded maximum profiles of type " + newUserType.getName() + " for user " + + userInfo.id + ". Maximum allowed= " + + newUserType.getMaxAllowedPerParent()); + } + + final UserTypeDetails oldUserType = mUserTypes.get(userInfo.userType); + final int oldFlags; + if (oldUserType != null) { + oldFlags = oldUserType.getDefaultUserInfoFlags(); + } else { + // if oldUserType is missing from config_user_types.xml -> can only assume FLAG_PROFILE + oldFlags = UserInfo.FLAG_PROFILE; + } + + //convert userData to newUserType + userInfo.userType = newUserType.getName(); + // remove old default flags and add newUserType's default flags + userInfo.flags = newUserType.getDefaultUserInfoFlags() | (userInfo.flags ^ oldFlags); + + // merge existing base restrictions with the new type's default restrictions + synchronized (mRestrictionsLock) { + if (!BundleUtils.isEmpty(newUserType.getDefaultRestrictions())) { + final Bundle newRestrictions = BundleUtils.clone( + mBaseUserRestrictions.getRestrictions(userInfo.id)); + UserRestrictionsUtils.merge(newRestrictions, + newUserType.getDefaultRestrictions()); + updateUserRestrictionsInternalLR(newRestrictions, userInfo.id); + if (DBG) { + Slog.i(LOG_TAG, "Updated user " + userInfo.id + + " restrictions to " + newRestrictions); + } + } + } + + // re-compute badge index + userInfo.profileBadge = getFreeProfileBadgeLU(userInfo.profileGroupId, userInfo.userType); + } + @GuardedBy({"mPackagesLock", "mRestrictionsLock"}) private void fallbackToSingleUserLP() { int flags = UserInfo.FLAG_SYSTEM | UserInfo.FLAG_INITIALIZED | UserInfo.FLAG_ADMIN @@ -5759,98 +5853,4 @@ public class UserManagerService extends IUserManager.Stub { } return mDevicePolicyManagerInternal; } - - @GuardedBy("mUsersLock") - @VisibleForTesting - void upgradeUserTypesLU(@NonNull List<UserTypeFactory.UserTypeUpgrade> upgradeOps, - @NonNull ArrayMap<String, UserTypeDetails> userTypes, - final int formerUserTypeVersion, - @NonNull Set<Integer> userIdsToWrite) { - for (UserTypeFactory.UserTypeUpgrade userTypeUpgrade : upgradeOps) { - if (DBG) { - Slog.i(LOG_TAG, "Upgrade: " + userTypeUpgrade.getFromType() + " to: " - + userTypeUpgrade.getToType() + " maxVersion: " - + userTypeUpgrade.getUpToVersion()); - } - - // upgrade user type if version up to getUpToVersion() - if (formerUserTypeVersion <= userTypeUpgrade.getUpToVersion()) { - for (int i = 0; i < mUsers.size(); i++) { - UserData userData = mUsers.valueAt(i); - if (userTypeUpgrade.getFromType().equals(userData.info.userType)) { - final UserTypeDetails newUserType = userTypes.get( - userTypeUpgrade.getToType()); - - if (newUserType == null) { - throw new IllegalStateException( - "Upgrade destination user type not defined: " - + userTypeUpgrade.getToType()); - } - - upgradeProfileToTypeLU(userData.info, newUserType); - userIdsToWrite.add(userData.info.id); - } - } - } - } - } - - /** - * Changes the user type of a profile to a new user type. - * @param userInfo The user to be updated. - * @param newUserType The new user type. - */ - @GuardedBy("mUsersLock") - @VisibleForTesting - void upgradeProfileToTypeLU(@NonNull UserInfo userInfo, @NonNull UserTypeDetails newUserType) { - Slog.i(LOG_TAG, "Upgrading user " + userInfo.id - + " from " + userInfo.userType - + " to " + newUserType.getName()); - - if (!userInfo.isProfile()) { - throw new IllegalStateException( - "Can only upgrade profile types. " + userInfo.userType - + " is not a profile type."); - } - - // Exceeded maximum profiles for parent user: log error, but allow upgrade - if (!canAddMoreProfilesToUser(newUserType.getName(), userInfo.profileGroupId, false)) { - Slog.w(LOG_TAG, - "Exceeded maximum profiles of type " + newUserType.getName() + " for user " - + userInfo.id + ". Maximum allowed= " - + newUserType.getMaxAllowedPerParent()); - } - - final UserTypeDetails oldUserType = mUserTypes.get(userInfo.userType); - final int oldFlags; - if (oldUserType != null) { - oldFlags = oldUserType.getDefaultUserInfoFlags(); - } else { - // if oldUserType is missing from config_user_types.xml -> can only assume FLAG_PROFILE - oldFlags = UserInfo.FLAG_PROFILE; - } - - //convert userData to newUserType - userInfo.userType = newUserType.getName(); - // remove old default flags and add newUserType's default flags - userInfo.flags = newUserType.getDefaultUserInfoFlags() | (userInfo.flags ^ oldFlags); - - // merge existing base restrictions with the new type's default restrictions - synchronized (mRestrictionsLock) { - if (!BundleUtils.isEmpty(newUserType.getDefaultRestrictions())) { - final Bundle newRestrictions = BundleUtils.clone( - mBaseUserRestrictions.getRestrictions(userInfo.id)); - UserRestrictionsUtils.merge(newRestrictions, - newUserType.getDefaultRestrictions()); - updateUserRestrictionsInternalLR(newRestrictions, userInfo.id); - if (DBG) { - Slog.i(LOG_TAG, "Updated user " + userInfo.id - + " restrictions to " + newRestrictions); - } - } - } - - // re-compute badge index - userInfo.profileBadge = getFreeProfileBadgeLU(userInfo.profileGroupId, userInfo.userType); - } } diff --git a/services/core/java/com/android/server/wm/WindowManagerShellCommand.java b/services/core/java/com/android/server/wm/WindowManagerShellCommand.java index a46a8d56e226..64a26ec69f03 100644 --- a/services/core/java/com/android/server/wm/WindowManagerShellCommand.java +++ b/services/core/java/com/android/server/wm/WindowManagerShellCommand.java @@ -17,6 +17,7 @@ package com.android.server.wm; import static android.os.Build.IS_USER; +import static android.view.CrossWindowBlurListeners.CROSS_WINDOW_BLUR_SUPPORTED; import static com.android.server.wm.WindowManagerService.LETTERBOX_BACKGROUND_APP_COLOR_BACKGROUND; import static com.android.server.wm.WindowManagerService.LETTERBOX_BACKGROUND_APP_COLOR_BACKGROUND_FLOATING; @@ -135,6 +136,8 @@ public class WindowManagerShellCommand extends ShellCommand { return runGetLetterboxBackgroundColor(pw); case "reset": return runReset(pw); + case "disable-blur": + return runSetBlurDisabled(pw); default: return handleDefaultCommands(cmd); } @@ -214,6 +217,33 @@ public class WindowManagerShellCommand extends ShellCommand { return 0; } + private int runSetBlurDisabled(PrintWriter pw) throws RemoteException { + String arg = getNextArg(); + if (arg == null) { + pw.println("Blur supported on device: " + CROSS_WINDOW_BLUR_SUPPORTED); + pw.println("Blur enabled: " + mInternal.mBlurController.mBlurEnabled); + return 0; + } + + final boolean disableBlur; + switch (arg) { + case "true": + case "1": + disableBlur = true; + break; + case "false": + case "0": + disableBlur = false; + break; + default: + getErrPrintWriter().println("Error: expected true, 1, false, 0, but got " + arg); + return -1; + } + + mInterface.setForceCrossWindowBlurDisabled(disableBlur); + return 0; + } + private void printInitialDisplayDensity(PrintWriter pw , int displayId) { try { final int initialDensity = mInterface.getInitialDisplayDensity(displayId); @@ -725,6 +755,7 @@ public class WindowManagerShellCommand extends ShellCommand { pw.println(" Set display scaling mode."); pw.println(" dismiss-keyguard"); pw.println(" Dismiss the keyguard, prompting user for auth if necessary."); + pw.println(" disable-blur [true|1|false|0]"); pw.println(" user-rotation [-d DISPLAY_ID] [free|lock] [rotation]"); pw.println(" Print or set user rotation mode and user rotation."); pw.println(" dump-visible-window-views"); diff --git a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java index a8131e4e00ce..283895bb53e2 100644 --- a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java +++ b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java @@ -51,6 +51,7 @@ import static android.app.admin.DevicePolicyManager.DELEGATION_KEEP_UNINSTALLED_ import static android.app.admin.DevicePolicyManager.DELEGATION_NETWORK_LOGGING; import static android.app.admin.DevicePolicyManager.DELEGATION_PACKAGE_ACCESS; import static android.app.admin.DevicePolicyManager.DELEGATION_PERMISSION_GRANT; +import static android.app.admin.DevicePolicyManager.DELEGATION_SECURITY_LOGGING; import static android.app.admin.DevicePolicyManager.ENCRYPTION_STATUS_ACTIVE_PER_USER; import static android.app.admin.DevicePolicyManager.ID_TYPE_BASE_INFO; import static android.app.admin.DevicePolicyManager.ID_TYPE_IMEI; @@ -430,6 +431,7 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager { DELEGATION_INSTALL_EXISTING_PACKAGE, DELEGATION_KEEP_UNINSTALLED_PACKAGES, DELEGATION_NETWORK_LOGGING, + DELEGATION_SECURITY_LOGGING, DELEGATION_CERT_SELECTION, }; @@ -440,9 +442,18 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager { DELEGATION_NETWORK_LOGGING, }); + // Subset of delegations that can only be delegated by Device Owner or Profile Owner of an + // organization-owned and managed profile. + private static final List<String> + DEVICE_OWNER_OR_ORGANIZATION_OWNED_MANAGED_PROFILE_OWNER_DELEGATIONS = + Arrays.asList(new String[]{ + DELEGATION_SECURITY_LOGGING, + }); + // Subset of delegations that only one single package within a given user can hold private static final List<String> EXCLUSIVE_DELEGATIONS = Arrays.asList(new String[] { DELEGATION_NETWORK_LOGGING, + DELEGATION_SECURITY_LOGGING, DELEGATION_CERT_SELECTION, }); @@ -6024,6 +6035,10 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager { if (!Collections.disjoint(scopes, DEVICE_OWNER_OR_MANAGED_PROFILE_OWNER_DELEGATIONS)) { Preconditions.checkCallAuthorization(isDeviceOwner(caller) || (isProfileOwner(caller) && isManagedProfile(caller.getUserId()))); + } else if (!Collections.disjoint( + scopes, DEVICE_OWNER_OR_ORGANIZATION_OWNED_MANAGED_PROFILE_OWNER_DELEGATIONS)) { + Preconditions.checkCallAuthorization(isDeviceOwner(caller) + || isProfileOwnerOfOrganizationOwnedDevice(caller)); } else { Preconditions.checkCallAuthorization(isDeviceOwner(caller) || isProfileOwner(caller)); } @@ -7658,6 +7673,10 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager { receiverComponent = resolveDelegateReceiver(DELEGATION_NETWORK_LOGGING, action, deviceOwnerUserId); } + if (action.equals(DeviceAdminReceiver.ACTION_SECURITY_LOGS_AVAILABLE)) { + receiverComponent = resolveDelegateReceiver(DELEGATION_SECURITY_LOGGING, action, + deviceOwnerUserId); + } if (receiverComponent == null) { synchronized (getLockObject()) { receiverComponent = mOwners.getDeviceOwnerComponent(); @@ -7674,6 +7693,10 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager { if (action.equals(DeviceAdminReceiver.ACTION_NETWORK_LOGS_AVAILABLE)) { receiverComponent = resolveDelegateReceiver(DELEGATION_NETWORK_LOGGING, action, userId); } + if (action.equals(DeviceAdminReceiver.ACTION_SECURITY_LOGS_AVAILABLE)) { + receiverComponent = resolveDelegateReceiver( + DELEGATION_SECURITY_LOGGING, action, userId); + } if (receiverComponent == null) { receiverComponent = getOwnerComponent(userId); } @@ -13920,16 +13943,24 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager { } @Override - public void setSecurityLoggingEnabled(ComponentName admin, boolean enabled) { + public void setSecurityLoggingEnabled(ComponentName admin, String packageName, + boolean enabled) { if (!mHasFeature) { return; } - Objects.requireNonNull(admin); - final CallerIdentity caller = getCallerIdentity(admin); + final CallerIdentity caller = getCallerIdentity(admin, packageName); synchronized (getLockObject()) { - Preconditions.checkCallAuthorization(isProfileOwnerOfOrganizationOwnedDevice(caller) - || isDeviceOwner(caller)); + if (admin != null) { + Preconditions.checkCallAuthorization( + isProfileOwnerOfOrganizationOwnedDevice(caller) + || isDeviceOwner(caller)); + } else { + // A delegate app passes a null admin component, which is expected + Preconditions.checkCallAuthorization( + isCallerDelegate(caller, DELEGATION_SECURITY_LOGGING)); + } + if (enabled == mInjector.securityLogGetLoggingEnabledProperty()) { return; } @@ -13949,17 +13980,23 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager { } @Override - public boolean isSecurityLoggingEnabled(ComponentName admin) { + public boolean isSecurityLoggingEnabled(ComponentName admin, String packageName) { if (!mHasFeature) { return false; } synchronized (getLockObject()) { if (!isCallerWithSystemUid()) { - Objects.requireNonNull(admin); - final CallerIdentity caller = getCallerIdentity(admin); - Preconditions.checkCallAuthorization( - isProfileOwnerOfOrganizationOwnedDevice(caller) || isDeviceOwner(caller)); + final CallerIdentity caller = getCallerIdentity(admin, packageName); + if (admin != null) { + Preconditions.checkCallAuthorization( + isProfileOwnerOfOrganizationOwnedDevice(caller) + || isDeviceOwner(caller)); + } else { + // A delegate app passes a null admin component, which is expected + Preconditions.checkCallAuthorization( + isCallerDelegate(caller, DELEGATION_SECURITY_LOGGING)); + } } return mInjector.securityLogGetLoggingEnabledProperty(); } @@ -13977,15 +14014,23 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager { } @Override - public ParceledListSlice<SecurityEvent> retrievePreRebootSecurityLogs(ComponentName admin) { + public ParceledListSlice<SecurityEvent> retrievePreRebootSecurityLogs(ComponentName admin, + String packageName) { if (!mHasFeature) { return null; } - Objects.requireNonNull(admin, "ComponentName is null"); - final CallerIdentity caller = getCallerIdentity(admin); - Preconditions.checkCallAuthorization(isDeviceOwner(caller) - || isProfileOwnerOfOrganizationOwnedDevice(caller)); + final CallerIdentity caller = getCallerIdentity(admin, packageName); + if (admin != null) { + Preconditions.checkCallAuthorization( + isProfileOwnerOfOrganizationOwnedDevice(caller) + || isDeviceOwner(caller)); + } else { + // A delegate app passes a null admin component, which is expected + Preconditions.checkCallAuthorization( + isCallerDelegate(caller, DELEGATION_SECURITY_LOGGING)); + } + Preconditions.checkCallAuthorization(isOrganizationOwnedDeviceWithManagedProfile() || areAllUsersAffiliatedWithDeviceLocked()); @@ -14015,15 +14060,22 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager { } @Override - public ParceledListSlice<SecurityEvent> retrieveSecurityLogs(ComponentName admin) { + public ParceledListSlice<SecurityEvent> retrieveSecurityLogs(ComponentName admin, + String packageName) { if (!mHasFeature) { return null; } - Objects.requireNonNull(admin, "ComponentName is null"); - final CallerIdentity caller = getCallerIdentity(admin); - Preconditions.checkCallAuthorization(isDeviceOwner(caller) - || isProfileOwnerOfOrganizationOwnedDevice(caller)); + final CallerIdentity caller = getCallerIdentity(admin, packageName); + if (admin != null) { + Preconditions.checkCallAuthorization( + isProfileOwnerOfOrganizationOwnedDevice(caller) + || isDeviceOwner(caller)); + } else { + // A delegate app passes a null admin component, which is expected + Preconditions.checkCallAuthorization( + isCallerDelegate(caller, DELEGATION_SECURITY_LOGGING)); + } Preconditions.checkCallAuthorization(isOrganizationOwnedDeviceWithManagedProfile() || areAllUsersAffiliatedWithDeviceLocked()); diff --git a/services/incremental/ServiceWrappers.cpp b/services/incremental/ServiceWrappers.cpp index 7e85f9db70fd..34654994c9fc 100644 --- a/services/incremental/ServiceWrappers.cpp +++ b/services/incremental/ServiceWrappers.cpp @@ -255,7 +255,7 @@ public: static JNIEnv* getOrAttachJniEnv(JavaVM* jvm); -class RealTimedQueueWrapper : public TimedQueueWrapper { +class RealTimedQueueWrapper final : public TimedQueueWrapper { public: RealTimedQueueWrapper(JavaVM* jvm) { mThread = std::thread([this, jvm]() { @@ -268,11 +268,11 @@ public: CHECK(!mThread.joinable()) << "call stop first"; } - void addJob(MountId id, Milliseconds after, Job what) final { + void addJob(MountId id, Milliseconds timeout, Job what) final { const auto now = Clock::now(); { std::unique_lock lock(mMutex); - mJobs.insert(TimedJob{id, now + after, std::move(what)}); + mJobs.insert(TimedJob{id, now + timeout, std::move(what)}); } mCondition.notify_all(); } @@ -293,29 +293,28 @@ public: private: void runTimers() { static constexpr TimePoint kInfinityTs{Clock::duration::max()}; - TimePoint nextJobTs = kInfinityTs; std::unique_lock lock(mMutex); for (;;) { - mCondition.wait_until(lock, nextJobTs, [this, nextJobTs]() { + const TimePoint nextJobTs = mJobs.empty() ? kInfinityTs : mJobs.begin()->when; + mCondition.wait_until(lock, nextJobTs, [this, oldNextJobTs = nextJobTs]() { const auto now = Clock::now(); - const auto firstJobTs = !mJobs.empty() ? mJobs.begin()->when : kInfinityTs; - return !mRunning || firstJobTs <= now || firstJobTs < nextJobTs; + const auto newFirstJobTs = !mJobs.empty() ? mJobs.begin()->when : kInfinityTs; + return newFirstJobTs <= now || newFirstJobTs < oldNextJobTs || !mRunning; }); if (!mRunning) { return; } const auto now = Clock::now(); - auto it = mJobs.begin(); - // Always acquire begin(). We can't use it after unlock as mTimedJobs can change. - for (; it != mJobs.end() && it->when <= now; it = mJobs.begin()) { + // Always re-acquire begin(). We can't use it after unlock as mTimedJobs can change. + for (auto it = mJobs.begin(); it != mJobs.end() && it->when <= now; + it = mJobs.begin()) { auto jobNode = mJobs.extract(it); lock.unlock(); jobNode.value().what(); lock.lock(); } - nextJobTs = it != mJobs.end() ? it->when : kInfinityTs; } } @@ -328,7 +327,7 @@ private: } }; bool mRunning = true; - std::set<TimedJob> mJobs; + std::multiset<TimedJob> mJobs; std::condition_variable mCondition; std::mutex mMutex; std::thread mThread; diff --git a/services/tests/mockingservicestests/src/com/android/server/pm/dex/OWNERS b/services/tests/mockingservicestests/src/com/android/server/pm/dex/OWNERS index 5a4431ee8c89..5492dc8e37a3 100644 --- a/services/tests/mockingservicestests/src/com/android/server/pm/dex/OWNERS +++ b/services/tests/mockingservicestests/src/com/android/server/pm/dex/OWNERS @@ -1,2 +1 @@ -calin@google.com -ngeoffray@google.com +include platform/art:/OWNERS
\ No newline at end of file diff --git a/services/tests/servicestests/src/com/android/server/display/LogicalDisplayMapperTest.java b/services/tests/servicestests/src/com/android/server/display/LogicalDisplayMapperTest.java index bcd853c76a79..dcb2c1573424 100644 --- a/services/tests/servicestests/src/com/android/server/display/LogicalDisplayMapperTest.java +++ b/services/tests/servicestests/src/com/android/server/display/LogicalDisplayMapperTest.java @@ -186,11 +186,14 @@ public class LogicalDisplayMapperTest { LogicalDisplay display2 = add(createDisplayDevice(Display.TYPE_INTERNAL, 600, 800, 0)); LogicalDisplay display3 = add(createDisplayDevice(Display.TYPE_VIRTUAL, 600, 800, 0)); + // Physical displays should be automatically put into the default group. assertEquals(Display.DEFAULT_DISPLAY_GROUP, mLogicalDisplayMapper.getDisplayGroupIdFromDisplayIdLocked(id(display1))); assertEquals(Display.DEFAULT_DISPLAY_GROUP, mLogicalDisplayMapper.getDisplayGroupIdFromDisplayIdLocked(id(display2))); - assertEquals(Display.DEFAULT_DISPLAY_GROUP, + + // Virtual displays should belong to no group by default. + assertEquals(Display.INVALID_DISPLAY_GROUP, mLogicalDisplayMapper.getDisplayGroupIdFromDisplayIdLocked(id(display3))); } @@ -212,13 +215,13 @@ public class LogicalDisplayMapperTest { assertNotEquals(Display.DEFAULT_DISPLAY_GROUP, mLogicalDisplayMapper.getDisplayGroupIdFromDisplayIdLocked(id(display3))); - // Now switch it back to the default group by removing the flag and issuing an update + // Now switch it to the invalid group by removing the flag and issuing an update DisplayDeviceInfo info = device3.getSourceInfo(); info.flags = info.flags & ~DisplayDeviceInfo.FLAG_OWN_DISPLAY_GROUP; mDisplayDeviceRepo.onDisplayDeviceEvent(device3, DISPLAY_DEVICE_EVENT_CHANGED); - // Verify the new group is correct. - assertEquals(Display.DEFAULT_DISPLAY_GROUP, + // Verify the virtual display has not been placed into a group. + assertEquals(Display.INVALID_DISPLAY_GROUP, mLogicalDisplayMapper.getDisplayGroupIdFromDisplayIdLocked(id(display3))); } diff --git a/telecomm/java/android/telecom/CallDiagnosticService.java b/telecomm/java/android/telecom/CallDiagnosticService.java index f5357b19c4de..011dc17a1c1e 100644 --- a/telecomm/java/android/telecom/CallDiagnosticService.java +++ b/telecomm/java/android/telecom/CallDiagnosticService.java @@ -27,6 +27,8 @@ import android.os.Handler; import android.os.HandlerExecutor; import android.os.IBinder; import android.os.RemoteException; + +import android.telephony.CallQuality; import android.util.ArrayMap; import com.android.internal.telecom.ICallDiagnosticService; @@ -111,6 +113,12 @@ public abstract class CallDiagnosticService extends Service { @NonNull DisconnectCause disconnectCause) throws RemoteException { handleCallDisconnected(callId, disconnectCause); } + + @Override + public void callQualityChanged(String callId, CallQuality callQuality) + throws RemoteException { + handleCallQualityChanged(callId, callQuality); + } } /** @@ -375,6 +383,21 @@ public abstract class CallDiagnosticService extends Service { } /** + * Handles a change reported by Telecom to the call quality for a call. + * @param callId the call ID the change applies to. + * @param callQuality The new call quality. + */ + private void handleCallQualityChanged(@NonNull String callId, + @NonNull CallQuality callQuality) { + Log.i(this, "handleCallQualityChanged; call=%s, cq=%s", callId, callQuality); + CallDiagnostics callDiagnostics; + callDiagnostics = mDiagnosticCallByTelecomCallId.get(callId); + if (callDiagnostics != null) { + callDiagnostics.onCallQualityReceived(callQuality); + } + } + + /** * Handles a request from a {@link CallDiagnostics} to send a device to device message (received * via {@link CallDiagnostics#sendDeviceToDeviceMessage(int, int)}. * @param callDiagnostics diff --git a/telecomm/java/android/telecom/Connection.java b/telecomm/java/android/telecom/Connection.java index 6dab6df22cf9..2dc18e856349 100644 --- a/telecomm/java/android/telecom/Connection.java +++ b/telecomm/java/android/telecom/Connection.java @@ -44,6 +44,7 @@ import android.os.ParcelFileDescriptor; import android.os.Parcelable; import android.os.RemoteException; import android.os.SystemClock; +import android.telephony.CallQuality; import android.telephony.ims.ImsStreamMediaProfile; import android.util.ArraySet; import android.view.Surface; @@ -978,6 +979,23 @@ public abstract class Connection extends Conferenceable { public static final String EXTRA_DEVICE_TO_DEVICE_MESSAGE_VALUE = "android.telecom.extra.DEVICE_TO_DEVICE_MESSAGE_VALUE"; + /** + * Connection event used to communicate a {@link android.telephony.CallQuality} report from + * telephony to Telecom for relaying to + * {@link DiagnosticCall#onCallQualityReceived(CallQuality)}. + * @hide + */ + public static final String EVENT_CALL_QUALITY_REPORT = + "android.telecom.event.CALL_QUALITY_REPORT"; + + /** + * Extra sent with {@link #EVENT_CALL_QUALITY_REPORT} containing the + * {@link android.telephony.CallQuality} data. + * @hide + */ + public static final String EXTRA_CALL_QUALITY_REPORT = + "android.telecom.extra.CALL_QUALITY_REPORT"; + // Flag controlling whether PII is emitted into the logs private static final boolean PII_DEBUG = Log.isLoggable(android.util.Log.DEBUG); diff --git a/telecomm/java/com/android/internal/telecom/ICallDiagnosticService.aidl b/telecomm/java/com/android/internal/telecom/ICallDiagnosticService.aidl index fc9879aaf0a8..4bd369f2c556 100644 --- a/telecomm/java/com/android/internal/telecom/ICallDiagnosticService.aidl +++ b/telecomm/java/com/android/internal/telecom/ICallDiagnosticService.aidl @@ -20,6 +20,7 @@ import android.telecom.BluetoothCallQualityReport; import android.telecom.CallAudioState; import android.telecom.DisconnectCause; import android.telecom.ParcelableCall; +import android.telephony.CallQuality; import com.android.internal.telecom.ICallDiagnosticServiceAdapter; /** @@ -34,6 +35,7 @@ oneway interface ICallDiagnosticService { void updateCallAudioState(in CallAudioState callAudioState); void removeDiagnosticCall(in String callId); void receiveDeviceToDeviceMessage(in String callId, int message, int value); + void callQualityChanged(in String callId, in CallQuality callQuality); void receiveBluetoothCallQualityReport(in BluetoothCallQualityReport qualityReport); void notifyCallDisconnected(in String callId, in DisconnectCause disconnectCause); } diff --git a/telephony/java/android/telephony/SmsManager.java b/telephony/java/android/telephony/SmsManager.java index 4926687f6724..17af4638c874 100644 --- a/telephony/java/android/telephony/SmsManager.java +++ b/telephony/java/android/telephony/SmsManager.java @@ -19,6 +19,7 @@ package android.telephony; import android.Manifest; import android.annotation.CallbackExecutor; import android.annotation.IntDef; +import android.annotation.IntRange; import android.annotation.NonNull; import android.annotation.Nullable; import android.annotation.RequiresPermission; @@ -2207,7 +2208,9 @@ public final class SmsManager { * * @return the total number of SMS records which can be stored on the SIM card. */ - @RequiresPermission(android.Manifest.permission.READ_PHONE_STATE) + @RequiresPermission(anyOf = {android.Manifest.permission.READ_PHONE_STATE, + android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE}) + @IntRange(from = 0) public int getSmsCapacityOnIcc() { int ret = 0; try { |