summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--core/java/android/app/Notification.java5
-rw-r--r--core/java/android/app/admin/DevicePolicyManager.java14
-rw-r--r--core/java/android/app/admin/DevicePolicyResources.java11
-rw-r--r--core/java/android/app/admin/IDevicePolicyManager.aidl2
-rw-r--r--core/java/android/companion/virtual/VirtualDeviceManager.java11
-rw-r--r--core/java/android/credentials/CredentialManager.java12
-rw-r--r--core/java/android/credentials/ICredentialManager.aidl2
-rw-r--r--core/java/android/hardware/display/DisplayManager.java6
-rw-r--r--core/java/android/service/notification/ZenModeConfig.java5
-rw-r--r--core/java/android/view/ViewRootImpl.java419
-rw-r--r--core/java/android/view/WindowManager.java36
-rw-r--r--core/java/android/window/ScreenCapture.java2
-rw-r--r--core/java/com/android/internal/app/IntentForwarderActivity.java12
-rw-r--r--core/java/com/android/internal/app/ResolverActivity.java36
-rw-r--r--core/java/com/android/internal/widget/MessagingImageMessage.java5
-rw-r--r--core/res/res/drawable-hdpi/pointer_copy.pngbin1543 -> 1641 bytes
-rw-r--r--core/res/res/drawable-hdpi/pointer_grab.pngbin971 -> 1014 bytes
-rw-r--r--core/res/res/drawable-hdpi/pointer_grabbing.pngbin847 -> 886 bytes
-rw-r--r--core/res/res/drawable-hdpi/pointer_hand.pngbin954 -> 1014 bytes
-rw-r--r--core/res/res/drawable-hdpi/pointer_nodrop.pngbin1719 -> 1662 bytes
-rw-r--r--core/res/res/drawable-mdpi/pointer_copy.pngbin932 -> 920 bytes
-rw-r--r--core/res/res/drawable-mdpi/pointer_copy_large.pngbin3183 -> 3217 bytes
-rw-r--r--core/res/res/drawable-mdpi/pointer_grab.pngbin546 -> 580 bytes
-rw-r--r--core/res/res/drawable-mdpi/pointer_grab_large.pngbin2001 -> 2010 bytes
-rw-r--r--core/res/res/drawable-mdpi/pointer_grabbing.pngbin471 -> 521 bytes
-rw-r--r--core/res/res/drawable-mdpi/pointer_grabbing_large.pngbin1760 -> 1826 bytes
-rw-r--r--core/res/res/drawable-mdpi/pointer_hand.pngbin519 -> 561 bytes
-rw-r--r--core/res/res/drawable-mdpi/pointer_hand_large.pngbin2020 -> 2015 bytes
-rw-r--r--core/res/res/drawable-mdpi/pointer_nodrop.pngbin994 -> 943 bytes
-rw-r--r--core/res/res/drawable-mdpi/pointer_nodrop_large.pngbin3520 -> 3270 bytes
-rw-r--r--core/res/res/drawable-xhdpi/pointer_copy.pngbin2262 -> 2376 bytes
-rw-r--r--core/res/res/drawable-xhdpi/pointer_copy_large.pngbin8043 -> 8457 bytes
-rw-r--r--core/res/res/drawable-xhdpi/pointer_grab.pngbin1412 -> 1483 bytes
-rw-r--r--core/res/res/drawable-xhdpi/pointer_grab_large.pngbin5624 -> 5838 bytes
-rw-r--r--core/res/res/drawable-xhdpi/pointer_grabbing.pngbin1217 -> 1292 bytes
-rw-r--r--core/res/res/drawable-xhdpi/pointer_grabbing_large.pngbin4914 -> 5094 bytes
-rw-r--r--core/res/res/drawable-xhdpi/pointer_hand.pngbin1390 -> 1437 bytes
-rw-r--r--core/res/res/drawable-xhdpi/pointer_hand_large.pngbin5654 -> 5852 bytes
-rw-r--r--core/res/res/drawable-xhdpi/pointer_nodrop.pngbin2486 -> 2377 bytes
-rw-r--r--core/res/res/drawable-xhdpi/pointer_nodrop_large.pngbin8899 -> 8612 bytes
-rw-r--r--core/res/res/drawable-xxhdpi/pointer_copy.pngbin3886 -> 4169 bytes
-rw-r--r--core/res/res/drawable-xxhdpi/pointer_grab.pngbin2623 -> 2709 bytes
-rw-r--r--core/res/res/drawable-xxhdpi/pointer_grabbing.pngbin2252 -> 2355 bytes
-rw-r--r--core/res/res/drawable-xxhdpi/pointer_hand.pngbin2555 -> 2692 bytes
-rw-r--r--core/res/res/drawable-xxhdpi/pointer_nodrop.pngbin4356 -> 4156 bytes
-rw-r--r--core/res/res/drawable/pointer_copy_icon.xml2
-rw-r--r--core/res/res/drawable/pointer_copy_large_icon.xml4
-rw-r--r--core/res/res/drawable/pointer_grab_icon.xml4
-rw-r--r--core/res/res/drawable/pointer_grab_large_icon.xml4
-rw-r--r--core/res/res/drawable/pointer_grabbing_large_icon.xml4
-rw-r--r--core/res/res/drawable/pointer_hand_icon.xml2
-rw-r--r--core/res/res/drawable/pointer_hand_large_icon.xml2
-rw-r--r--core/res/res/drawable/pointer_nodrop_icon.xml2
-rw-r--r--core/res/res/drawable/pointer_nodrop_large_icon.xml4
-rw-r--r--core/res/res/values/config.xml3
-rw-r--r--core/res/res/values/symbols.xml2
-rw-r--r--core/tests/coretests/src/android/provider/DeviceConfigServiceManagerTest.java73
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/kidsmode/KidsModeTaskOrganizer.java8
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipBoundsAlgorithm.java2
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipTaskOrganizer.java11
-rw-r--r--libs/hwui/Android.bp4
-rw-r--r--libs/hwui/pipeline/skia/SkiaPipeline.cpp28
-rw-r--r--libs/hwui/pipeline/skia/SkiaPipeline.h2
-rw-r--r--libs/hwui/pipeline/skia/SkiaVulkanPipeline.cpp5
-rw-r--r--libs/hwui/pipeline/skia/SkiaVulkanPipeline.h2
-rw-r--r--libs/hwui/renderthread/VulkanSurface.cpp10
-rw-r--r--libs/hwui/renderthread/VulkanSurface.h2
-rw-r--r--media/java/android/media/IAudioService.aidl2
-rw-r--r--media/jni/android_media_MediaCodec.cpp263
-rw-r--r--media/jni/android_media_MediaCodec.h2
-rw-r--r--packages/CredentialManager/src/com/android/credentialmanager/CredentialSelectorActivity.kt3
-rw-r--r--packages/CredentialManager/src/com/android/credentialmanager/common/ui/BottomSheet.kt7
-rw-r--r--packages/CredentialManager/src/com/android/credentialmanager/common/ui/SnackBar.kt3
-rw-r--r--packages/CredentialManager/src/com/android/credentialmanager/createflow/CreateCredentialComponents.kt4
-rw-r--r--packages/CredentialManager/src/com/android/credentialmanager/getflow/GetCredentialComponents.kt7
-rw-r--r--packages/SettingsProvider/src/com/android/providers/settings/SettingsProvider.java37
-rw-r--r--packages/SettingsProvider/src/com/android/providers/settings/WritableNamespacePrefixes.java3
-rw-r--r--packages/SystemUI/src/com/android/systemui/flags/Flags.kt2
-rw-r--r--packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java4
-rw-r--r--packages/SystemUI/src/com/android/systemui/media/controls/ui/KeyguardMediaController.kt20
-rw-r--r--packages/SystemUI/src/com/android/systemui/media/dialog/MediaOutputAdapter.java18
-rw-r--r--packages/SystemUI/src/com/android/systemui/media/dialog/MediaOutputBaseAdapter.java4
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/ui/viewmodel/MobileIconViewModel.kt5
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/controls/management/ControlsFavoritingActivityTest.kt16
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/media/controls/ui/KeyguardMediaControllerTest.kt39
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/media/dialog/MediaOutputAdapterTest.java2
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/ui/viewmodel/MobileIconViewModelTest.kt18
-rw-r--r--services/companion/java/com/android/server/companion/virtual/VirtualDeviceImpl.java9
-rw-r--r--services/companion/java/com/android/server/companion/virtual/VirtualDeviceManagerService.java70
-rw-r--r--services/core/java/com/android/server/display/AutomaticBrightnessController.java180
-rw-r--r--services/core/java/com/android/server/display/BrightnessMappingStrategy.java6
-rw-r--r--services/core/java/com/android/server/display/BrightnessThrottler.java171
-rw-r--r--services/core/java/com/android/server/display/DisplayDeviceConfig.java56
-rw-r--r--services/core/java/com/android/server/display/DisplayPowerController.java20
-rw-r--r--services/core/java/com/android/server/display/DisplayPowerController2.java18
-rw-r--r--services/core/java/com/android/server/display/layout/Layout.java4
-rwxr-xr-xservices/core/java/com/android/server/notification/NotificationManagerService.java23
-rw-r--r--services/core/java/com/android/server/wm/ActivityRecord.java4
-rw-r--r--services/core/java/com/android/server/wm/BackgroundActivityStartController.java2
-rw-r--r--services/core/java/com/android/server/wm/DisplayArea.java9
-rw-r--r--services/core/java/com/android/server/wm/DisplayContent.java6
-rw-r--r--services/core/java/com/android/server/wm/EmbeddedWindowController.java4
-rw-r--r--services/core/java/com/android/server/wm/LetterboxUiController.java48
-rw-r--r--services/core/java/com/android/server/wm/TaskDisplayArea.java2
-rw-r--r--services/core/java/com/android/server/wm/Transition.java33
-rw-r--r--services/core/java/com/android/server/wm/WindowState.java13
-rw-r--r--services/credentials/java/com/android/server/credentials/ClearRequestSession.java6
-rw-r--r--services/credentials/java/com/android/server/credentials/CreateRequestSession.java8
-rw-r--r--services/credentials/java/com/android/server/credentials/CredentialManagerService.java83
-rw-r--r--services/credentials/java/com/android/server/credentials/CredentialManagerUi.java31
-rw-r--r--services/credentials/java/com/android/server/credentials/GetRequestSession.java9
-rw-r--r--services/credentials/java/com/android/server/credentials/PrepareGetRequestSession.java15
-rw-r--r--services/credentials/java/com/android/server/credentials/ProviderClearSession.java3
-rw-r--r--services/credentials/java/com/android/server/credentials/ProviderCreateSession.java3
-rw-r--r--services/credentials/java/com/android/server/credentials/ProviderGetSession.java4
-rw-r--r--services/credentials/java/com/android/server/credentials/ProviderSession.java3
-rw-r--r--services/credentials/java/com/android/server/credentials/RequestSession.java57
-rw-r--r--services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java710
-rw-r--r--services/tests/servicestests/src/com/android/server/display/AutomaticBrightnessControllerTest.java180
-rw-r--r--services/tests/servicestests/src/com/android/server/display/BrightnessThrottlerTest.java60
-rw-r--r--services/tests/servicestests/src/com/android/server/display/DisplayDeviceConfigTest.java64
-rwxr-xr-xservices/tests/uiservicestests/src/com/android/server/notification/NotificationManagerServiceTest.java10
-rw-r--r--services/tests/uiservicestests/src/com/android/server/notification/ZenModeConfigTest.java12
-rw-r--r--services/tests/wmtests/src/com/android/server/wm/LetterboxUiControllerTest.java38
-rw-r--r--services/tests/wmtests/src/com/android/server/wm/SizeCompatTests.java2
125 files changed, 2085 insertions, 1108 deletions
diff --git a/core/java/android/app/Notification.java b/core/java/android/app/Notification.java
index 7aedd30d660e..96d785f0df9c 100644
--- a/core/java/android/app/Notification.java
+++ b/core/java/android/app/Notification.java
@@ -4067,8 +4067,9 @@ public class Notification implements Parcelable
* notification if alerts for this notification's group should be handled by a different
* notification. This is only applicable for notifications that belong to a
* {@link #setGroup(String) group}. This must be called on all notifications you want to
- * mute. For example, if you want only the summary of your group to make noise, all
- * children in the group should have the group alert behavior {@link #GROUP_ALERT_SUMMARY}.
+ * mute. For example, if you want only the summary of your group to make noise and/or peek
+ * on screen, all children in the group should have the group alert behavior
+ * {@link #GROUP_ALERT_SUMMARY}.
*
* <p> The default value is {@link #GROUP_ALERT_ALL}.</p>
*/
diff --git a/core/java/android/app/admin/DevicePolicyManager.java b/core/java/android/app/admin/DevicePolicyManager.java
index bad6c77a17f3..7dabe60e3ba8 100644
--- a/core/java/android/app/admin/DevicePolicyManager.java
+++ b/core/java/android/app/admin/DevicePolicyManager.java
@@ -6413,7 +6413,7 @@ public class DevicePolicyManager {
public void lockNow(@LockNowFlag int flags) {
if (mService != null) {
try {
- mService.lockNow(flags, mParentInstance);
+ mService.lockNow(flags, mContext.getPackageName(), mParentInstance);
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
@@ -13646,8 +13646,8 @@ public class DevicePolicyManager {
* privacy-sensitive events happening outside the managed profile would have been redacted
* already.
*
- * @param admin Which device admin this request is associated with. Null if the caller is not
- * a device admin
+ * @param admin Which device admin this request is associated with, or {@code null}
+ * if called by a delegated app.
* @param enabled whether security logging should be enabled or not.
* @throws SecurityException if the caller is not permitted to control security logging.
* @see #setAffiliationIds
@@ -13699,8 +13699,8 @@ public class DevicePolicyManager {
* it must be affiliated with the device. Otherwise a {@link SecurityException} will be thrown.
* See {@link #isAffiliatedUser}.
*
- * @param admin Which device admin this request is associated with. Null if the caller is not
- * a device admin.
+ * @param admin Which device admin this request is associated with, or {@code null}
+ * if called by a delegated app.
* @return the new batch of security logs which is a list of {@link SecurityEvent},
* or {@code null} if rate limitation is exceeded or if logging is currently disabled.
* @throws SecurityException if the caller is not allowed to access security logging,
@@ -13857,8 +13857,8 @@ public class DevicePolicyManager {
* it must be affiliated with the device. Otherwise a {@link SecurityException} will be thrown.
* See {@link #isAffiliatedUser}.
*
- * @param admin Which device admin this request is associated with. Null if the caller is not
- * a device admin.
+ * @param admin Which device admin this request is associated with, or {@code null}
+ * if called by a delegated app.
* @return Device logs from before the latest reboot of the system, or {@code null} if this API
* is not supported on the device.
* @throws SecurityException if the caller is not allowed to access security logging, or
diff --git a/core/java/android/app/admin/DevicePolicyResources.java b/core/java/android/app/admin/DevicePolicyResources.java
index a49891356ccd..593f73635617 100644
--- a/core/java/android/app/admin/DevicePolicyResources.java
+++ b/core/java/android/app/admin/DevicePolicyResources.java
@@ -1857,6 +1857,17 @@ public final class DevicePolicyResources {
public static final String WORK_PROFILE_TELEPHONY_PAUSED_TURN_ON_BUTTON =
PREFIX + "TURN_ON_WORK_PROFILE_BUTTON_TEXT";
+ public static final String MINIRESOLVER_OPEN_IN_WORK =
+ PREFIX + "MINIRESOLVER_OPEN_IN_WORK";
+
+ public static final String MINIRESOLVER_OPEN_IN_PERSONAL =
+ PREFIX + "MINIRESOLVER_OPEN_IN_PERSONAL";
+
+ public static final String MINIRESOLVER_USE_WORK_BROWSER =
+ PREFIX + "MINIRESOLVER_OPEN_IN_PERSONAL";
+
+ public static final String MINIRESOLVER_USE_PERSONAL_BROWSER =
+ PREFIX + "MINIRESOLVER_OPEN_IN_PERSONAL";
}
/**
diff --git a/core/java/android/app/admin/IDevicePolicyManager.aidl b/core/java/android/app/admin/IDevicePolicyManager.aidl
index 8d508c0fb79d..9b0b18ac74ec 100644
--- a/core/java/android/app/admin/IDevicePolicyManager.aidl
+++ b/core/java/android/app/admin/IDevicePolicyManager.aidl
@@ -119,7 +119,7 @@ interface IDevicePolicyManager {
void setRequiredStrongAuthTimeout(in ComponentName who, String callerPackageName, long timeMs, boolean parent);
long getRequiredStrongAuthTimeout(in ComponentName who, int userId, boolean parent);
- void lockNow(int flags, boolean parent);
+ void lockNow(int flags, String callerPackageName, boolean parent);
/**
* @param factoryReset only applicable when `targetSdk >= U`, either tries to factoryReset/fail or removeUser/fail otherwise
diff --git a/core/java/android/companion/virtual/VirtualDeviceManager.java b/core/java/android/companion/virtual/VirtualDeviceManager.java
index da6784be4404..2ca2b79bcc08 100644
--- a/core/java/android/companion/virtual/VirtualDeviceManager.java
+++ b/core/java/android/companion/virtual/VirtualDeviceManager.java
@@ -64,6 +64,7 @@ import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
import java.util.ArrayList;
import java.util.List;
+import java.util.Objects;
import java.util.concurrent.Executor;
import java.util.function.IntConsumer;
@@ -171,6 +172,7 @@ public final class VirtualDeviceManager {
public VirtualDevice createVirtualDevice(
int associationId,
@NonNull VirtualDeviceParams params) {
+ Objects.requireNonNull(params, "params must not be null");
try {
return new VirtualDevice(mService, mContext, associationId, params);
} catch (RemoteException e) {
@@ -409,6 +411,9 @@ public final class VirtualDeviceManager {
@NonNull PendingIntent pendingIntent,
@NonNull Executor executor,
@NonNull IntConsumer listener) {
+ Objects.requireNonNull(pendingIntent, "pendingIntent must not be null");
+ Objects.requireNonNull(executor, "executor must not be null");
+ Objects.requireNonNull(listener, "listener must not be null");
mVirtualDeviceInternal.launchPendingIntent(
displayId, pendingIntent, executor, listener);
}
@@ -483,6 +488,7 @@ public final class VirtualDeviceManager {
@NonNull VirtualDisplayConfig config,
@Nullable @CallbackExecutor Executor executor,
@Nullable VirtualDisplay.Callback callback) {
+ Objects.requireNonNull(config, "config must not be null");
return mVirtualDeviceInternal.createVirtualDisplay(config, executor, callback);
}
@@ -503,6 +509,7 @@ public final class VirtualDeviceManager {
@RequiresPermission(android.Manifest.permission.CREATE_VIRTUAL_DEVICE)
@NonNull
public VirtualDpad createVirtualDpad(@NonNull VirtualDpadConfig config) {
+ Objects.requireNonNull(config, "config must not be null");
return mVirtualDeviceInternal.createVirtualDpad(config);
}
@@ -514,6 +521,7 @@ public final class VirtualDeviceManager {
@RequiresPermission(android.Manifest.permission.CREATE_VIRTUAL_DEVICE)
@NonNull
public VirtualKeyboard createVirtualKeyboard(@NonNull VirtualKeyboardConfig config) {
+ Objects.requireNonNull(config, "config must not be null");
return mVirtualDeviceInternal.createVirtualKeyboard(config);
}
@@ -550,6 +558,7 @@ public final class VirtualDeviceManager {
@RequiresPermission(android.Manifest.permission.CREATE_VIRTUAL_DEVICE)
@NonNull
public VirtualMouse createVirtualMouse(@NonNull VirtualMouseConfig config) {
+ Objects.requireNonNull(config, "config must not be null");
return mVirtualDeviceInternal.createVirtualMouse(config);
}
@@ -587,6 +596,7 @@ public final class VirtualDeviceManager {
@NonNull
public VirtualTouchscreen createVirtualTouchscreen(
@NonNull VirtualTouchscreenConfig config) {
+ Objects.requireNonNull(config, "config must not be null");
return mVirtualDeviceInternal.createVirtualTouchscreen(config);
}
@@ -659,6 +669,7 @@ public final class VirtualDeviceManager {
@NonNull VirtualDisplay display,
@Nullable Executor executor,
@Nullable AudioConfigurationChangeCallback callback) {
+ Objects.requireNonNull(display, "display must not be null");
return mVirtualDeviceInternal.createVirtualAudioDevice(display, executor, callback);
}
diff --git a/core/java/android/credentials/CredentialManager.java b/core/java/android/credentials/CredentialManager.java
index 00ce17adfda6..9140d02e223d 100644
--- a/core/java/android/credentials/CredentialManager.java
+++ b/core/java/android/credentials/CredentialManager.java
@@ -460,9 +460,17 @@ public final class CredentialManager {
return false;
}
+ /**
+ * Returns whether the service is enabled.
+ *
+ * @hide
+ */
private boolean isServiceEnabled() {
- return DeviceConfig.getBoolean(
- DeviceConfig.NAMESPACE_CREDENTIAL, DEVICE_CONFIG_ENABLE_CREDENTIAL_MANAGER, true);
+ try {
+ return mService.isServiceEnabled();
+ } catch (RemoteException e) {
+ return false;
+ }
}
/**
diff --git a/core/java/android/credentials/ICredentialManager.aidl b/core/java/android/credentials/ICredentialManager.aidl
index 5fde96b0b9ff..b779c56035d3 100644
--- a/core/java/android/credentials/ICredentialManager.aidl
+++ b/core/java/android/credentials/ICredentialManager.aidl
@@ -58,5 +58,7 @@ interface ICredentialManager {
List<CredentialProviderInfo> getCredentialProviderServices(in int userId, in int providerFilter);
List<CredentialProviderInfo> getCredentialProviderServicesForTesting(in int providerFilter);
+
+ boolean isServiceEnabled();
}
diff --git a/core/java/android/hardware/display/DisplayManager.java b/core/java/android/hardware/display/DisplayManager.java
index b5281a5025b8..2aead3c22deb 100644
--- a/core/java/android/hardware/display/DisplayManager.java
+++ b/core/java/android/hardware/display/DisplayManager.java
@@ -1758,10 +1758,12 @@ public final class DisplayManager {
/**
* Key for the brightness throttling data as a String formatted:
* <displayId>,<no of throttling levels>,[<severity as string>,<brightness cap>]
- * Where the latter part is repeated for each throttling level, and the entirety is repeated
- * for each display, separated by a semicolon.
+ * [,<throttlingId>]?
+ * Where [<severity as string>,<brightness cap>] is repeated for each throttling level.
+ * The entirety is repeated for each display and throttling id, separated by a semicolon.
* For example:
* 123,1,critical,0.8;456,2,moderate,0.9,critical,0.7
+ * 123,1,critical,0.8,default;123,1,moderate,0.6,id_2;456,2,moderate,0.9,critical,0.7
*/
String KEY_BRIGHTNESS_THROTTLING_DATA = "brightness_throttling_data";
}
diff --git a/core/java/android/service/notification/ZenModeConfig.java b/core/java/android/service/notification/ZenModeConfig.java
index 5c2b38963005..402da28b3c5c 100644
--- a/core/java/android/service/notification/ZenModeConfig.java
+++ b/core/java/android/service/notification/ZenModeConfig.java
@@ -1008,9 +1008,8 @@ public class ZenModeConfig implements Parcelable {
.allowAlarms(allowAlarms)
.allowMedia(allowMedia)
.allowSystem(allowSystem)
- .allowConversations(allowConversations
- ? ZenModeConfig.getZenPolicySenders(allowConversationsFrom)
- : ZenPolicy.PEOPLE_TYPE_NONE);
+ .allowConversations(allowConversations ? allowConversationsFrom
+ : ZenPolicy.CONVERSATION_SENDERS_NONE);
if (suppressedVisualEffects == 0) {
builder.showAllVisualEffects();
} else {
diff --git a/core/java/android/view/ViewRootImpl.java b/core/java/android/view/ViewRootImpl.java
index c30b5953adce..2f5cd5434b89 100644
--- a/core/java/android/view/ViewRootImpl.java
+++ b/core/java/android/view/ViewRootImpl.java
@@ -265,6 +265,7 @@ public final class ViewRootImpl implements ViewParent,
private static final boolean DEBUG_KEEP_SCREEN_ON = false || LOCAL_LOGV;
private static final boolean DEBUG_CONTENT_CAPTURE = false || LOCAL_LOGV;
private static final boolean DEBUG_SCROLL_CAPTURE = false || LOCAL_LOGV;
+ private static final boolean DEBUG_TOUCH_NAVIGATION = false || LOCAL_LOGV;
private static final boolean DEBUG_BLAST = false || LOCAL_LOGV;
private static final int LOGTAG_INPUT_FOCUS = 62001;
@@ -7122,7 +7123,8 @@ public final class ViewRootImpl implements ViewParent,
mJoystick.cancel();
} else if ((source & InputDevice.SOURCE_TOUCH_NAVIGATION)
== InputDevice.SOURCE_TOUCH_NAVIGATION) {
- mTouchNavigation.cancel(event);
+ // Touch navigation events cannot be cancelled since they are dispatched
+ // immediately.
}
}
}
@@ -7641,392 +7643,109 @@ public final class ViewRootImpl implements ViewParent,
}
/**
- * Creates dpad events from unhandled touch navigation movements.
+ * Creates DPAD events from unhandled touch navigation movements.
*/
final class SyntheticTouchNavigationHandler extends Handler {
private static final String LOCAL_TAG = "SyntheticTouchNavigationHandler";
- private static final boolean LOCAL_DEBUG = false;
-
- // Assumed nominal width and height in millimeters of a touch navigation pad,
- // if no resolution information is available from the input system.
- private static final float DEFAULT_WIDTH_MILLIMETERS = 48;
- private static final float DEFAULT_HEIGHT_MILLIMETERS = 48;
-
- /* TODO: These constants should eventually be moved to ViewConfiguration. */
-
- // The nominal distance traveled to move by one unit.
- private static final int TICK_DISTANCE_MILLIMETERS = 12;
-
- // Minimum and maximum fling velocity in ticks per second.
- // The minimum velocity should be set such that we perform enough ticks per
- // second that the fling appears to be fluid. For example, if we set the minimum
- // to 2 ticks per second, then there may be up to half a second delay between the next
- // to last and last ticks which is noticeably discrete and jerky. This value should
- // probably not be set to anything less than about 4.
- // If fling accuracy is a problem then consider tuning the tick distance instead.
- private static final float MIN_FLING_VELOCITY_TICKS_PER_SECOND = 6f;
- private static final float MAX_FLING_VELOCITY_TICKS_PER_SECOND = 20f;
-
- // Fling velocity decay factor applied after each new key is emitted.
- // This parameter controls the deceleration and overall duration of the fling.
- // The fling stops automatically when its velocity drops below the minimum
- // fling velocity defined above.
- private static final float FLING_TICK_DECAY = 0.8f;
-
- /* The input device that we are tracking. */
+ // The id of the input device that is being tracked.
private int mCurrentDeviceId = -1;
private int mCurrentSource;
- private boolean mCurrentDeviceSupported;
-
- /* Configuration for the current input device. */
- // The scaled tick distance. A movement of this amount should generally translate
- // into a single dpad event in a given direction.
- private float mConfigTickDistance;
-
- // The minimum and maximum scaled fling velocity.
- private float mConfigMinFlingVelocity;
- private float mConfigMaxFlingVelocity;
-
- /* Tracking state. */
-
- // The velocity tracker for detecting flings.
- private VelocityTracker mVelocityTracker;
+ private int mPendingKeyMetaState;
- // The active pointer id, or -1 if none.
- private int mActivePointerId = -1;
+ private final GestureDetector mGestureDetector = new GestureDetector(mContext,
+ new GestureDetector.OnGestureListener() {
+ @Override
+ public boolean onDown(@NonNull MotionEvent e) {
+ // This can be ignored since it's not clear what KeyEvent this will
+ // belong to.
+ return true;
+ }
- // Location where tracking started.
- private float mStartX;
- private float mStartY;
+ @Override
+ public void onShowPress(@NonNull MotionEvent e) {
- // Most recently observed position.
- private float mLastX;
- private float mLastY;
+ }
- // Accumulated movement delta since the last direction key was sent.
- private float mAccumulatedX;
- private float mAccumulatedY;
+ @Override
+ public boolean onSingleTapUp(@NonNull MotionEvent e) {
+ dispatchTap(e.getEventTime());
+ return true;
+ }
- // Set to true if any movement was delivered to the app.
- // Implies that tap slop was exceeded.
- private boolean mConsumedMovement;
+ @Override
+ public boolean onScroll(@Nullable MotionEvent e1, @NonNull MotionEvent e2,
+ float distanceX, float distanceY) {
+ // Scroll doesn't translate to DPAD events so should be ignored.
+ return true;
+ }
- // The most recently sent key down event.
- // The keycode remains set until the direction changes or a fling ends
- // so that repeated key events may be generated as required.
- private long mPendingKeyDownTime;
- private int mPendingKeyCode = KeyEvent.KEYCODE_UNKNOWN;
- private int mPendingKeyRepeatCount;
- private int mPendingKeyMetaState;
+ @Override
+ public void onLongPress(@NonNull MotionEvent e) {
+ // Long presses don't translate to DPAD events so should be ignored.
+ }
- // The current fling velocity while a fling is in progress.
- private boolean mFlinging;
- private float mFlingVelocity;
+ @Override
+ public boolean onFling(@Nullable MotionEvent e1, @NonNull MotionEvent e2,
+ float velocityX, float velocityY) {
+ dispatchFling(velocityX, velocityY, e2.getEventTime());
+ return true;
+ }
+ });
- public SyntheticTouchNavigationHandler() {
+ SyntheticTouchNavigationHandler() {
super(true);
}
public void process(MotionEvent event) {
+ if (event.getDevice() == null) {
+ // The current device is not supported.
+ if (DEBUG_TOUCH_NAVIGATION) {
+ Log.d(LOCAL_TAG,
+ "Current device not supported so motion event is not processed");
+ }
+ return;
+ }
+ mPendingKeyMetaState = event.getMetaState();
// Update the current device information.
- final long time = event.getEventTime();
final int deviceId = event.getDeviceId();
final int source = event.getSource();
if (mCurrentDeviceId != deviceId || mCurrentSource != source) {
- finishKeys(time);
- finishTracking(time);
mCurrentDeviceId = deviceId;
mCurrentSource = source;
- mCurrentDeviceSupported = false;
- InputDevice device = event.getDevice();
- if (device != null) {
- // In order to support an input device, we must know certain
- // characteristics about it, such as its size and resolution.
- InputDevice.MotionRange xRange = device.getMotionRange(MotionEvent.AXIS_X);
- InputDevice.MotionRange yRange = device.getMotionRange(MotionEvent.AXIS_Y);
- if (xRange != null && yRange != null) {
- mCurrentDeviceSupported = true;
-
- // Infer the resolution if it not actually known.
- float xRes = xRange.getResolution();
- if (xRes <= 0) {
- xRes = xRange.getRange() / DEFAULT_WIDTH_MILLIMETERS;
- }
- float yRes = yRange.getResolution();
- if (yRes <= 0) {
- yRes = yRange.getRange() / DEFAULT_HEIGHT_MILLIMETERS;
- }
- float nominalRes = (xRes + yRes) * 0.5f;
-
- // Precompute all of the configuration thresholds we will need.
- mConfigTickDistance = TICK_DISTANCE_MILLIMETERS * nominalRes;
- mConfigMinFlingVelocity =
- MIN_FLING_VELOCITY_TICKS_PER_SECOND * mConfigTickDistance;
- mConfigMaxFlingVelocity =
- MAX_FLING_VELOCITY_TICKS_PER_SECOND * mConfigTickDistance;
-
- if (LOCAL_DEBUG) {
- Log.d(LOCAL_TAG, "Configured device " + mCurrentDeviceId
- + " (" + Integer.toHexString(mCurrentSource) + "): "
- + ", mConfigTickDistance=" + mConfigTickDistance
- + ", mConfigMinFlingVelocity=" + mConfigMinFlingVelocity
- + ", mConfigMaxFlingVelocity=" + mConfigMaxFlingVelocity);
- }
- }
- }
- }
- if (!mCurrentDeviceSupported) {
- return;
- }
-
- // Handle the event.
- final int action = event.getActionMasked();
- switch (action) {
- case MotionEvent.ACTION_DOWN: {
- boolean caughtFling = mFlinging;
- finishKeys(time);
- finishTracking(time);
- mActivePointerId = event.getPointerId(0);
- mVelocityTracker = VelocityTracker.obtain();
- mVelocityTracker.addMovement(event);
- mStartX = event.getX();
- mStartY = event.getY();
- mLastX = mStartX;
- mLastY = mStartY;
- mAccumulatedX = 0;
- mAccumulatedY = 0;
-
- // If we caught a fling, then pretend that the tap slop has already
- // been exceeded to suppress taps whose only purpose is to stop the fling.
- mConsumedMovement = caughtFling;
- break;
- }
-
- case MotionEvent.ACTION_MOVE:
- case MotionEvent.ACTION_UP: {
- if (mActivePointerId < 0) {
- break;
- }
- final int index = event.findPointerIndex(mActivePointerId);
- if (index < 0) {
- finishKeys(time);
- finishTracking(time);
- break;
- }
-
- mVelocityTracker.addMovement(event);
- final float x = event.getX(index);
- final float y = event.getY(index);
- mAccumulatedX += x - mLastX;
- mAccumulatedY += y - mLastY;
- mLastX = x;
- mLastY = y;
-
- // Consume any accumulated movement so far.
- final int metaState = event.getMetaState();
- consumeAccumulatedMovement(time, metaState);
-
- // Detect taps and flings.
- if (action == MotionEvent.ACTION_UP) {
- if (mConsumedMovement && mPendingKeyCode != KeyEvent.KEYCODE_UNKNOWN) {
- // It might be a fling.
- mVelocityTracker.computeCurrentVelocity(1000, mConfigMaxFlingVelocity);
- final float vx = mVelocityTracker.getXVelocity(mActivePointerId);
- final float vy = mVelocityTracker.getYVelocity(mActivePointerId);
- if (!startFling(time, vx, vy)) {
- finishKeys(time);
- }
- }
- finishTracking(time);
- }
- break;
- }
-
- case MotionEvent.ACTION_CANCEL: {
- finishKeys(time);
- finishTracking(time);
- break;
- }
- }
- }
-
- public void cancel(MotionEvent event) {
- if (mCurrentDeviceId == event.getDeviceId()
- && mCurrentSource == event.getSource()) {
- final long time = event.getEventTime();
- finishKeys(time);
- finishTracking(time);
}
- }
-
- private void finishKeys(long time) {
- cancelFling();
- sendKeyUp(time);
- }
-
- private void finishTracking(long time) {
- if (mActivePointerId >= 0) {
- mActivePointerId = -1;
- mVelocityTracker.recycle();
- mVelocityTracker = null;
- }
- }
- private void consumeAccumulatedMovement(long time, int metaState) {
- final float absX = Math.abs(mAccumulatedX);
- final float absY = Math.abs(mAccumulatedY);
- if (absX >= absY) {
- if (absX >= mConfigTickDistance) {
- mAccumulatedX = consumeAccumulatedMovement(time, metaState, mAccumulatedX,
- KeyEvent.KEYCODE_DPAD_LEFT, KeyEvent.KEYCODE_DPAD_RIGHT);
- mAccumulatedY = 0;
- mConsumedMovement = true;
- }
- } else {
- if (absY >= mConfigTickDistance) {
- mAccumulatedY = consumeAccumulatedMovement(time, metaState, mAccumulatedY,
- KeyEvent.KEYCODE_DPAD_UP, KeyEvent.KEYCODE_DPAD_DOWN);
- mAccumulatedX = 0;
- mConsumedMovement = true;
- }
- }
+ // Interpret the event.
+ mGestureDetector.onTouchEvent(event);
}
- private float consumeAccumulatedMovement(long time, int metaState,
- float accumulator, int negativeKeyCode, int positiveKeyCode) {
- while (accumulator <= -mConfigTickDistance) {
- sendKeyDownOrRepeat(time, negativeKeyCode, metaState);
- accumulator += mConfigTickDistance;
- }
- while (accumulator >= mConfigTickDistance) {
- sendKeyDownOrRepeat(time, positiveKeyCode, metaState);
- accumulator -= mConfigTickDistance;
- }
- return accumulator;
+ private void dispatchTap(long time) {
+ dispatchEvent(time, KeyEvent.KEYCODE_DPAD_CENTER);
}
- private void sendKeyDownOrRepeat(long time, int keyCode, int metaState) {
- if (mPendingKeyCode != keyCode) {
- sendKeyUp(time);
- mPendingKeyDownTime = time;
- mPendingKeyCode = keyCode;
- mPendingKeyRepeatCount = 0;
+ private void dispatchFling(float x, float y, long time) {
+ if (Math.abs(x) > Math.abs(y)) {
+ dispatchEvent(time,
+ x > 0 ? KeyEvent.KEYCODE_DPAD_RIGHT : KeyEvent.KEYCODE_DPAD_LEFT);
} else {
- mPendingKeyRepeatCount += 1;
- }
- mPendingKeyMetaState = metaState;
-
- // Note: Normally we would pass FLAG_LONG_PRESS when the repeat count is 1
- // but it doesn't quite make sense when simulating the events in this way.
- if (LOCAL_DEBUG) {
- Log.d(LOCAL_TAG, "Sending key down: keyCode=" + mPendingKeyCode
- + ", repeatCount=" + mPendingKeyRepeatCount
- + ", metaState=" + Integer.toHexString(mPendingKeyMetaState));
- }
- enqueueInputEvent(new KeyEvent(mPendingKeyDownTime, time,
- KeyEvent.ACTION_DOWN, mPendingKeyCode, mPendingKeyRepeatCount,
- mPendingKeyMetaState, mCurrentDeviceId,
- KeyEvent.FLAG_FALLBACK, mCurrentSource));
- }
-
- private void sendKeyUp(long time) {
- if (mPendingKeyCode != KeyEvent.KEYCODE_UNKNOWN) {
- if (LOCAL_DEBUG) {
- Log.d(LOCAL_TAG, "Sending key up: keyCode=" + mPendingKeyCode
- + ", metaState=" + Integer.toHexString(mPendingKeyMetaState));
- }
- enqueueInputEvent(new KeyEvent(mPendingKeyDownTime, time,
- KeyEvent.ACTION_UP, mPendingKeyCode, 0, mPendingKeyMetaState,
- mCurrentDeviceId, 0, KeyEvent.FLAG_FALLBACK,
- mCurrentSource));
- mPendingKeyCode = KeyEvent.KEYCODE_UNKNOWN;
- }
- }
-
- private boolean startFling(long time, float vx, float vy) {
- if (LOCAL_DEBUG) {
- Log.d(LOCAL_TAG, "Considering fling: vx=" + vx + ", vy=" + vy
- + ", min=" + mConfigMinFlingVelocity);
- }
-
- // Flings must be oriented in the same direction as the preceding movements.
- switch (mPendingKeyCode) {
- case KeyEvent.KEYCODE_DPAD_LEFT:
- if (-vx >= mConfigMinFlingVelocity
- && Math.abs(vy) < mConfigMinFlingVelocity) {
- mFlingVelocity = -vx;
- break;
- }
- return false;
-
- case KeyEvent.KEYCODE_DPAD_RIGHT:
- if (vx >= mConfigMinFlingVelocity
- && Math.abs(vy) < mConfigMinFlingVelocity) {
- mFlingVelocity = vx;
- break;
- }
- return false;
-
- case KeyEvent.KEYCODE_DPAD_UP:
- if (-vy >= mConfigMinFlingVelocity
- && Math.abs(vx) < mConfigMinFlingVelocity) {
- mFlingVelocity = -vy;
- break;
- }
- return false;
-
- case KeyEvent.KEYCODE_DPAD_DOWN:
- if (vy >= mConfigMinFlingVelocity
- && Math.abs(vx) < mConfigMinFlingVelocity) {
- mFlingVelocity = vy;
- break;
- }
- return false;
- }
-
- // Post the first fling event.
- mFlinging = postFling(time);
- return mFlinging;
- }
-
- private boolean postFling(long time) {
- // The idea here is to estimate the time when the pointer would have
- // traveled one tick distance unit given the current fling velocity.
- // This effect creates continuity of motion.
- if (mFlingVelocity >= mConfigMinFlingVelocity) {
- long delay = (long)(mConfigTickDistance / mFlingVelocity * 1000);
- postAtTime(mFlingRunnable, time + delay);
- if (LOCAL_DEBUG) {
- Log.d(LOCAL_TAG, "Posted fling: velocity="
- + mFlingVelocity + ", delay=" + delay
- + ", keyCode=" + mPendingKeyCode);
- }
- return true;
+ dispatchEvent(time, y > 0 ? KeyEvent.KEYCODE_DPAD_DOWN : KeyEvent.KEYCODE_DPAD_UP);
}
- return false;
}
- private void cancelFling() {
- if (mFlinging) {
- removeCallbacks(mFlingRunnable);
- mFlinging = false;
+ private void dispatchEvent(long time, int keyCode) {
+ if (DEBUG_TOUCH_NAVIGATION) {
+ Log.d(LOCAL_TAG, "Dispatching DPAD events DOWN and UP with keycode " + keyCode);
}
+ enqueueInputEvent(new KeyEvent(time, time,
+ KeyEvent.ACTION_DOWN, keyCode, /* repeat= */ 0, mPendingKeyMetaState,
+ mCurrentDeviceId, /* scancode= */ 0, KeyEvent.FLAG_FALLBACK,
+ mCurrentSource));
+ enqueueInputEvent(new KeyEvent(time, time,
+ KeyEvent.ACTION_UP, keyCode, /* repeat= */ 0, mPendingKeyMetaState,
+ mCurrentDeviceId, /* scancode= */ 0, KeyEvent.FLAG_FALLBACK,
+ mCurrentSource));
}
-
- private final Runnable mFlingRunnable = new Runnable() {
- @Override
- public void run() {
- final long time = SystemClock.uptimeMillis();
- sendKeyDownOrRepeat(time, mPendingKeyCode, mPendingKeyMetaState);
- mFlingVelocity *= FLING_TICK_DECAY;
- if (!postFling(time)) {
- mFlinging = false;
- finishKeys(time);
- }
- }
- };
}
final class SyntheticKeyboardHandler {
diff --git a/core/java/android/view/WindowManager.java b/core/java/android/view/WindowManager.java
index 48686fc25916..02b34786e9f2 100644
--- a/core/java/android/view/WindowManager.java
+++ b/core/java/android/view/WindowManager.java
@@ -869,6 +869,42 @@ public interface WindowManager extends ViewManager {
"android.window.PROPERTY_COMPAT_IGNORE_REQUESTED_ORIENTATION";
/**
+ * Application level {@link android.content.pm.PackageManager.Property PackageManager.Property}
+ * for an app to inform the system that the app can be opted-out from the compatibility
+ * treatment that avoids {@link android.app.Activity#setRequestedOrientation} loops. The loop
+ * can be trigerred by ignoreRequestedOrientation display setting enabled on the device or
+ * by the landscape natural orientation of the device.
+ *
+ * <p>The system could ignore {@link android.app.Activity#setRequestedOrientation}
+ * call from an app if both of the following conditions are true:
+ * <ul>
+ * <li>Activity has requested orientation more than 2 times within 1-second timer
+ * <li>Activity is not letterboxed for fixed orientation
+ * </ul>
+ *
+ * <p>Setting this property to {@code false} informs the system that the app must be
+ * opted-out from the compatibility treatment even if the device manufacturer has opted the app
+ * into the treatment.
+ *
+ * <p>Not setting this property at all, or setting this property to {@code true} has no effect.
+ *
+ * <p><b>Syntax:</b>
+ * <pre>
+ * &lt;application&gt;
+ * &lt;property
+ * android:name=
+ * "android.window.PROPERTY_COMPAT_IGNORE_ORIENTATION_REQUEST_WHEN_LOOP_DETECTED"
+ * android:value="false"/&gt;
+ * &lt;/application&gt;
+ * </pre>
+ *
+ * @hide
+ */
+ // TODO(b/274924641): Make this public API.
+ String PROPERTY_COMPAT_IGNORE_ORIENTATION_REQUEST_WHEN_LOOP_DETECTED =
+ "android.window.PROPERTY_COMPAT_IGNORE_ORIENTATION_REQUEST_WHEN_LOOP_DETECTED";
+
+ /**
* Application level {@link android.content.pm.PackageManager.Property PackageManager
* .Property} for an app to inform the system that it needs to be opted-out from the
* compatibility treatment that sandboxes {@link android.view.View} API.
diff --git a/core/java/android/window/ScreenCapture.java b/core/java/android/window/ScreenCapture.java
index d8e64d48f456..95451a966055 100644
--- a/core/java/android/window/ScreenCapture.java
+++ b/core/java/android/window/ScreenCapture.java
@@ -309,7 +309,7 @@ public class ScreenCapture {
/** Release any layers if set using {@link Builder#setExcludeLayers(SurfaceControl[])}. */
public void release() {
- if (mExcludeLayers.length == 0) {
+ if (mExcludeLayers == null || mExcludeLayers.length == 0) {
return;
}
diff --git a/core/java/com/android/internal/app/IntentForwarderActivity.java b/core/java/com/android/internal/app/IntentForwarderActivity.java
index 75e797b4ec9d..44d517ad0c32 100644
--- a/core/java/com/android/internal/app/IntentForwarderActivity.java
+++ b/core/java/com/android/internal/app/IntentForwarderActivity.java
@@ -19,6 +19,7 @@ package com.android.internal.app;
import static android.Manifest.permission.INTERACT_ACROSS_USERS;
import static android.app.admin.DevicePolicyResources.Strings.Core.FORWARD_INTENT_TO_PERSONAL;
import static android.app.admin.DevicePolicyResources.Strings.Core.FORWARD_INTENT_TO_WORK;
+import static android.app.admin.DevicePolicyResources.Strings.Core.MINIRESOLVER_OPEN_IN_WORK;
import static android.content.pm.PackageManager.MATCH_DEFAULT_ONLY;
import static android.content.pm.PackageManager.PERMISSION_GRANTED;
@@ -212,9 +213,7 @@ public class IntentForwarderActivity extends Activity {
buttonContainer.setPadding(0, 0, 0, buttonContainer.getPaddingBottom());
((TextView) findViewById(R.id.open_cross_profile)).setText(
- getResources().getString(
- R.string.miniresolver_open_in_work,
- target.loadLabel(packageManagerForTargetUser)));
+ getOpenInWorkMessage(target.loadLabel(packageManagerForTargetUser)));
// The mini-resolver's negative button is reused in this flow to cancel the intent
((Button) findViewById(R.id.use_same_profile_browser)).setText(R.string.cancel);
@@ -226,6 +225,13 @@ public class IntentForwarderActivity extends Activity {
});
}
+ private String getOpenInWorkMessage(CharSequence targetLabel) {
+ return getSystemService(DevicePolicyManager.class).getResources().getString(
+ MINIRESOLVER_OPEN_IN_WORK,
+ () -> getString(R.string.miniresolver_open_in_work, targetLabel),
+ targetLabel);
+ }
+
private String getForwardToPersonalMessage() {
return getSystemService(DevicePolicyManager.class).getResources().getString(
FORWARD_INTENT_TO_PERSONAL,
diff --git a/core/java/com/android/internal/app/ResolverActivity.java b/core/java/com/android/internal/app/ResolverActivity.java
index 73c5207e6238..499d38c31b59 100644
--- a/core/java/com/android/internal/app/ResolverActivity.java
+++ b/core/java/com/android/internal/app/ResolverActivity.java
@@ -19,6 +19,10 @@ package com.android.internal.app;
import static android.Manifest.permission.INTERACT_ACROSS_PROFILES;
import static android.app.admin.DevicePolicyResources.Strings.Core.FORWARD_INTENT_TO_PERSONAL;
import static android.app.admin.DevicePolicyResources.Strings.Core.FORWARD_INTENT_TO_WORK;
+import static android.app.admin.DevicePolicyResources.Strings.Core.MINIRESOLVER_OPEN_IN_PERSONAL;
+import static android.app.admin.DevicePolicyResources.Strings.Core.MINIRESOLVER_OPEN_IN_WORK;
+import static android.app.admin.DevicePolicyResources.Strings.Core.MINIRESOLVER_USE_PERSONAL_BROWSER;
+import static android.app.admin.DevicePolicyResources.Strings.Core.MINIRESOLVER_USE_WORK_BROWSER;
import static android.app.admin.DevicePolicyResources.Strings.Core.RESOLVER_CANT_ACCESS_PERSONAL;
import static android.app.admin.DevicePolicyResources.Strings.Core.RESOLVER_CANT_ACCESS_WORK;
import static android.app.admin.DevicePolicyResources.Strings.Core.RESOLVER_CROSS_PROFILE_BLOCKED_TITLE;
@@ -46,6 +50,7 @@ import android.app.VoiceInteractor.PickOptionRequest.Option;
import android.app.VoiceInteractor.Prompt;
import android.app.admin.DevicePolicyEventLogger;
import android.app.admin.DevicePolicyManager;
+import android.app.admin.DevicePolicyResourcesManager;
import android.compat.annotation.UnsupportedAppUsage;
import android.content.BroadcastReceiver;
import android.content.ComponentName;
@@ -1713,14 +1718,29 @@ public class ResolverActivity extends Activity implements
}
}.execute();
- ((TextView) findViewById(R.id.open_cross_profile)).setText(
- getResources().getString(
- inWorkProfile ? R.string.miniresolver_open_in_personal
- : R.string.miniresolver_open_in_work,
- otherProfileResolveInfo.getDisplayLabel()));
- ((Button) findViewById(R.id.use_same_profile_browser)).setText(
- inWorkProfile ? R.string.miniresolver_use_work_browser
- : R.string.miniresolver_use_personal_browser);
+ CharSequence targetDisplayLabel = otherProfileResolveInfo.getDisplayLabel();
+
+ DevicePolicyResourcesManager devicePolicyResourcesManager = getSystemService(
+ DevicePolicyManager.class).getResources();
+
+ if (inWorkProfile) {
+ ((TextView) findViewById(R.id.open_cross_profile)).setText(
+ devicePolicyResourcesManager.getString(MINIRESOLVER_OPEN_IN_WORK,
+ () -> getString(R.string.miniresolver_open_in_work, targetDisplayLabel),
+ targetDisplayLabel));
+ ((Button) findViewById(R.id.use_same_profile_browser)).setText(
+ devicePolicyResourcesManager.getString(MINIRESOLVER_USE_WORK_BROWSER,
+ () -> getString(R.string.miniresolver_use_work_browser)));
+ } else {
+ ((TextView) findViewById(R.id.open_cross_profile)).setText(
+ devicePolicyResourcesManager.getString(MINIRESOLVER_OPEN_IN_PERSONAL,
+ () -> getString(R.string.miniresolver_open_in_personal,
+ targetDisplayLabel),
+ targetDisplayLabel));
+ ((Button) findViewById(R.id.use_same_profile_browser)).setText(
+ devicePolicyResourcesManager.getString(MINIRESOLVER_USE_PERSONAL_BROWSER,
+ () -> getString(R.string.miniresolver_use_personal_browser)));
+ }
findViewById(R.id.use_same_profile_browser).setOnClickListener(
v -> {
diff --git a/core/java/com/android/internal/widget/MessagingImageMessage.java b/core/java/com/android/internal/widget/MessagingImageMessage.java
index 8e7fe18b222b..098bce14e619 100644
--- a/core/java/com/android/internal/widget/MessagingImageMessage.java
+++ b/core/java/com/android/internal/widget/MessagingImageMessage.java
@@ -198,6 +198,11 @@ public class MessagingImageMessage extends ImageView implements MessagingMessage
@Override
public int getMeasuredType() {
+ if (mDrawable == null) {
+ Log.e(TAG, "getMeasuredType() after recycle()!");
+ return MEASURED_NORMAL;
+ }
+
int measuredHeight = getMeasuredHeight();
int minImageHeight;
if (mIsIsolated) {
diff --git a/core/res/res/drawable-hdpi/pointer_copy.png b/core/res/res/drawable-hdpi/pointer_copy.png
index c5eda2e5b5c4..5d06a8eaa551 100644
--- a/core/res/res/drawable-hdpi/pointer_copy.png
+++ b/core/res/res/drawable-hdpi/pointer_copy.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/pointer_grab.png b/core/res/res/drawable-hdpi/pointer_grab.png
index 26da04de1d12..b76ec16e243b 100644
--- a/core/res/res/drawable-hdpi/pointer_grab.png
+++ b/core/res/res/drawable-hdpi/pointer_grab.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/pointer_grabbing.png b/core/res/res/drawable-hdpi/pointer_grabbing.png
index f4031a9227c7..10013e9a1821 100644
--- a/core/res/res/drawable-hdpi/pointer_grabbing.png
+++ b/core/res/res/drawable-hdpi/pointer_grabbing.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/pointer_hand.png b/core/res/res/drawable-hdpi/pointer_hand.png
index a7ae55fc4b5f..8a7277477ab0 100644
--- a/core/res/res/drawable-hdpi/pointer_hand.png
+++ b/core/res/res/drawable-hdpi/pointer_hand.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/pointer_nodrop.png b/core/res/res/drawable-hdpi/pointer_nodrop.png
index 7043323701dd..9df140c5816b 100644
--- a/core/res/res/drawable-hdpi/pointer_nodrop.png
+++ b/core/res/res/drawable-hdpi/pointer_nodrop.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/pointer_copy.png b/core/res/res/drawable-mdpi/pointer_copy.png
index e731108370d3..7189dada1bf2 100644
--- a/core/res/res/drawable-mdpi/pointer_copy.png
+++ b/core/res/res/drawable-mdpi/pointer_copy.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/pointer_copy_large.png b/core/res/res/drawable-mdpi/pointer_copy_large.png
index 15ccb04b8f76..a3d487df9e5e 100644
--- a/core/res/res/drawable-mdpi/pointer_copy_large.png
+++ b/core/res/res/drawable-mdpi/pointer_copy_large.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/pointer_grab.png b/core/res/res/drawable-mdpi/pointer_grab.png
index d625b55f7066..977b36cd875a 100644
--- a/core/res/res/drawable-mdpi/pointer_grab.png
+++ b/core/res/res/drawable-mdpi/pointer_grab.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/pointer_grab_large.png b/core/res/res/drawable-mdpi/pointer_grab_large.png
index 9d36df0d6d94..80587ceb8aba 100644
--- a/core/res/res/drawable-mdpi/pointer_grab_large.png
+++ b/core/res/res/drawable-mdpi/pointer_grab_large.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/pointer_grabbing.png b/core/res/res/drawable-mdpi/pointer_grabbing.png
index 71bb17ba5592..2bdcbdc7af75 100644
--- a/core/res/res/drawable-mdpi/pointer_grabbing.png
+++ b/core/res/res/drawable-mdpi/pointer_grabbing.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/pointer_grabbing_large.png b/core/res/res/drawable-mdpi/pointer_grabbing_large.png
index 5574b07faf44..a8a599c5ebee 100644
--- a/core/res/res/drawable-mdpi/pointer_grabbing_large.png
+++ b/core/res/res/drawable-mdpi/pointer_grabbing_large.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/pointer_hand.png b/core/res/res/drawable-mdpi/pointer_hand.png
index d7f7beda111c..e94b927cada6 100644
--- a/core/res/res/drawable-mdpi/pointer_hand.png
+++ b/core/res/res/drawable-mdpi/pointer_hand.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/pointer_hand_large.png b/core/res/res/drawable-mdpi/pointer_hand_large.png
index f775464ced18..7d89067b98bd 100644
--- a/core/res/res/drawable-mdpi/pointer_hand_large.png
+++ b/core/res/res/drawable-mdpi/pointer_hand_large.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/pointer_nodrop.png b/core/res/res/drawable-mdpi/pointer_nodrop.png
index 931b74094d79..15764fa4e51b 100644
--- a/core/res/res/drawable-mdpi/pointer_nodrop.png
+++ b/core/res/res/drawable-mdpi/pointer_nodrop.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/pointer_nodrop_large.png b/core/res/res/drawable-mdpi/pointer_nodrop_large.png
index 88f77d300a15..46ff5f779cef 100644
--- a/core/res/res/drawable-mdpi/pointer_nodrop_large.png
+++ b/core/res/res/drawable-mdpi/pointer_nodrop_large.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/pointer_copy.png b/core/res/res/drawable-xhdpi/pointer_copy.png
index 5b6cc5bc454f..8d889e1ad131 100644
--- a/core/res/res/drawable-xhdpi/pointer_copy.png
+++ b/core/res/res/drawable-xhdpi/pointer_copy.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/pointer_copy_large.png b/core/res/res/drawable-xhdpi/pointer_copy_large.png
index d78a410a2887..860c85499617 100644
--- a/core/res/res/drawable-xhdpi/pointer_copy_large.png
+++ b/core/res/res/drawable-xhdpi/pointer_copy_large.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/pointer_grab.png b/core/res/res/drawable-xhdpi/pointer_grab.png
index 46dd3eeb95c6..dd3c6de46be5 100644
--- a/core/res/res/drawable-xhdpi/pointer_grab.png
+++ b/core/res/res/drawable-xhdpi/pointer_grab.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/pointer_grab_large.png b/core/res/res/drawable-xhdpi/pointer_grab_large.png
index 1c7e63e2e527..bcae2c943d12 100644
--- a/core/res/res/drawable-xhdpi/pointer_grab_large.png
+++ b/core/res/res/drawable-xhdpi/pointer_grab_large.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/pointer_grabbing.png b/core/res/res/drawable-xhdpi/pointer_grabbing.png
index 2fb8a9c4442f..500fa73f58e4 100644
--- a/core/res/res/drawable-xhdpi/pointer_grabbing.png
+++ b/core/res/res/drawable-xhdpi/pointer_grabbing.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/pointer_grabbing_large.png b/core/res/res/drawable-xhdpi/pointer_grabbing_large.png
index 3467a03e2a56..c9c6f187e2a8 100644
--- a/core/res/res/drawable-xhdpi/pointer_grabbing_large.png
+++ b/core/res/res/drawable-xhdpi/pointer_grabbing_large.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/pointer_hand.png b/core/res/res/drawable-xhdpi/pointer_hand.png
index 926310cce74d..e931afe4eec8 100644
--- a/core/res/res/drawable-xhdpi/pointer_hand.png
+++ b/core/res/res/drawable-xhdpi/pointer_hand.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/pointer_hand_large.png b/core/res/res/drawable-xhdpi/pointer_hand_large.png
index 546b222164b5..39ae1b7438d0 100644
--- a/core/res/res/drawable-xhdpi/pointer_hand_large.png
+++ b/core/res/res/drawable-xhdpi/pointer_hand_large.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/pointer_nodrop.png b/core/res/res/drawable-xhdpi/pointer_nodrop.png
index fdfc2671255c..4c9fe63136a8 100644
--- a/core/res/res/drawable-xhdpi/pointer_nodrop.png
+++ b/core/res/res/drawable-xhdpi/pointer_nodrop.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/pointer_nodrop_large.png b/core/res/res/drawable-xhdpi/pointer_nodrop_large.png
index 2b5e8a4b0f59..ae60e77bbc5e 100644
--- a/core/res/res/drawable-xhdpi/pointer_nodrop_large.png
+++ b/core/res/res/drawable-xhdpi/pointer_nodrop_large.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/pointer_copy.png b/core/res/res/drawable-xxhdpi/pointer_copy.png
index bef4fb4e8c17..24661a653f42 100644
--- a/core/res/res/drawable-xxhdpi/pointer_copy.png
+++ b/core/res/res/drawable-xxhdpi/pointer_copy.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/pointer_grab.png b/core/res/res/drawable-xxhdpi/pointer_grab.png
index 6caa1ba77eb9..1917722fa4fa 100644
--- a/core/res/res/drawable-xxhdpi/pointer_grab.png
+++ b/core/res/res/drawable-xxhdpi/pointer_grab.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/pointer_grabbing.png b/core/res/res/drawable-xxhdpi/pointer_grabbing.png
index b52f75174a16..a4cd9e56ba2f 100644
--- a/core/res/res/drawable-xxhdpi/pointer_grabbing.png
+++ b/core/res/res/drawable-xxhdpi/pointer_grabbing.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/pointer_hand.png b/core/res/res/drawable-xxhdpi/pointer_hand.png
index f3ee077b5cc9..917529b9aa2a 100644
--- a/core/res/res/drawable-xxhdpi/pointer_hand.png
+++ b/core/res/res/drawable-xxhdpi/pointer_hand.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/pointer_nodrop.png b/core/res/res/drawable-xxhdpi/pointer_nodrop.png
index ef54301e4eac..35b4d13bd0be 100644
--- a/core/res/res/drawable-xxhdpi/pointer_nodrop.png
+++ b/core/res/res/drawable-xxhdpi/pointer_nodrop.png
Binary files differ
diff --git a/core/res/res/drawable/pointer_copy_icon.xml b/core/res/res/drawable/pointer_copy_icon.xml
index da32939b5b0f..7e7c0caf6d78 100644
--- a/core/res/res/drawable/pointer_copy_icon.xml
+++ b/core/res/res/drawable/pointer_copy_icon.xml
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="utf-8"?>
<pointer-icon xmlns:android="http://schemas.android.com/apk/res/android"
android:bitmap="@drawable/pointer_copy"
- android:hotSpotX="7.5dp"
+ android:hotSpotX="8.5dp"
android:hotSpotY="7.5dp" />
diff --git a/core/res/res/drawable/pointer_copy_large_icon.xml b/core/res/res/drawable/pointer_copy_large_icon.xml
index 55d47b4f4d63..54e95238f501 100644
--- a/core/res/res/drawable/pointer_copy_large_icon.xml
+++ b/core/res/res/drawable/pointer_copy_large_icon.xml
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="utf-8"?>
<pointer-icon xmlns:android="http://schemas.android.com/apk/res/android"
android:bitmap="@drawable/pointer_copy_large"
- android:hotSpotX="22.5dp"
- android:hotSpotY="22.5dp" />
+ android:hotSpotX="21.25dp"
+ android:hotSpotY="18.75dp" />
diff --git a/core/res/res/drawable/pointer_grab_icon.xml b/core/res/res/drawable/pointer_grab_icon.xml
index b3d4e78828cd..dd1216a2995b 100644
--- a/core/res/res/drawable/pointer_grab_icon.xml
+++ b/core/res/res/drawable/pointer_grab_icon.xml
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="utf-8"?>
<pointer-icon xmlns:android="http://schemas.android.com/apk/res/android"
android:bitmap="@drawable/pointer_grab"
- android:hotSpotX="13.5dp"
- android:hotSpotY="13.5dp" />
+ android:hotSpotX="9.5dp"
+ android:hotSpotY="4.5dp" />
diff --git a/core/res/res/drawable/pointer_grab_large_icon.xml b/core/res/res/drawable/pointer_grab_large_icon.xml
index 343c7d27c749..b5dbd11fb286 100644
--- a/core/res/res/drawable/pointer_grab_large_icon.xml
+++ b/core/res/res/drawable/pointer_grab_large_icon.xml
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="utf-8"?>
<pointer-icon xmlns:android="http://schemas.android.com/apk/res/android"
android:bitmap="@drawable/pointer_grab_large"
- android:hotSpotX="33.75dp"
- android:hotSpotY="33.75dp" />
+ android:hotSpotX="23.75dp"
+ android:hotSpotY="11.25dp" />
diff --git a/core/res/res/drawable/pointer_grabbing_large_icon.xml b/core/res/res/drawable/pointer_grabbing_large_icon.xml
index ac1626530778..b041c8397771 100644
--- a/core/res/res/drawable/pointer_grabbing_large_icon.xml
+++ b/core/res/res/drawable/pointer_grabbing_large_icon.xml
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="utf-8"?>
<pointer-icon xmlns:android="http://schemas.android.com/apk/res/android"
android:bitmap="@drawable/pointer_grabbing_large"
- android:hotSpotX="25.5dp"
- android:hotSpotY="22.5dp" />
+ android:hotSpotX="21.25dp"
+ android:hotSpotY="18.75dp" />
diff --git a/core/res/res/drawable/pointer_hand_icon.xml b/core/res/res/drawable/pointer_hand_icon.xml
index 3f9d1a639ddb..0feccd296406 100644
--- a/core/res/res/drawable/pointer_hand_icon.xml
+++ b/core/res/res/drawable/pointer_hand_icon.xml
@@ -2,4 +2,4 @@
<pointer-icon xmlns:android="http://schemas.android.com/apk/res/android"
android:bitmap="@drawable/pointer_hand"
android:hotSpotX="9.5dp"
- android:hotSpotY="1.5dp" />
+ android:hotSpotY="2.5dp" />
diff --git a/core/res/res/drawable/pointer_hand_large_icon.xml b/core/res/res/drawable/pointer_hand_large_icon.xml
index cd49762bd23f..6257b0ba2fb1 100644
--- a/core/res/res/drawable/pointer_hand_large_icon.xml
+++ b/core/res/res/drawable/pointer_hand_large_icon.xml
@@ -2,4 +2,4 @@
<pointer-icon xmlns:android="http://schemas.android.com/apk/res/android"
android:bitmap="@drawable/pointer_hand_large"
android:hotSpotX="23.75dp"
- android:hotSpotY="3.75dp" />
+ android:hotSpotY="6.25dp" />
diff --git a/core/res/res/drawable/pointer_nodrop_icon.xml b/core/res/res/drawable/pointer_nodrop_icon.xml
index 4dffd23638da..fb78d7469120 100644
--- a/core/res/res/drawable/pointer_nodrop_icon.xml
+++ b/core/res/res/drawable/pointer_nodrop_icon.xml
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="utf-8"?>
<pointer-icon xmlns:android="http://schemas.android.com/apk/res/android"
android:bitmap="@drawable/pointer_nodrop"
- android:hotSpotX="7.5dp"
+ android:hotSpotX="8.5dp"
android:hotSpotY="7.5dp" />
diff --git a/core/res/res/drawable/pointer_nodrop_large_icon.xml b/core/res/res/drawable/pointer_nodrop_large_icon.xml
index 602c744401a9..2385e11109b0 100644
--- a/core/res/res/drawable/pointer_nodrop_large_icon.xml
+++ b/core/res/res/drawable/pointer_nodrop_large_icon.xml
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="utf-8"?>
<pointer-icon xmlns:android="http://schemas.android.com/apk/res/android"
android:bitmap="@drawable/pointer_nodrop_large"
- android:hotSpotX="22.5dp"
- android:hotSpotY="22.5dp" />
+ android:hotSpotX="21.25dp"
+ android:hotSpotY="18.75dp" />
diff --git a/core/res/res/values/config.xml b/core/res/res/values/config.xml
index 76bae8de304d..3ff63519572f 100644
--- a/core/res/res/values/config.xml
+++ b/core/res/res/values/config.xml
@@ -4461,7 +4461,8 @@
See android.credentials.CredentialManager
-->
- <string name="config_defaultCredentialProviderService" translatable="false"></string>
+ <string-array name="config_defaultCredentialProviderService" translatable="false">
+ </string-array>
<!-- The package name for the system's smartspace service.
This service returns smartspace results.
diff --git a/core/res/res/values/symbols.xml b/core/res/res/values/symbols.xml
index 9fc2ed16b0c1..7b582da836aa 100644
--- a/core/res/res/values/symbols.xml
+++ b/core/res/res/values/symbols.xml
@@ -3754,7 +3754,7 @@
<java-symbol type="string" name="config_defaultAppPredictionService" />
<java-symbol type="string" name="config_defaultContentSuggestionsService" />
<java-symbol type="string" name="config_defaultCredentialManagerHybridService" />
- <java-symbol type="string" name="config_defaultCredentialProviderService" />
+ <java-symbol type="array" name="config_defaultCredentialProviderService" />
<java-symbol type="string" name="config_defaultSearchUiService" />
<java-symbol type="string" name="config_defaultSmartspaceService" />
<java-symbol type="string" name="config_defaultWallpaperEffectsGenerationService" />
diff --git a/core/tests/coretests/src/android/provider/DeviceConfigServiceManagerTest.java b/core/tests/coretests/src/android/provider/DeviceConfigServiceManagerTest.java
new file mode 100644
index 000000000000..e20258a625dd
--- /dev/null
+++ b/core/tests/coretests/src/android/provider/DeviceConfigServiceManagerTest.java
@@ -0,0 +1,73 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.provider;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import static org.junit.Assert.assertThrows;
+import static org.junit.Assume.assumeTrue;
+
+import android.platform.test.annotations.Presubmit;
+
+import androidx.test.filters.SmallTest;
+import androidx.test.runner.AndroidJUnit4;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+/**
+ * Class that tests the APIs of DeviceConfigServiceManager.ServiceRegisterer.
+ */
+@Presubmit
+@RunWith(AndroidJUnit4.class)
+@SmallTest
+public class DeviceConfigServiceManagerTest {
+
+ private static final String SERVICE_NAME = "device_config_updatable";
+ private DeviceConfigServiceManager.ServiceRegisterer mRegisterer;
+
+ @Before
+ public void setUp() {
+ mRegisterer = new DeviceConfigServiceManager.ServiceRegisterer(SERVICE_NAME);
+ }
+
+ @Test
+ public void testGetOrThrow() throws DeviceConfigServiceManager.ServiceNotFoundException {
+ if (UpdatableDeviceConfigServiceReadiness.shouldStartUpdatableService()) {
+ assertThat(mRegisterer.getOrThrow()).isNotNull();
+ } else {
+ assertThrows(DeviceConfigServiceManager.ServiceNotFoundException.class,
+ mRegisterer::getOrThrow);
+ }
+ }
+
+ @Test
+ public void testGet() {
+ assumeTrue(UpdatableDeviceConfigServiceReadiness.shouldStartUpdatableService());
+ assertThat(mRegisterer.get()).isNotNull();
+ }
+
+ @Test
+ public void testTryGet() {
+ if (UpdatableDeviceConfigServiceReadiness.shouldStartUpdatableService()) {
+ assertThat(mRegisterer.tryGet()).isNotNull();
+ } else {
+ assertThat(mRegisterer.tryGet()).isNull();
+ }
+ }
+}
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/kidsmode/KidsModeTaskOrganizer.java b/libs/WindowManager/Shell/src/com/android/wm/shell/kidsmode/KidsModeTaskOrganizer.java
index 318a49a8de31..6d46a9c3d0e7 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/kidsmode/KidsModeTaskOrganizer.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/kidsmode/KidsModeTaskOrganizer.java
@@ -23,6 +23,7 @@ import static android.app.WindowConfiguration.WINDOWING_MODE_FULLSCREEN;
import static android.app.WindowConfiguration.WINDOWING_MODE_UNDEFINED;
import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE;
import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_REVERSE_LANDSCAPE;
+import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_SENSOR_LANDSCAPE;
import static android.view.Display.DEFAULT_DISPLAY;
import android.app.ActivityManager;
@@ -310,8 +311,11 @@ public class KidsModeTaskOrganizer extends ShellTaskOrganizer {
// TODO(229961548): Remove ignoreOrientationRequest exception for Kids Mode once possible.
if (mReverseDefaultRotationEnabled) {
setOrientationRequestPolicy(/* isIgnoreOrientationRequestDisabled */ true,
- /* fromOrientations */ new int[]{SCREEN_ORIENTATION_REVERSE_LANDSCAPE},
- /* toOrientations */ new int[]{SCREEN_ORIENTATION_LANDSCAPE});
+ /* fromOrientations */
+ new int[]{SCREEN_ORIENTATION_LANDSCAPE, SCREEN_ORIENTATION_REVERSE_LANDSCAPE},
+ /* toOrientations */
+ new int[]{SCREEN_ORIENTATION_SENSOR_LANDSCAPE,
+ SCREEN_ORIENTATION_SENSOR_LANDSCAPE});
} else {
setOrientationRequestPolicy(/* isIgnoreOrientationRequestDisabled */ true,
/* fromOrientations */ null, /* toOrientations */ null);
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipBoundsAlgorithm.java b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipBoundsAlgorithm.java
index 867162be4c6d..24d0b996a3cb 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipBoundsAlgorithm.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipBoundsAlgorithm.java
@@ -198,7 +198,7 @@ public class PipBoundsAlgorithm {
/**
* @return whether the given {@param aspectRatio} is valid.
*/
- private boolean isValidPictureInPictureAspectRatio(float aspectRatio) {
+ public boolean isValidPictureInPictureAspectRatio(float aspectRatio) {
return Float.compare(mMinAspectRatio, aspectRatio) <= 0
&& Float.compare(aspectRatio, mMaxAspectRatio) <= 0;
}
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipTaskOrganizer.java b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipTaskOrganizer.java
index 09e050e91c64..a0bd064149d2 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipTaskOrganizer.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipTaskOrganizer.java
@@ -1259,7 +1259,16 @@ public class PipTaskOrganizer implements ShellTaskOrganizer.TaskListener,
protected void applyNewPictureInPictureParams(@NonNull PictureInPictureParams params) {
if (mDeferredTaskInfo != null || PipUtils.aspectRatioChanged(params.getAspectRatioFloat(),
mPictureInPictureParams.getAspectRatioFloat())) {
- mPipParamsChangedForwarder.notifyAspectRatioChanged(params.getAspectRatioFloat());
+ if (mPipBoundsAlgorithm.isValidPictureInPictureAspectRatio(
+ params.getAspectRatioFloat())) {
+ mPipParamsChangedForwarder.notifyAspectRatioChanged(params.getAspectRatioFloat());
+ } else {
+ ProtoLog.d(ShellProtoLogGroup.WM_SHELL_PICTURE_IN_PICTURE,
+ "%s: New aspect ratio is not valid."
+ + " hasAspectRatio=%b"
+ + " aspectRatio=%f",
+ TAG, params.hasSetAspectRatio(), params.getAspectRatioFloat());
+ }
}
if (mDeferredTaskInfo != null
|| PipUtils.remoteActionsChanged(params.getActions(),
diff --git a/libs/hwui/Android.bp b/libs/hwui/Android.bp
index 5d79104200d9..70c36a5803ee 100644
--- a/libs/hwui/Android.bp
+++ b/libs/hwui/Android.bp
@@ -55,6 +55,10 @@ cc_defaults {
// GCC false-positives on this warning, and since we -Werror that's
// a problem
"-Wno-free-nonheap-object",
+
+ // Do not de-optimise cold code paths in AFDO.
+ // Some code paths might be infrequently executed but critical to latency.
+ "-fno-profile-sample-accurate",
],
include_dirs: [
diff --git a/libs/hwui/pipeline/skia/SkiaPipeline.cpp b/libs/hwui/pipeline/skia/SkiaPipeline.cpp
index 8ea71f11e2f0..1f929685b62c 100644
--- a/libs/hwui/pipeline/skia/SkiaPipeline.cpp
+++ b/libs/hwui/pipeline/skia/SkiaPipeline.cpp
@@ -28,6 +28,7 @@
#include <SkMultiPictureDocument.h>
#include <SkOverdrawCanvas.h>
#include <SkOverdrawColorFilter.h>
+#include <SkPaintFilterCanvas.h>
#include <SkPicture.h>
#include <SkPictureRecorder.h>
#include <SkRect.h>
@@ -36,15 +37,15 @@
#include <SkStream.h>
#include <SkString.h>
#include <SkTypeface.h>
-#include "include/gpu/GpuTypes.h" // from Skia
#include <android-base/properties.h>
+#include <gui/TraceUtils.h>
#include <unistd.h>
#include <sstream>
-#include <gui/TraceUtils.h>
#include "LightingInfo.h"
#include "VectorDrawable.h"
+#include "include/gpu/GpuTypes.h" // from Skia
#include "thread/CommonPool.h"
#include "tools/SkSharingProc.h"
#include "utils/Color.h"
@@ -449,6 +450,23 @@ void SkiaPipeline::endCapture(SkSurface* surface) {
}
}
+class ForceDitherCanvas : public SkPaintFilterCanvas {
+public:
+ ForceDitherCanvas(SkCanvas* canvas) : SkPaintFilterCanvas(canvas) {}
+
+protected:
+ bool onFilter(SkPaint& paint) const override {
+ paint.setDither(true);
+ return true;
+ }
+
+ void onDrawDrawable(SkDrawable* drawable, const SkMatrix* matrix) override {
+ // We unroll the drawable using "this" canvas, so that draw calls contained inside will
+ // get dithering applied
+ drawable->draw(this, matrix);
+ }
+};
+
void SkiaPipeline::renderFrame(const LayerUpdateQueue& layers, const SkRect& clip,
const std::vector<sp<RenderNode>>& nodes, bool opaque,
const Rect& contentDrawBounds, sk_sp<SkSurface> surface,
@@ -503,6 +521,12 @@ void SkiaPipeline::renderFrameImpl(const SkRect& clip,
canvas->clear(SK_ColorTRANSPARENT);
}
+ std::optional<ForceDitherCanvas> forceDitherCanvas;
+ if (shouldForceDither()) {
+ forceDitherCanvas.emplace(canvas);
+ canvas = &forceDitherCanvas.value();
+ }
+
if (1 == nodes.size()) {
if (!nodes[0]->nothingToDraw()) {
RenderNodeDrawable root(nodes[0].get(), canvas);
diff --git a/libs/hwui/pipeline/skia/SkiaPipeline.h b/libs/hwui/pipeline/skia/SkiaPipeline.h
index befee8989383..0763b06b53ef 100644
--- a/libs/hwui/pipeline/skia/SkiaPipeline.h
+++ b/libs/hwui/pipeline/skia/SkiaPipeline.h
@@ -98,6 +98,8 @@ protected:
bool isCapturingSkp() const { return mCaptureMode != CaptureMode::None; }
+ virtual bool shouldForceDither() const { return mColorMode != ColorMode::Default; }
+
private:
void renderFrameImpl(const SkRect& clip,
const std::vector<sp<RenderNode>>& nodes, bool opaque,
diff --git a/libs/hwui/pipeline/skia/SkiaVulkanPipeline.cpp b/libs/hwui/pipeline/skia/SkiaVulkanPipeline.cpp
index c8f2e69ae0a4..6f1b99b95bbd 100644
--- a/libs/hwui/pipeline/skia/SkiaVulkanPipeline.cpp
+++ b/libs/hwui/pipeline/skia/SkiaVulkanPipeline.cpp
@@ -203,6 +203,11 @@ sk_sp<Bitmap> SkiaVulkanPipeline::allocateHardwareBitmap(renderthread::RenderThr
return nullptr;
}
+bool SkiaVulkanPipeline::shouldForceDither() const {
+ if (mVkSurface && mVkSurface->isBeyond8Bit()) return false;
+ return SkiaPipeline::shouldForceDither();
+}
+
void SkiaVulkanPipeline::onContextDestroyed() {
if (mVkSurface) {
vulkanManager().destroySurface(mVkSurface);
diff --git a/libs/hwui/pipeline/skia/SkiaVulkanPipeline.h b/libs/hwui/pipeline/skia/SkiaVulkanPipeline.h
index d921ddb0d0fb..0713e93bccde 100644
--- a/libs/hwui/pipeline/skia/SkiaVulkanPipeline.h
+++ b/libs/hwui/pipeline/skia/SkiaVulkanPipeline.h
@@ -63,6 +63,8 @@ public:
protected:
void onContextDestroyed() override;
+ bool shouldForceDither() const override;
+
private:
renderthread::VulkanManager& vulkanManager();
renderthread::VulkanSurface* mVkSurface = nullptr;
diff --git a/libs/hwui/renderthread/VulkanSurface.cpp b/libs/hwui/renderthread/VulkanSurface.cpp
index 21b6c44e997e..ae4f0572576e 100644
--- a/libs/hwui/renderthread/VulkanSurface.cpp
+++ b/libs/hwui/renderthread/VulkanSurface.cpp
@@ -530,6 +530,16 @@ void VulkanSurface::setColorSpace(sk_sp<SkColorSpace> colorSpace) {
}
}
+bool VulkanSurface::isBeyond8Bit() const {
+ switch (mWindowInfo.bufferFormat) {
+ case AHARDWAREBUFFER_FORMAT_R10G10B10A2_UNORM:
+ case AHARDWAREBUFFER_FORMAT_R16G16B16A16_FLOAT:
+ return true;
+ default:
+ return false;
+ }
+}
+
} /* namespace renderthread */
} /* namespace uirenderer */
} /* namespace android */
diff --git a/libs/hwui/renderthread/VulkanSurface.h b/libs/hwui/renderthread/VulkanSurface.h
index e2ddc6b07768..3b69b73bcab3 100644
--- a/libs/hwui/renderthread/VulkanSurface.h
+++ b/libs/hwui/renderthread/VulkanSurface.h
@@ -48,6 +48,8 @@ public:
void setColorSpace(sk_sp<SkColorSpace> colorSpace);
+ bool isBeyond8Bit() const;
+
private:
/*
* All structs/methods in this private section are specifically for use by the VulkanManager
diff --git a/media/java/android/media/IAudioService.aidl b/media/java/android/media/IAudioService.aidl
index f9d4efea57e2..fe5afc5a717e 100644
--- a/media/java/android/media/IAudioService.aidl
+++ b/media/java/android/media/IAudioService.aidl
@@ -268,7 +268,7 @@ interface IAudioService {
boolean isVolumeControlUsingVolumeGroups();
@EnforcePermission("MODIFY_AUDIO_SETTINGS_PRIVILEGED")
- oneway void registerStreamAliasingDispatcher(IStreamAliasingDispatcher isad, boolean register);
+ void registerStreamAliasingDispatcher(IStreamAliasingDispatcher isad, boolean register);
@EnforcePermission("MODIFY_AUDIO_SETTINGS_PRIVILEGED")
void setNotifAliasRingForTest(boolean alias);
diff --git a/media/jni/android_media_MediaCodec.cpp b/media/jni/android_media_MediaCodec.cpp
index 9a4aa3344374..dea7f03d369a 100644
--- a/media/jni/android_media_MediaCodec.cpp
+++ b/media/jni/android_media_MediaCodec.cpp
@@ -43,6 +43,8 @@
#include <android_runtime/android_hardware_HardwareBuffer.h>
+#include <android-base/stringprintf.h>
+
#include <binder/MemoryDealer.h>
#include <cutils/compiler.h>
@@ -1276,7 +1278,8 @@ void JMediaCodec::handleCallback(const sp<AMessage> &msg) {
ALOGE("Could not create MediaCodec.BufferInfo.");
env->ExceptionClear();
}
- jniThrowException(env, "java/lang/IllegalStateException", NULL);
+ jniThrowException(env, "java/lang/IllegalStateException",
+ "Fatal error: could not create MediaCodec.BufferInfo object");
return;
}
@@ -1309,7 +1312,8 @@ void JMediaCodec::handleCallback(const sp<AMessage> &msg) {
ALOGE("Could not create CodecException object.");
env->ExceptionClear();
}
- jniThrowException(env, "java/lang/IllegalStateException", NULL);
+ jniThrowException(env, "java/lang/IllegalStateException",
+ "Fatal error: could not create CodecException object");
return;
}
@@ -1322,7 +1326,9 @@ void JMediaCodec::handleCallback(const sp<AMessage> &msg) {
CHECK(msg->findMessage("format", &format));
if (OK != ConvertMessageToMap(env, format, &obj)) {
- jniThrowException(env, "java/lang/IllegalStateException", NULL);
+ jniThrowException(env, "java/lang/IllegalStateException",
+ "Fatal error: failed to convert format "
+ "from native to Java object");
return;
}
@@ -1353,7 +1359,8 @@ void JMediaCodec::handleFirstTunnelFrameReadyNotification(const sp<AMessage> &ms
status_t err = ConvertMessageToMap(env, data, &obj);
if (err != OK) {
- jniThrowException(env, "java/lang/IllegalStateException", NULL);
+ jniThrowException(env, "java/lang/IllegalStateException",
+ "Fatal error: failed to convert format from native to Java object");
return;
}
@@ -1374,7 +1381,8 @@ void JMediaCodec::handleFrameRenderedNotification(const sp<AMessage> &msg) {
status_t err = ConvertMessageToMap(env, data, &obj);
if (err != OK) {
- jniThrowException(env, "java/lang/IllegalStateException", NULL);
+ jniThrowException(env, "java/lang/IllegalStateException",
+ "Fatal error: failed to convert format from native to Java object");
return;
}
@@ -1385,6 +1393,18 @@ void JMediaCodec::handleFrameRenderedNotification(const sp<AMessage> &msg) {
env->DeleteLocalRef(obj);
}
+std::string JMediaCodec::getExceptionMessage(const char *msg = nullptr) const {
+ if (mCodec == nullptr) {
+ return msg ?: "";
+ }
+ std::string prefix = "";
+ if (msg && msg[0] != '\0') {
+ prefix.append(msg);
+ prefix.append("\n");
+ }
+ return prefix + mCodec->getErrorLog().extract();
+}
+
void JMediaCodec::onMessageReceived(const sp<AMessage> &msg) {
switch (msg->what()) {
case kWhatCallbackNotify:
@@ -1471,9 +1491,17 @@ static void throwCryptoException(JNIEnv *env, status_t err, const char *msg,
env->Throw(exception);
}
+static std::string GetExceptionMessage(const sp<JMediaCodec> &codec, const char *msg) {
+ if (codec == NULL) {
+ return msg ?: "codec is released already";
+ }
+ return codec->getExceptionMessage(msg);
+}
+
static jint throwExceptionAsNecessary(
JNIEnv *env, status_t err, int32_t actionCode = ACTION_CODE_FATAL,
- const char *msg = NULL, const sp<ICrypto>& crypto = NULL) {
+ const char *msg = NULL, const sp<ICrypto>& crypto = NULL,
+ const sp<JMediaCodec> &codec = NULL) {
switch (err) {
case OK:
return 0;
@@ -1488,23 +1516,38 @@ static jint throwExceptionAsNecessary(
return DEQUEUE_INFO_OUTPUT_BUFFERS_CHANGED;
case INVALID_OPERATION:
- jniThrowException(env, "java/lang/IllegalStateException", msg);
+ jniThrowException(
+ env, "java/lang/IllegalStateException",
+ GetExceptionMessage(codec, msg).c_str());
return 0;
case BAD_VALUE:
- jniThrowException(env, "java/lang/IllegalArgumentException", msg);
+ jniThrowException(
+ env, "java/lang/IllegalArgumentException",
+ GetExceptionMessage(codec, msg).c_str());
return 0;
default:
if (isCryptoError(err)) {
- throwCryptoException(env, err, msg, crypto);
+ throwCryptoException(
+ env, err,
+ GetExceptionMessage(codec, msg).c_str(),
+ crypto);
return 0;
}
- throwCodecException(env, err, actionCode, msg);
+ throwCodecException(
+ env, err, actionCode,
+ GetExceptionMessage(codec, msg).c_str());
return 0;
}
}
+static jint throwExceptionAsNecessary(
+ JNIEnv *env, status_t err, const sp<JMediaCodec> &codec,
+ int32_t actionCode = ACTION_CODE_FATAL) {
+ return throwExceptionAsNecessary(env, err, actionCode, NULL, NULL, codec);
+}
+
static void android_media_MediaCodec_native_enableOnFirstTunnelFrameReadyListener(
JNIEnv *env,
jobject thiz,
@@ -1512,13 +1555,13 @@ static void android_media_MediaCodec_native_enableOnFirstTunnelFrameReadyListene
sp<JMediaCodec> codec = getMediaCodec(env, thiz);
if (codec == NULL || codec->initCheck() != OK) {
- throwExceptionAsNecessary(env, INVALID_OPERATION);
+ throwExceptionAsNecessary(env, INVALID_OPERATION, codec);
return;
}
status_t err = codec->enableOnFirstTunnelFrameReadyListener(enabled);
- throwExceptionAsNecessary(env, err);
+ throwExceptionAsNecessary(env, err, codec);
}
static void android_media_MediaCodec_native_enableOnFrameRenderedListener(
@@ -1528,13 +1571,13 @@ static void android_media_MediaCodec_native_enableOnFrameRenderedListener(
sp<JMediaCodec> codec = getMediaCodec(env, thiz);
if (codec == NULL || codec->initCheck() != OK) {
- throwExceptionAsNecessary(env, INVALID_OPERATION);
+ throwExceptionAsNecessary(env, INVALID_OPERATION, codec);
return;
}
status_t err = codec->enableOnFrameRenderedListener(enabled);
- throwExceptionAsNecessary(env, err);
+ throwExceptionAsNecessary(env, err, codec);
}
static void android_media_MediaCodec_native_setCallback(
@@ -1544,13 +1587,13 @@ static void android_media_MediaCodec_native_setCallback(
sp<JMediaCodec> codec = getMediaCodec(env, thiz);
if (codec == NULL || codec->initCheck() != OK) {
- throwExceptionAsNecessary(env, INVALID_OPERATION);
+ throwExceptionAsNecessary(env, INVALID_OPERATION, codec);
return;
}
status_t err = codec->setCallback(cb);
- throwExceptionAsNecessary(env, err);
+ throwExceptionAsNecessary(env, err, codec);
}
static void android_media_MediaCodec_native_configure(
@@ -1564,7 +1607,7 @@ static void android_media_MediaCodec_native_configure(
sp<JMediaCodec> codec = getMediaCodec(env, thiz);
if (codec == NULL || codec->initCheck() != OK) {
- throwExceptionAsNecessary(env, INVALID_OPERATION);
+ throwExceptionAsNecessary(env, INVALID_OPERATION, codec);
return;
}
@@ -1602,7 +1645,7 @@ static void android_media_MediaCodec_native_configure(
err = codec->configure(format, bufferProducer, crypto, descrambler, flags);
- throwExceptionAsNecessary(env, err);
+ throwExceptionAsNecessary(env, err, codec);
}
static void android_media_MediaCodec_native_setSurface(
@@ -1612,7 +1655,7 @@ static void android_media_MediaCodec_native_setSurface(
sp<JMediaCodec> codec = getMediaCodec(env, thiz);
if (codec == NULL || codec->initCheck() != OK) {
- throwExceptionAsNecessary(env, INVALID_OPERATION);
+ throwExceptionAsNecessary(env, INVALID_OPERATION, codec);
return;
}
@@ -1631,7 +1674,7 @@ static void android_media_MediaCodec_native_setSurface(
}
status_t err = codec->setSurface(bufferProducer);
- throwExceptionAsNecessary(env, err);
+ throwExceptionAsNecessary(env, err, codec);
}
sp<PersistentSurface> android_media_MediaCodec_getPersistentInputSurface(
@@ -1735,7 +1778,7 @@ static void android_media_MediaCodec_setInputSurface(
sp<JMediaCodec> codec = getMediaCodec(env, thiz);
if (codec == NULL || codec->initCheck() != OK) {
- throwExceptionAsNecessary(env, INVALID_OPERATION);
+ throwExceptionAsNecessary(env, INVALID_OPERATION, codec);
return;
}
@@ -1749,7 +1792,7 @@ static void android_media_MediaCodec_setInputSurface(
}
status_t err = codec->setInputSurface(persistentSurface);
if (err != NO_ERROR) {
- throwExceptionAsNecessary(env, err);
+ throwExceptionAsNecessary(env, err, codec);
}
}
@@ -1759,7 +1802,7 @@ static jobject android_media_MediaCodec_createInputSurface(JNIEnv* env,
sp<JMediaCodec> codec = getMediaCodec(env, thiz);
if (codec == NULL || codec->initCheck() != OK) {
- throwExceptionAsNecessary(env, INVALID_OPERATION);
+ throwExceptionAsNecessary(env, INVALID_OPERATION, codec);
return NULL;
}
@@ -1767,7 +1810,7 @@ static jobject android_media_MediaCodec_createInputSurface(JNIEnv* env,
sp<IGraphicBufferProducer> bufferProducer;
status_t err = codec->createInputSurface(&bufferProducer);
if (err != NO_ERROR) {
- throwExceptionAsNecessary(env, err);
+ throwExceptionAsNecessary(env, err, codec);
return NULL;
}
@@ -1782,13 +1825,13 @@ static void android_media_MediaCodec_start(JNIEnv *env, jobject thiz) {
sp<JMediaCodec> codec = getMediaCodec(env, thiz);
if (codec == NULL || codec->initCheck() != OK) {
- throwExceptionAsNecessary(env, INVALID_OPERATION);
+ throwExceptionAsNecessary(env, INVALID_OPERATION, codec);
return;
}
status_t err = codec->start();
- throwExceptionAsNecessary(env, err, ACTION_CODE_FATAL, "start failed");
+ throwExceptionAsNecessary(env, err, codec);
}
static void android_media_MediaCodec_stop(JNIEnv *env, jobject thiz) {
@@ -1797,13 +1840,13 @@ static void android_media_MediaCodec_stop(JNIEnv *env, jobject thiz) {
sp<JMediaCodec> codec = getMediaCodec(env, thiz);
if (codec == NULL || codec->initCheck() != OK) {
- throwExceptionAsNecessary(env, INVALID_OPERATION);
+ throwExceptionAsNecessary(env, INVALID_OPERATION, codec);
return;
}
status_t err = codec->stop();
- throwExceptionAsNecessary(env, err);
+ throwExceptionAsNecessary(env, err, codec);
}
static void android_media_MediaCodec_reset(JNIEnv *env, jobject thiz) {
@@ -1812,7 +1855,7 @@ static void android_media_MediaCodec_reset(JNIEnv *env, jobject thiz) {
sp<JMediaCodec> codec = getMediaCodec(env, thiz);
if (codec == NULL || codec->initCheck() != OK) {
- throwExceptionAsNecessary(env, INVALID_OPERATION);
+ throwExceptionAsNecessary(env, INVALID_OPERATION, codec);
return;
}
@@ -1825,7 +1868,7 @@ static void android_media_MediaCodec_reset(JNIEnv *env, jobject thiz) {
// trigger an IllegalStateException.
err = UNKNOWN_ERROR;
}
- throwExceptionAsNecessary(env, err);
+ throwExceptionAsNecessary(env, err, codec);
}
static void android_media_MediaCodec_flush(JNIEnv *env, jobject thiz) {
@@ -1834,13 +1877,13 @@ static void android_media_MediaCodec_flush(JNIEnv *env, jobject thiz) {
sp<JMediaCodec> codec = getMediaCodec(env, thiz);
if (codec == NULL || codec->initCheck() != OK) {
- throwExceptionAsNecessary(env, INVALID_OPERATION);
+ throwExceptionAsNecessary(env, INVALID_OPERATION, codec);
return;
}
status_t err = codec->flush();
- throwExceptionAsNecessary(env, err);
+ throwExceptionAsNecessary(env, err, codec);
}
static void android_media_MediaCodec_queueInputBuffer(
@@ -1856,7 +1899,7 @@ static void android_media_MediaCodec_queueInputBuffer(
sp<JMediaCodec> codec = getMediaCodec(env, thiz);
if (codec == NULL || codec->initCheck() != OK) {
- throwExceptionAsNecessary(env, INVALID_OPERATION);
+ throwExceptionAsNecessary(env, INVALID_OPERATION, codec);
return;
}
@@ -1866,7 +1909,8 @@ static void android_media_MediaCodec_queueInputBuffer(
index, offset, size, timestampUs, flags, &errorDetailMsg);
throwExceptionAsNecessary(
- env, err, ACTION_CODE_FATAL, errorDetailMsg.empty() ? NULL : errorDetailMsg.c_str());
+ env, err, ACTION_CODE_FATAL,
+ codec->getExceptionMessage(errorDetailMsg.c_str()).c_str());
}
struct NativeCryptoInfo {
@@ -1890,7 +1934,9 @@ struct NativeCryptoInfo {
} else if (jmode == gCryptoModes.AesCbc) {
mMode = CryptoPlugin::kMode_AES_CBC;
} else {
- throwExceptionAsNecessary(env, INVALID_OPERATION);
+ throwExceptionAsNecessary(
+ env, INVALID_OPERATION, ACTION_CODE_FATAL,
+ base::StringPrintf("unrecognized crypto mode: %d", jmode).c_str());
return;
}
@@ -2026,7 +2072,7 @@ static void android_media_MediaCodec_queueSecureInputBuffer(
sp<JMediaCodec> codec = getMediaCodec(env, thiz);
if (codec == NULL || codec->initCheck() != OK) {
- throwExceptionAsNecessary(env, INVALID_OPERATION);
+ throwExceptionAsNecessary(env, INVALID_OPERATION, codec);
return;
}
@@ -2056,7 +2102,9 @@ static void android_media_MediaCodec_queueSecureInputBuffer(
} else if (jmode == gCryptoModes.AesCbc) {
mode = CryptoPlugin::kMode_AES_CBC;
} else {
- throwExceptionAsNecessary(env, INVALID_OPERATION);
+ throwExceptionAsNecessary(
+ env, INVALID_OPERATION, ACTION_CODE_FATAL,
+ base::StringPrintf("Unrecognized crypto mode: %d", jmode).c_str());
return;
}
@@ -2175,8 +2223,8 @@ static void android_media_MediaCodec_queueSecureInputBuffer(
subSamples = NULL;
throwExceptionAsNecessary(
- env, err, ACTION_CODE_FATAL, errorDetailMsg.empty() ? NULL : errorDetailMsg.c_str(),
- codec->getCrypto());
+ env, err, ACTION_CODE_FATAL,
+ codec->getExceptionMessage(errorDetailMsg.c_str()).c_str(), codec->getCrypto());
}
static jobject android_media_MediaCodec_mapHardwareBuffer(JNIEnv *env, jclass, jobject bufferObj) {
@@ -2518,14 +2566,16 @@ static void android_media_MediaCodec_native_queueLinearBlock(
sp<JMediaCodec> codec = getMediaCodec(env, thiz);
if (codec == nullptr || codec->initCheck() != OK) {
- throwExceptionAsNecessary(env, INVALID_OPERATION);
+ throwExceptionAsNecessary(env, INVALID_OPERATION, codec);
return;
}
sp<AMessage> tunings;
status_t err = ConvertKeyValueListsToAMessage(env, keys, values, &tunings);
if (err != OK) {
- throwExceptionAsNecessary(env, err);
+ throwExceptionAsNecessary(
+ env, err, ACTION_CODE_FATAL,
+ "error occurred while converting tunings from Java to native");
return;
}
@@ -2545,15 +2595,23 @@ static void android_media_MediaCodec_native_queueLinearBlock(
}
env->MonitorExit(lock.get());
} else {
- throwExceptionAsNecessary(env, INVALID_OPERATION);
+ throwExceptionAsNecessary(
+ env, INVALID_OPERATION, ACTION_CODE_FATAL,
+ "Failed to grab lock for a LinearBlock object");
return;
}
AString errorDetailMsg;
if (codec->hasCryptoOrDescrambler()) {
if (!memory) {
+ // It means there was an unexpected failure in extractMemoryFromContext above
ALOGI("queueLinearBlock: no ashmem memory for encrypted content");
- throwExceptionAsNecessary(env, BAD_VALUE);
+ throwExceptionAsNecessary(
+ env, BAD_VALUE, ACTION_CODE_FATAL,
+ "Unexpected error: the input buffer is not compatible with "
+ "the secure codec, and a fallback logic failed.\n"
+ "Suggestion: please try including the secure codec when calling "
+ "MediaCodec.LinearBlock#obtain method to obtain a compatible buffer.");
return;
}
auto cryptoInfo =
@@ -2577,14 +2635,22 @@ static void android_media_MediaCodec_native_queueLinearBlock(
ALOGI_IF(err != OK, "queueEncryptedLinearBlock returned err = %d", err);
} else {
if (!buffer) {
+ // It means there was an unexpected failure in extractBufferFromContext above
ALOGI("queueLinearBlock: no C2Buffer found");
- throwExceptionAsNecessary(env, BAD_VALUE);
+ throwExceptionAsNecessary(
+ env, BAD_VALUE, ACTION_CODE_FATAL,
+ "Unexpected error: the input buffer is not compatible with "
+ "the non-secure codec, and a fallback logic failed.\n"
+ "Suggestion: please do not include the secure codec when calling "
+ "MediaCodec.LinearBlock#obtain method to obtain a compatible buffer.");
return;
}
err = codec->queueBuffer(
index, buffer, presentationTimeUs, flags, tunings, &errorDetailMsg);
}
- throwExceptionAsNecessary(env, err, ACTION_CODE_FATAL, errorDetailMsg.c_str());
+ throwExceptionAsNecessary(
+ env, err, ACTION_CODE_FATAL,
+ codec->getExceptionMessage(errorDetailMsg.c_str()).c_str());
}
static void android_media_MediaCodec_native_queueHardwareBuffer(
@@ -2595,14 +2661,16 @@ static void android_media_MediaCodec_native_queueHardwareBuffer(
sp<JMediaCodec> codec = getMediaCodec(env, thiz);
if (codec == NULL || codec->initCheck() != OK) {
- throwExceptionAsNecessary(env, INVALID_OPERATION);
+ throwExceptionAsNecessary(env, INVALID_OPERATION, codec);
return;
}
sp<AMessage> tunings;
status_t err = ConvertKeyValueListsToAMessage(env, keys, values, &tunings);
if (err != OK) {
- throwExceptionAsNecessary(env, err);
+ throwExceptionAsNecessary(
+ env, err, ACTION_CODE_FATAL,
+ "error occurred while converting tunings from Java to native");
return;
}
@@ -2627,7 +2695,9 @@ static void android_media_MediaCodec_native_queueHardwareBuffer(
ALOGW("Failed to wrap AHardwareBuffer into C2GraphicAllocation");
native_handle_close(handle);
native_handle_delete(handle);
- throwExceptionAsNecessary(env, BAD_VALUE);
+ throwExceptionAsNecessary(
+ env, BAD_VALUE, ACTION_CODE_FATAL,
+ "HardwareBuffer not recognized");
return;
}
std::shared_ptr<C2GraphicBlock> block = _C2BlockFactory::CreateGraphicBlock(alloc);
@@ -2636,7 +2706,9 @@ static void android_media_MediaCodec_native_queueHardwareBuffer(
AString errorDetailMsg;
err = codec->queueBuffer(
index, buffer, presentationTimeUs, flags, tunings, &errorDetailMsg);
- throwExceptionAsNecessary(env, err, ACTION_CODE_FATAL, errorDetailMsg.c_str());
+ throwExceptionAsNecessary(
+ env, err, ACTION_CODE_FATAL,
+ codec->getExceptionMessage(errorDetailMsg.c_str()).c_str());
}
static void android_media_MediaCodec_native_getOutputFrame(
@@ -2646,13 +2718,13 @@ static void android_media_MediaCodec_native_getOutputFrame(
sp<JMediaCodec> codec = getMediaCodec(env, thiz);
if (codec == NULL || codec->initCheck() != OK) {
- throwExceptionAsNecessary(env, INVALID_OPERATION);
+ throwExceptionAsNecessary(env, INVALID_OPERATION, codec);
return;
}
status_t err = codec->getOutputFrame(env, frame, index);
if (err != OK) {
- throwExceptionAsNecessary(env, err);
+ throwExceptionAsNecessary(env, err, codec);
}
}
@@ -2663,7 +2735,7 @@ static jint android_media_MediaCodec_dequeueInputBuffer(
sp<JMediaCodec> codec = getMediaCodec(env, thiz);
if (codec == NULL || codec->initCheck() != OK) {
- throwExceptionAsNecessary(env, INVALID_OPERATION);
+ throwExceptionAsNecessary(env, INVALID_OPERATION, codec);
return -1;
}
@@ -2674,7 +2746,7 @@ static jint android_media_MediaCodec_dequeueInputBuffer(
return (jint) index;
}
- return throwExceptionAsNecessary(env, err);
+ return throwExceptionAsNecessary(env, err, codec);
}
static jint android_media_MediaCodec_dequeueOutputBuffer(
@@ -2684,7 +2756,7 @@ static jint android_media_MediaCodec_dequeueOutputBuffer(
sp<JMediaCodec> codec = getMediaCodec(env, thiz);
if (codec == NULL || codec->initCheck() != OK) {
- throwExceptionAsNecessary(env, INVALID_OPERATION);
+ throwExceptionAsNecessary(env, INVALID_OPERATION, codec);
return 0;
}
@@ -2696,7 +2768,7 @@ static jint android_media_MediaCodec_dequeueOutputBuffer(
return (jint) index;
}
- return throwExceptionAsNecessary(env, err);
+ return throwExceptionAsNecessary(env, err, codec);
}
static void android_media_MediaCodec_releaseOutputBuffer(
@@ -2707,13 +2779,13 @@ static void android_media_MediaCodec_releaseOutputBuffer(
sp<JMediaCodec> codec = getMediaCodec(env, thiz);
if (codec == NULL || codec->initCheck() != OK) {
- throwExceptionAsNecessary(env, INVALID_OPERATION);
+ throwExceptionAsNecessary(env, INVALID_OPERATION, codec);
return;
}
status_t err = codec->releaseOutputBuffer(index, render, updatePTS, timestampNs);
- throwExceptionAsNecessary(env, err);
+ throwExceptionAsNecessary(env, err, codec);
}
static void android_media_MediaCodec_signalEndOfInputStream(JNIEnv* env,
@@ -2722,13 +2794,13 @@ static void android_media_MediaCodec_signalEndOfInputStream(JNIEnv* env,
sp<JMediaCodec> codec = getMediaCodec(env, thiz);
if (codec == NULL || codec->initCheck() != OK) {
- throwExceptionAsNecessary(env, INVALID_OPERATION);
+ throwExceptionAsNecessary(env, INVALID_OPERATION, codec);
return;
}
status_t err = codec->signalEndOfInputStream();
- throwExceptionAsNecessary(env, err);
+ throwExceptionAsNecessary(env, err, codec);
}
static jobject android_media_MediaCodec_getFormatNative(
@@ -2738,7 +2810,7 @@ static jobject android_media_MediaCodec_getFormatNative(
sp<JMediaCodec> codec = getMediaCodec(env, thiz);
if (codec == NULL || codec->initCheck() != OK) {
- throwExceptionAsNecessary(env, INVALID_OPERATION);
+ throwExceptionAsNecessary(env, INVALID_OPERATION, codec);
return NULL;
}
@@ -2749,7 +2821,7 @@ static jobject android_media_MediaCodec_getFormatNative(
return format;
}
- throwExceptionAsNecessary(env, err);
+ throwExceptionAsNecessary(env, err, codec);
return NULL;
}
@@ -2761,7 +2833,7 @@ static jobject android_media_MediaCodec_getOutputFormatForIndexNative(
sp<JMediaCodec> codec = getMediaCodec(env, thiz);
if (codec == NULL || codec->initCheck() != OK) {
- throwExceptionAsNecessary(env, INVALID_OPERATION);
+ throwExceptionAsNecessary(env, INVALID_OPERATION, codec);
return NULL;
}
@@ -2772,7 +2844,7 @@ static jobject android_media_MediaCodec_getOutputFormatForIndexNative(
return format;
}
- throwExceptionAsNecessary(env, err);
+ throwExceptionAsNecessary(env, err, codec);
return NULL;
}
@@ -2784,7 +2856,7 @@ static jobjectArray android_media_MediaCodec_getBuffers(
sp<JMediaCodec> codec = getMediaCodec(env, thiz);
if (codec == NULL || codec->initCheck() != OK) {
- throwExceptionAsNecessary(env, INVALID_OPERATION);
+ throwExceptionAsNecessary(env, INVALID_OPERATION, codec);
return NULL;
}
@@ -2797,7 +2869,7 @@ static jobjectArray android_media_MediaCodec_getBuffers(
// if we're out of memory, an exception was already thrown
if (err != NO_MEMORY) {
- throwExceptionAsNecessary(env, err);
+ throwExceptionAsNecessary(env, err, codec);
}
return NULL;
@@ -2810,7 +2882,7 @@ static jobject android_media_MediaCodec_getBuffer(
sp<JMediaCodec> codec = getMediaCodec(env, thiz);
if (codec == NULL || codec->initCheck() != OK) {
- throwExceptionAsNecessary(env, INVALID_OPERATION);
+ throwExceptionAsNecessary(env, INVALID_OPERATION, codec);
return NULL;
}
@@ -2823,7 +2895,7 @@ static jobject android_media_MediaCodec_getBuffer(
// if we're out of memory, an exception was already thrown
if (err != NO_MEMORY) {
- throwExceptionAsNecessary(env, err);
+ throwExceptionAsNecessary(env, err, codec);
}
return NULL;
@@ -2836,7 +2908,7 @@ static jobject android_media_MediaCodec_getImage(
sp<JMediaCodec> codec = getMediaCodec(env, thiz);
if (codec == NULL || codec->initCheck() != OK) {
- throwExceptionAsNecessary(env, INVALID_OPERATION);
+ throwExceptionAsNecessary(env, INVALID_OPERATION, codec);
return NULL;
}
@@ -2849,7 +2921,7 @@ static jobject android_media_MediaCodec_getImage(
// if we're out of memory, an exception was already thrown
if (err != NO_MEMORY) {
- throwExceptionAsNecessary(env, err);
+ throwExceptionAsNecessary(env, err, codec);
}
return NULL;
@@ -2862,7 +2934,7 @@ static jobject android_media_MediaCodec_getName(
sp<JMediaCodec> codec = getMediaCodec(env, thiz);
if (codec == NULL || codec->initCheck() != OK) {
- throwExceptionAsNecessary(env, INVALID_OPERATION);
+ throwExceptionAsNecessary(env, INVALID_OPERATION, codec);
return NULL;
}
@@ -2873,7 +2945,7 @@ static jobject android_media_MediaCodec_getName(
return name;
}
- throwExceptionAsNecessary(env, err);
+ throwExceptionAsNecessary(env, err, codec);
return NULL;
}
@@ -2885,7 +2957,7 @@ static jobject android_media_MediaCodec_getOwnCodecInfo(
sp<JMediaCodec> codec = getMediaCodec(env, thiz);
if (codec == NULL || codec->initCheck() != OK) {
- throwExceptionAsNecessary(env, INVALID_OPERATION);
+ throwExceptionAsNecessary(env, INVALID_OPERATION, codec);
return NULL;
}
@@ -2896,7 +2968,7 @@ static jobject android_media_MediaCodec_getOwnCodecInfo(
return codecInfoObj;
}
- throwExceptionAsNecessary(env, err);
+ throwExceptionAsNecessary(env, err, codec);
return NULL;
}
@@ -2908,7 +2980,8 @@ android_media_MediaCodec_native_getMetrics(JNIEnv *env, jobject thiz)
sp<JMediaCodec> codec = getMediaCodec(env, thiz);
if (codec == NULL || codec->initCheck() != OK) {
- jniThrowException(env, "java/lang/IllegalStateException", NULL);
+ jniThrowException(env, "java/lang/IllegalStateException",
+ GetExceptionMessage(codec, NULL).c_str());
return 0;
}
@@ -2937,7 +3010,7 @@ static void android_media_MediaCodec_setParameters(
sp<JMediaCodec> codec = getMediaCodec(env, thiz);
if (codec == NULL || codec->initCheck() != OK) {
- throwExceptionAsNecessary(env, INVALID_OPERATION);
+ throwExceptionAsNecessary(env, INVALID_OPERATION, codec);
return;
}
@@ -2948,7 +3021,7 @@ static void android_media_MediaCodec_setParameters(
err = codec->setParameters(params);
}
- throwExceptionAsNecessary(env, err);
+ throwExceptionAsNecessary(env, err, codec);
}
static void android_media_MediaCodec_setVideoScalingMode(
@@ -2956,13 +3029,14 @@ static void android_media_MediaCodec_setVideoScalingMode(
sp<JMediaCodec> codec = getMediaCodec(env, thiz);
if (codec == NULL || codec->initCheck() != OK) {
- throwExceptionAsNecessary(env, INVALID_OPERATION);
+ throwExceptionAsNecessary(env, INVALID_OPERATION, codec);
return;
}
if (mode != NATIVE_WINDOW_SCALING_MODE_SCALE_TO_WINDOW
&& mode != NATIVE_WINDOW_SCALING_MODE_SCALE_CROP) {
- jniThrowException(env, "java/lang/IllegalArgumentException", NULL);
+ jniThrowException(env, "java/lang/IllegalArgumentException",
+ String8::format("Unrecognized mode: %d", mode));
return;
}
@@ -2974,7 +3048,7 @@ static void android_media_MediaCodec_setAudioPresentation(
sp<JMediaCodec> codec = getMediaCodec(env, thiz);
if (codec == NULL || codec->initCheck() != OK) {
- throwExceptionAsNecessary(env, INVALID_OPERATION);
+ throwExceptionAsNecessary(env, INVALID_OPERATION, codec);
return;
}
@@ -2986,14 +3060,14 @@ static jobject android_media_MediaCodec_getSupportedVendorParameters(
sp<JMediaCodec> codec = getMediaCodec(env, thiz);
if (codec == NULL || codec->initCheck() != OK) {
- throwExceptionAsNecessary(env, INVALID_OPERATION);
+ throwExceptionAsNecessary(env, INVALID_OPERATION, codec);
return NULL;
}
jobject ret = NULL;
status_t status = codec->querySupportedVendorParameters(env, &ret);
if (status != OK) {
- throwExceptionAsNecessary(env, status);
+ throwExceptionAsNecessary(env, status, codec);
}
return ret;
@@ -3004,7 +3078,7 @@ static jobject android_media_MediaCodec_getParameterDescriptor(
sp<JMediaCodec> codec = getMediaCodec(env, thiz);
if (codec == NULL || codec->initCheck() != OK) {
- throwExceptionAsNecessary(env, INVALID_OPERATION);
+ throwExceptionAsNecessary(env, INVALID_OPERATION, codec);
return NULL;
}
@@ -3021,13 +3095,13 @@ static void android_media_MediaCodec_subscribeToVendorParameters(
sp<JMediaCodec> codec = getMediaCodec(env, thiz);
if (codec == NULL || codec->initCheck() != OK) {
- throwExceptionAsNecessary(env, INVALID_OPERATION);
+ throwExceptionAsNecessary(env, INVALID_OPERATION, codec);
return;
}
status_t status = codec->subscribeToVendorParameters(env, names);
if (status != OK) {
- throwExceptionAsNecessary(env, status);
+ throwExceptionAsNecessary(env, status, codec);
}
return;
}
@@ -3037,13 +3111,13 @@ static void android_media_MediaCodec_unsubscribeFromVendorParameters(
sp<JMediaCodec> codec = getMediaCodec(env, thiz);
if (codec == NULL || codec->initCheck() != OK) {
- throwExceptionAsNecessary(env, INVALID_OPERATION);
+ throwExceptionAsNecessary(env, INVALID_OPERATION, codec);
return;
}
status_t status = codec->unsubscribeFromVendorParameters(env, names);
if (status != OK) {
- throwExceptionAsNecessary(env, status);
+ throwExceptionAsNecessary(env, status, codec);
}
return;
}
@@ -3440,11 +3514,15 @@ static jobject android_media_MediaCodec_LinearBlock_native_map(
if (!context->mReadonlyMapping) {
const C2BufferData data = buffer->data();
if (data.type() != C2BufferData::LINEAR) {
- throwExceptionAsNecessary(env, INVALID_OPERATION);
+ throwExceptionAsNecessary(
+ env, INVALID_OPERATION, ACTION_CODE_FATAL,
+ "Underlying buffer is not a linear buffer");
return nullptr;
}
if (data.linearBlocks().size() != 1u) {
- throwExceptionAsNecessary(env, INVALID_OPERATION);
+ throwExceptionAsNecessary(
+ env, INVALID_OPERATION, ACTION_CODE_FATAL,
+ "Underlying buffer contains more than one block");
return nullptr;
}
C2ConstLinearBlock block = data.linearBlocks().front();
@@ -3492,7 +3570,9 @@ static jobject android_media_MediaCodec_LinearBlock_native_map(
false, // readOnly
true /* clearBuffer */);
}
- throwExceptionAsNecessary(env, INVALID_OPERATION);
+ throwExceptionAsNecessary(
+ env, INVALID_OPERATION, ACTION_CODE_FATAL,
+ "Underlying buffer is empty");
return nullptr;
}
@@ -3515,7 +3595,9 @@ static void PopulateNamesVector(
}
const char *cstr = env->GetStringUTFChars(jstr, nullptr);
if (cstr == nullptr) {
- throwExceptionAsNecessary(env, BAD_VALUE);
+ throwExceptionAsNecessary(
+ env, BAD_VALUE, ACTION_CODE_FATAL,
+ "Error converting Java string to native");
return;
}
names->emplace_back(cstr);
@@ -3567,6 +3649,7 @@ static jboolean android_media_MediaCodec_LinearBlock_checkCompatible(
}
status_t err = MediaCodec::CanFetchLinearBlock(names, &isCompatible);
if (err != OK) {
+ // TODO: CodecErrorLog
throwExceptionAsNecessary(env, err);
}
return isCompatible;
diff --git a/media/jni/android_media_MediaCodec.h b/media/jni/android_media_MediaCodec.h
index 616c31b29157..fbaf64fda572 100644
--- a/media/jni/android_media_MediaCodec.h
+++ b/media/jni/android_media_MediaCodec.h
@@ -176,6 +176,8 @@ struct JMediaCodec : public AHandler {
const sp<ICrypto> &getCrypto() { return mCrypto; }
+ std::string getExceptionMessage(const char *msg) const;
+
protected:
virtual ~JMediaCodec();
diff --git a/packages/CredentialManager/src/com/android/credentialmanager/CredentialSelectorActivity.kt b/packages/CredentialManager/src/com/android/credentialmanager/CredentialSelectorActivity.kt
index 6f5015d6c79b..24f92c00c772 100644
--- a/packages/CredentialManager/src/com/android/credentialmanager/CredentialSelectorActivity.kt
+++ b/packages/CredentialManager/src/com/android/credentialmanager/CredentialSelectorActivity.kt
@@ -5,7 +5,7 @@
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
- * http://www.apache.org/licenses/LICENSE-2.0
+ * http://www.apache.org/licenses/LICENSE-2.0N
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
@@ -74,7 +74,6 @@ class CredentialSelectorActivity : ComponentActivity() {
override fun onNewIntent(intent: Intent) {
super.onNewIntent(intent)
setIntent(intent)
- Log.d(Constants.LOG_TAG, "Existing activity received new intent")
try {
val viewModel: CredentialSelectorViewModel by viewModels()
val (isCancellationRequest, shouldShowCancellationUi, appDisplayName) =
diff --git a/packages/CredentialManager/src/com/android/credentialmanager/common/ui/BottomSheet.kt b/packages/CredentialManager/src/com/android/credentialmanager/common/ui/BottomSheet.kt
index edc902e41e9a..53731f06816a 100644
--- a/packages/CredentialManager/src/com/android/credentialmanager/common/ui/BottomSheet.kt
+++ b/packages/CredentialManager/src/com/android/credentialmanager/common/ui/BottomSheet.kt
@@ -22,6 +22,7 @@ import androidx.compose.runtime.Composable
import androidx.compose.runtime.LaunchedEffect
import androidx.compose.ui.Modifier
import androidx.compose.ui.graphics.Color
+import com.android.compose.rememberSystemUiController
import com.android.credentialmanager.common.material.ModalBottomSheetLayout
import com.android.credentialmanager.common.material.ModalBottomSheetValue
import com.android.credentialmanager.common.material.rememberModalBottomSheetState
@@ -38,6 +39,12 @@ fun ModalBottomSheet(
initialValue = ModalBottomSheetValue.Expanded,
skipHalfExpanded = true
)
+ val sysUiController = rememberSystemUiController()
+ if (state.targetValue == ModalBottomSheetValue.Hidden) {
+ setTransparentSystemBarsColor(sysUiController)
+ } else {
+ setBottomSheetSystemBarsColor(sysUiController)
+ }
ModalBottomSheetLayout(
sheetBackgroundColor = LocalAndroidColorScheme.current.colorSurfaceBright,
modifier = Modifier.background(Color.Transparent),
diff --git a/packages/CredentialManager/src/com/android/credentialmanager/common/ui/SnackBar.kt b/packages/CredentialManager/src/com/android/credentialmanager/common/ui/SnackBar.kt
index dfff3d694877..244b604a87f9 100644
--- a/packages/CredentialManager/src/com/android/credentialmanager/common/ui/SnackBar.kt
+++ b/packages/CredentialManager/src/com/android/credentialmanager/common/ui/SnackBar.kt
@@ -37,6 +37,7 @@ import androidx.compose.ui.graphics.Color
import androidx.compose.ui.platform.LocalAccessibilityManager
import androidx.compose.ui.res.stringResource
import androidx.compose.ui.unit.dp
+import com.android.compose.rememberSystemUiController
import com.android.credentialmanager.R
import com.android.credentialmanager.common.material.Scrim
import com.android.credentialmanager.ui.theme.Shapes
@@ -49,6 +50,8 @@ fun Snackbar(
onDismiss: () -> Unit,
dismissOnTimeout: Boolean = false,
) {
+ val sysUiController = rememberSystemUiController()
+ setTransparentSystemBarsColor(sysUiController)
BoxWithConstraints {
Box(Modifier.fillMaxSize()) {
Scrim(
diff --git a/packages/CredentialManager/src/com/android/credentialmanager/createflow/CreateCredentialComponents.kt b/packages/CredentialManager/src/com/android/credentialmanager/createflow/CreateCredentialComponents.kt
index ed4cc959543b..648d83268541 100644
--- a/packages/CredentialManager/src/com/android/credentialmanager/createflow/CreateCredentialComponents.kt
+++ b/packages/CredentialManager/src/com/android/credentialmanager/createflow/CreateCredentialComponents.kt
@@ -46,7 +46,6 @@ import androidx.compose.ui.res.painterResource
import androidx.compose.ui.res.stringResource
import androidx.compose.ui.unit.dp
import androidx.core.graphics.drawable.toBitmap
-import com.android.compose.rememberSystemUiController
import com.android.credentialmanager.CredentialSelectorViewModel
import com.android.credentialmanager.R
import com.android.credentialmanager.common.BaseEntry
@@ -67,7 +66,6 @@ import com.android.credentialmanager.common.ui.MoreOptionTopAppBar
import com.android.credentialmanager.common.ui.SheetContainerCard
import com.android.credentialmanager.common.ui.PasskeyBenefitRow
import com.android.credentialmanager.common.ui.HeadlineText
-import com.android.credentialmanager.common.ui.setBottomSheetSystemBarsColor
import com.android.credentialmanager.logging.CreateCredentialEvent
import com.android.internal.logging.UiEventLogger.UiEventEnum
@@ -77,8 +75,6 @@ fun CreateCredentialScreen(
createCredentialUiState: CreateCredentialUiState,
providerActivityLauncher: ManagedActivityResultLauncher<IntentSenderRequest, ActivityResult>
) {
- val sysUiController = rememberSystemUiController()
- setBottomSheetSystemBarsColor(sysUiController)
ModalBottomSheet(
sheetContent = {
// Hide the sheet content as opposed to the whole bottom sheet to maintain the scrim
diff --git a/packages/CredentialManager/src/com/android/credentialmanager/getflow/GetCredentialComponents.kt b/packages/CredentialManager/src/com/android/credentialmanager/getflow/GetCredentialComponents.kt
index c27ac943bca7..6d7ecd70eb0b 100644
--- a/packages/CredentialManager/src/com/android/credentialmanager/getflow/GetCredentialComponents.kt
+++ b/packages/CredentialManager/src/com/android/credentialmanager/getflow/GetCredentialComponents.kt
@@ -41,7 +41,6 @@ import androidx.compose.ui.res.painterResource
import androidx.compose.ui.res.stringResource
import androidx.compose.ui.unit.dp
import androidx.core.graphics.drawable.toBitmap
-import com.android.compose.rememberSystemUiController
import com.android.credentialmanager.CredentialSelectorViewModel
import com.android.credentialmanager.R
import com.android.credentialmanager.common.BaseEntry
@@ -62,8 +61,6 @@ import com.android.credentialmanager.common.ui.CredentialListSectionHeader
import com.android.credentialmanager.common.ui.HeadlineIcon
import com.android.credentialmanager.common.ui.LargeLabelTextOnSurfaceVariant
import com.android.credentialmanager.common.ui.Snackbar
-import com.android.credentialmanager.common.ui.setTransparentSystemBarsColor
-import com.android.credentialmanager.common.ui.setBottomSheetSystemBarsColor
import com.android.credentialmanager.logging.GetCredentialEvent
import com.android.internal.logging.UiEventLogger.UiEventEnum
@@ -73,9 +70,7 @@ fun GetCredentialScreen(
getCredentialUiState: GetCredentialUiState,
providerActivityLauncher: ManagedActivityResultLauncher<IntentSenderRequest, ActivityResult>
) {
- val sysUiController = rememberSystemUiController()
if (getCredentialUiState.currentScreenState == GetScreenState.REMOTE_ONLY) {
- setTransparentSystemBarsColor(sysUiController)
RemoteCredentialSnackBarScreen(
onClick = viewModel::getFlowOnMoreOptionOnSnackBarSelected,
onCancel = viewModel::onUserCancel,
@@ -84,7 +79,6 @@ fun GetCredentialScreen(
viewModel.uiMetrics.log(GetCredentialEvent.CREDMAN_GET_CRED_SCREEN_REMOTE_ONLY)
} else if (getCredentialUiState.currentScreenState
== GetScreenState.UNLOCKED_AUTH_ENTRIES_ONLY) {
- setTransparentSystemBarsColor(sysUiController)
EmptyAuthEntrySnackBarScreen(
authenticationEntryList =
getCredentialUiState.providerDisplayInfo.authenticationEntryList,
@@ -95,7 +89,6 @@ fun GetCredentialScreen(
viewModel.uiMetrics.log(GetCredentialEvent
.CREDMAN_GET_CRED_SCREEN_UNLOCKED_AUTH_ENTRIES_ONLY)
} else {
- setBottomSheetSystemBarsColor(sysUiController)
ModalBottomSheet(
sheetContent = {
// Hide the sheet content as opposed to the whole bottom sheet to maintain the scrim
diff --git a/packages/SettingsProvider/src/com/android/providers/settings/SettingsProvider.java b/packages/SettingsProvider/src/com/android/providers/settings/SettingsProvider.java
index 7a97b78a4517..b0a19270018a 100644
--- a/packages/SettingsProvider/src/com/android/providers/settings/SettingsProvider.java
+++ b/packages/SettingsProvider/src/com/android/providers/settings/SettingsProvider.java
@@ -3748,7 +3748,7 @@ public class SettingsProvider extends ContentProvider {
}
private final class UpgradeController {
- private static final int SETTINGS_VERSION = 216;
+ private static final int SETTINGS_VERSION = 217;
private final int mUserId;
@@ -5711,7 +5711,7 @@ public class SettingsProvider extends ContentProvider {
.getSettingLocked(Settings.Secure.CREDENTIAL_SERVICE);
if (currentSetting.isNull()) {
final int resourceId =
- com.android.internal.R.string.config_defaultCredentialProviderService;
+ com.android.internal.R.array.config_defaultCredentialProviderService;
final Resources resources = getContext().getResources();
// If the config has not be defined we might get an exception. We also get
// values from both the string array type and the single string in case the
@@ -5771,6 +5771,39 @@ public class SettingsProvider extends ContentProvider {
currentVersion = 216;
}
+ if (currentVersion == 216) {
+ // Version 216: Set a default value for Credential Manager service.
+ // We are doing this migration again because of an incorrect setting.
+
+ final SettingsState secureSettings = getSecureSettingsLocked(userId);
+ final Setting currentSetting = secureSettings
+ .getSettingLocked(Settings.Secure.CREDENTIAL_SERVICE);
+ if (currentSetting.isNull()) {
+ final int resourceId =
+ com.android.internal.R.array.config_defaultCredentialProviderService;
+ final Resources resources = getContext().getResources();
+ // If the config has not be defined we might get an exception.
+ final List<String> providers = new ArrayList<>();
+ try {
+ providers.addAll(Arrays.asList(resources.getStringArray(resourceId)));
+ } catch (Resources.NotFoundException e) {
+ Slog.w(LOG_TAG,
+ "Get default array Cred Provider not found: " + e.toString());
+ }
+
+ if (!providers.isEmpty()) {
+ final String defaultValue = String.join(":", providers);
+ Slog.d(LOG_TAG, "Setting [" + defaultValue + "] as CredMan Service "
+ + "for user " + userId);
+ secureSettings.insertSettingOverrideableByRestoreLocked(
+ Settings.Secure.CREDENTIAL_SERVICE, defaultValue, null, true,
+ SettingsState.SYSTEM_PACKAGE_NAME);
+ }
+ }
+
+ currentVersion = 217;
+ }
+
// vXXX: Add new settings above this point.
if (currentVersion != newVersion) {
diff --git a/packages/SettingsProvider/src/com/android/providers/settings/WritableNamespacePrefixes.java b/packages/SettingsProvider/src/com/android/providers/settings/WritableNamespacePrefixes.java
index df27f6a67cfa..bd99a8bbb09f 100644
--- a/packages/SettingsProvider/src/com/android/providers/settings/WritableNamespacePrefixes.java
+++ b/packages/SettingsProvider/src/com/android/providers/settings/WritableNamespacePrefixes.java
@@ -170,6 +170,7 @@ final class WritableNamespacePrefixes {
"widget",
"wifi",
"window_manager",
- "window_manager_native_boot"
+ "window_manager_native_boot",
+ "wrong"
));
}
diff --git a/packages/SystemUI/src/com/android/systemui/flags/Flags.kt b/packages/SystemUI/src/com/android/systemui/flags/Flags.kt
index a7b45f4faee3..0bc8506f272d 100644
--- a/packages/SystemUI/src/com/android/systemui/flags/Flags.kt
+++ b/packages/SystemUI/src/com/android/systemui/flags/Flags.kt
@@ -285,7 +285,7 @@ object Flags {
/** Enables Font Scaling Quick Settings tile */
// TODO(b/269341316): Tracking Bug
@JvmField
- val ENABLE_FONT_SCALING_TILE = unreleasedFlag(509, "enable_font_scaling_tile", teamfood = true)
+ val ENABLE_FONT_SCALING_TILE = releasedFlag(509, "enable_font_scaling_tile")
/** Enables new QS Edit Mode visual refresh */
// TODO(b/269787742): Tracking Bug
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java b/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java
index b1efdd733faa..c102c5b57375 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java
@@ -2856,14 +2856,14 @@ public class KeyguardViewMediator implements CoreStartable, Dumpable,
+ " wasShowing=" + wasShowing);
}
+ mKeyguardUnlockAnimationControllerLazy.get()
+ .notifyFinishedKeyguardExitAnimation(cancelled);
finishSurfaceBehindRemoteAnimation(cancelled);
// Dispatch the callback on animation finishes.
mUpdateMonitor.dispatchKeyguardDismissAnimationFinished();
});
- mKeyguardUnlockAnimationControllerLazy.get().notifyFinishedKeyguardExitAnimation(
- cancelled);
}
/**
diff --git a/packages/SystemUI/src/com/android/systemui/media/controls/ui/KeyguardMediaController.kt b/packages/SystemUI/src/com/android/systemui/media/controls/ui/KeyguardMediaController.kt
index 8f1c9048026f..30ee147e302a 100644
--- a/packages/SystemUI/src/com/android/systemui/media/controls/ui/KeyguardMediaController.kt
+++ b/packages/SystemUI/src/com/android/systemui/media/controls/ui/KeyguardMediaController.kt
@@ -63,6 +63,10 @@ constructor(
override fun onStateChanged(newState: Int) {
refreshMediaPosition()
}
+
+ override fun onDozingChanged(isDozing: Boolean) {
+ refreshMediaPosition()
+ }
}
)
configurationController.addCallback(
@@ -198,7 +202,8 @@ constructor(
mediaHost.visible &&
!bypassController.bypassEnabled &&
keyguardOrUserSwitcher &&
- allowMediaPlayerOnLockScreen
+ allowMediaPlayerOnLockScreen &&
+ shouldBeVisibleForSplitShade()
if (visible) {
showMediaPlayer()
} else {
@@ -206,6 +211,19 @@ constructor(
}
}
+ private fun shouldBeVisibleForSplitShade(): Boolean {
+ if (!useSplitShade) {
+ return true
+ }
+ // We have to explicitly hide media for split shade when on AOD, as it is a child view of
+ // keyguard status view, and nothing hides keyguard status view on AOD.
+ // When using the double-line clock, it is not an issue, as media gets implicitly hidden
+ // by the clock. This is not the case for single-line clock though.
+ // For single shade, we don't need to do it, because media is a child of NSSL, which already
+ // gets hidden on AOD.
+ return !statusBarStateController.isDozing
+ }
+
private fun showMediaPlayer() {
if (useSplitShade) {
setVisibility(splitShadeContainer, View.VISIBLE)
diff --git a/packages/SystemUI/src/com/android/systemui/media/dialog/MediaOutputAdapter.java b/packages/SystemUI/src/com/android/systemui/media/dialog/MediaOutputAdapter.java
index 9928c4f79a96..f50a7a854169 100644
--- a/packages/SystemUI/src/com/android/systemui/media/dialog/MediaOutputAdapter.java
+++ b/packages/SystemUI/src/com/android/systemui/media/dialog/MediaOutputAdapter.java
@@ -205,7 +205,8 @@ public class MediaOutputAdapter extends MediaOutputBaseAdapter {
&& mController.isSubStatusSupported()
&& mController.isAdvancedLayoutSupported() && device.hasSubtext()) {
boolean isActiveWithOngoingSession =
- (device.hasOngoingSession() && currentlyConnected);
+ (device.hasOngoingSession() && (currentlyConnected || isDeviceIncluded(
+ mController.getSelectedMediaDevice(), device)));
boolean isHost = device.isHostForOngoingSession()
&& isActiveWithOngoingSession;
if (isHost) {
@@ -224,10 +225,17 @@ public class MediaOutputAdapter extends MediaOutputBaseAdapter {
if (isActiveWithOngoingSession) {
//Selected device which has ongoing session, disable seekbar since we
//only allow volume control on Host
- initSeekbar(device, isCurrentSeekbarInvisible);
mCurrentActivePosition = position;
}
- setUpDeviceIcon(device);
+ boolean showSeekbar =
+ (!device.hasOngoingSession() && currentlyConnected);
+ if (showSeekbar) {
+ updateTitleIcon(R.drawable.media_output_icon_volume,
+ mController.getColorItemContent());
+ initSeekbar(device, isCurrentSeekbarInvisible);
+ } else {
+ setUpDeviceIcon(device);
+ }
mSubTitleText.setText(device.getSubtextString());
Drawable deviceStatusIcon =
device.hasOngoingSession() ? mContext.getDrawable(
@@ -241,8 +249,8 @@ public class MediaOutputAdapter extends MediaOutputBaseAdapter {
updateTwoLineLayoutContentAlpha(
updateClickActionBasedOnSelectionBehavior(device)
? DEVICE_CONNECTED_ALPHA : DEVICE_DISCONNECTED_ALPHA);
- setTwoLineLayout(device, isActiveWithOngoingSession /* bFocused */,
- isActiveWithOngoingSession /* showSeekBar */,
+ setTwoLineLayout(device, currentlyConnected /* bFocused */,
+ showSeekbar /* showSeekBar */,
false /* showProgressBar */, true /* showSubtitle */,
deviceStatusIcon != null /* showStatus */,
isActiveWithOngoingSession /* isFakeActive */);
diff --git a/packages/SystemUI/src/com/android/systemui/media/dialog/MediaOutputBaseAdapter.java b/packages/SystemUI/src/com/android/systemui/media/dialog/MediaOutputBaseAdapter.java
index 731bb2f4db7c..73ab52722a79 100644
--- a/packages/SystemUI/src/com/android/systemui/media/dialog/MediaOutputBaseAdapter.java
+++ b/packages/SystemUI/src/com/android/systemui/media/dialog/MediaOutputBaseAdapter.java
@@ -270,10 +270,10 @@ public abstract class MediaOutputBaseAdapter extends
final Drawable backgroundDrawable;
if (mController.isAdvancedLayoutSupported() && mController.isSubStatusSupported()) {
backgroundDrawable = mContext.getDrawable(
- showSeekBar ? R.drawable.media_output_item_background_active
+ showSeekBar || isFakeActive ? R.drawable.media_output_item_background_active
: R.drawable.media_output_item_background).mutate();
backgroundDrawable.setTint(
- showSeekBar ? mController.getColorConnectedItemBackground()
+ showSeekBar || isFakeActive ? mController.getColorConnectedItemBackground()
: mController.getColorItemBackground());
mIconAreaLayout.setBackgroundTintList(
ColorStateList.valueOf(showProgressBar || isFakeActive
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/ui/viewmodel/MobileIconViewModel.kt b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/ui/viewmodel/MobileIconViewModel.kt
index 0fd007cf40ef..62bc27f9dd4e 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/ui/viewmodel/MobileIconViewModel.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/ui/viewmodel/MobileIconViewModel.kt
@@ -170,7 +170,10 @@ constructor(
if (networkTypeIconGroup.dataContentDescription != 0)
ContentDescription.Resource(networkTypeIconGroup.dataContentDescription)
else null
- val icon = Icon.Resource(networkTypeIconGroup.dataType, desc)
+ val icon =
+ if (networkTypeIconGroup.dataType != 0)
+ Icon.Resource(networkTypeIconGroup.dataType, desc)
+ else null
return@combine when {
!shouldShow -> null
else -> icon
diff --git a/packages/SystemUI/tests/src/com/android/systemui/controls/management/ControlsFavoritingActivityTest.kt b/packages/SystemUI/tests/src/com/android/systemui/controls/management/ControlsFavoritingActivityTest.kt
index 68846168d17b..f4cc8bcb09a5 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/controls/management/ControlsFavoritingActivityTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/controls/management/ControlsFavoritingActivityTest.kt
@@ -60,6 +60,12 @@ class ControlsFavoritingActivityTest : SysuiTestCase() {
}
val TEST_STRUCTURE: CharSequence = "TestStructure"
val TEST_APP: CharSequence = "TestApp"
+
+ private fun View.waitForPost() {
+ val latch = CountDownLatch(1)
+ post(latch::countDown)
+ latch.await()
+ }
}
@Main private val executor: Executor = MoreExecutors.directExecutor()
@@ -140,7 +146,10 @@ class ControlsFavoritingActivityTest : SysuiTestCase() {
val rearrangeButton = requireViewById<Button>(R.id.rearrange)
assertThat(rearrangeButton.visibility).isEqualTo(View.VISIBLE)
assertThat(rearrangeButton.isEnabled).isFalse()
- assertThat(requireViewById<Button>(R.id.other_apps).visibility).isEqualTo(View.GONE)
+
+ val otherAppsButton = requireViewById<Button>(R.id.other_apps)
+ otherAppsButton.waitForPost()
+ assertThat(otherAppsButton.visibility).isEqualTo(View.GONE)
}
}
@@ -160,7 +169,10 @@ class ControlsFavoritingActivityTest : SysuiTestCase() {
val rearrangeButton = requireViewById<Button>(R.id.rearrange)
assertThat(rearrangeButton.visibility).isEqualTo(View.GONE)
assertThat(rearrangeButton.isEnabled).isFalse()
- assertThat(requireViewById<Button>(R.id.other_apps).visibility).isEqualTo(View.VISIBLE)
+
+ val otherAppsButton = requireViewById<Button>(R.id.other_apps)
+ otherAppsButton.waitForPost()
+ assertThat(otherAppsButton.visibility).isEqualTo(View.VISIBLE)
}
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/media/controls/ui/KeyguardMediaControllerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/media/controls/ui/KeyguardMediaControllerTest.kt
index 20260069c943..b40ebc9bb156 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/media/controls/ui/KeyguardMediaControllerTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/media/controls/ui/KeyguardMediaControllerTest.kt
@@ -24,12 +24,14 @@ import android.view.View.GONE
import android.view.View.VISIBLE
import android.widget.FrameLayout
import com.android.systemui.SysuiTestCase
+import com.android.systemui.plugins.statusbar.StatusBarStateController
import com.android.systemui.statusbar.StatusBarState
import com.android.systemui.statusbar.SysuiStatusBarStateController
import com.android.systemui.statusbar.notification.stack.MediaContainerView
import com.android.systemui.statusbar.phone.KeyguardBypassController
import com.android.systemui.statusbar.policy.ConfigurationController
import com.android.systemui.util.animation.UniqueObjectHostView
+import com.android.systemui.util.mockito.whenever
import com.android.systemui.util.settings.FakeSettings
import com.android.systemui.utils.os.FakeHandler
import com.google.common.truth.Truth.assertThat
@@ -39,8 +41,9 @@ import org.junit.Rule
import org.junit.Test
import org.junit.runner.RunWith
import org.mockito.Mock
+import org.mockito.Mockito.any
+import org.mockito.Mockito.doAnswer
import org.mockito.Mockito.verify
-import org.mockito.Mockito.`when` as whenever
import org.mockito.junit.MockitoJUnit
@SmallTest
@@ -61,9 +64,16 @@ class KeyguardMediaControllerTest : SysuiTestCase() {
private lateinit var keyguardMediaController: KeyguardMediaController
private lateinit var testableLooper: TestableLooper
private lateinit var fakeHandler: FakeHandler
+ private lateinit var statusBarStateListener: StatusBarStateController.StateListener
@Before
fun setup() {
+ doAnswer {
+ statusBarStateListener = it.arguments[0] as StatusBarStateController.StateListener
+ return@doAnswer Unit
+ }
+ .whenever(statusBarStateController)
+ .addCallback(any(StatusBarStateController.StateListener::class.java))
// default state is positive, media should show up
whenever(mediaHost.visible).thenReturn(true)
whenever(statusBarStateController.state).thenReturn(StatusBarState.KEYGUARD)
@@ -170,4 +180,31 @@ class KeyguardMediaControllerTest : SysuiTestCase() {
fun testMediaHost_expandedPlayer() {
verify(mediaHost).expansion = MediaHostState.EXPANDED
}
+
+ @Test
+ fun dozing_inSplitShade_mediaIsHidden() {
+ val splitShadeContainer = FrameLayout(context)
+ keyguardMediaController.attachSplitShadeContainer(splitShadeContainer)
+ keyguardMediaController.useSplitShade = true
+
+ setDozing()
+
+ assertThat(splitShadeContainer.visibility).isEqualTo(GONE)
+ }
+
+ @Test
+ fun dozing_inSingleShade_mediaIsVisible() {
+ val splitShadeContainer = FrameLayout(context)
+ keyguardMediaController.attachSplitShadeContainer(splitShadeContainer)
+ keyguardMediaController.useSplitShade = false
+
+ setDozing()
+
+ assertThat(mediaContainerView.visibility).isEqualTo(VISIBLE)
+ }
+
+ private fun setDozing() {
+ whenever(statusBarStateController.isDozing).thenReturn(true)
+ statusBarStateListener.onDozingChanged(true)
+ }
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/media/dialog/MediaOutputAdapterTest.java b/packages/SystemUI/tests/src/com/android/systemui/media/dialog/MediaOutputAdapterTest.java
index 17d8799b4f84..7f7952feb10b 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/media/dialog/MediaOutputAdapterTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/media/dialog/MediaOutputAdapterTest.java
@@ -532,7 +532,7 @@ public class MediaOutputAdapterTest extends SysuiTestCase {
mMediaOutputAdapter.onBindViewHolder(mViewHolder, 0);
assertThat(mViewHolder.mTitleText.getVisibility()).isEqualTo(View.GONE);
- assertThat(mViewHolder.mSeekBar.getVisibility()).isEqualTo(View.VISIBLE);
+ assertThat(mViewHolder.mSeekBar.getVisibility()).isEqualTo(View.GONE);
assertThat(mViewHolder.mProgressBar.getVisibility()).isEqualTo(View.GONE);
assertThat(mViewHolder.mCheckBox.getVisibility()).isEqualTo(View.GONE);
assertThat(mViewHolder.mStatusIcon.getVisibility()).isEqualTo(View.VISIBLE);
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/ui/viewmodel/MobileIconViewModelTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/ui/viewmodel/MobileIconViewModelTest.kt
index 8ea8f87e6aff..1593e5c735a5 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/ui/viewmodel/MobileIconViewModelTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/ui/viewmodel/MobileIconViewModelTest.kt
@@ -20,6 +20,7 @@ import androidx.test.filters.SmallTest
import com.android.settingslib.AccessibilityContentDescriptions.PHONE_SIGNAL_STRENGTH
import com.android.settingslib.AccessibilityContentDescriptions.PHONE_SIGNAL_STRENGTH_NONE
import com.android.settingslib.mobile.TelephonyIcons.THREE_G
+import com.android.settingslib.mobile.TelephonyIcons.UNKNOWN
import com.android.systemui.SysuiTestCase
import com.android.systemui.common.shared.model.ContentDescription
import com.android.systemui.common.shared.model.Icon
@@ -343,7 +344,7 @@ class MobileIconViewModelTest : SysuiTestCase() {
fun networkType_alwaysShow_shownEvenWhenDisabled() =
testScope.runTest {
interactor.setIconGroup(THREE_G)
- interactor.setIsDataEnabled(true)
+ interactor.setIsDataEnabled(false)
interactor.alwaysShowDataRatIcon.value = true
var latest: Icon? = null
@@ -400,6 +401,21 @@ class MobileIconViewModelTest : SysuiTestCase() {
}
@Test
+ fun networkType_alwaysShow_notShownWhenInvalidDataTypeIcon() =
+ testScope.runTest {
+ // The UNKNOWN icon group doesn't have a valid data type icon ID
+ interactor.setIconGroup(UNKNOWN)
+ interactor.alwaysShowDataRatIcon.value = true
+
+ var latest: Icon? = null
+ val job = underTest.networkTypeIcon.onEach { latest = it }.launchIn(this)
+
+ assertThat(latest).isNull()
+
+ job.cancel()
+ }
+
+ @Test
fun `network type - alwaysShow - shown when not default`() =
testScope.runTest {
interactor.setIconGroup(THREE_G)
diff --git a/services/companion/java/com/android/server/companion/virtual/VirtualDeviceImpl.java b/services/companion/java/com/android/server/companion/virtual/VirtualDeviceImpl.java
index 1363ef31c68d..ae88f24ab409 100644
--- a/services/companion/java/com/android/server/companion/virtual/VirtualDeviceImpl.java
+++ b/services/companion/java/com/android/server/companion/virtual/VirtualDeviceImpl.java
@@ -126,7 +126,7 @@ final class VirtualDeviceImpl extends IVirtualDevice.Stub
private final VirtualDeviceManagerService mService;
private final PendingTrampolineCallback mPendingTrampolineCallback;
private final int mOwnerUid;
- private final int mDeviceId;
+ private int mDeviceId;
// Thou shall not hold the mVirtualDeviceLock over the mInputController calls.
// Holding the lock can lead to lock inversion with GlobalWindowManagerLock.
// 1. After display is created the window manager calls into VDM during construction
@@ -348,6 +348,7 @@ final class VirtualDeviceImpl extends IVirtualDevice.Stub
@Override // Binder call
public void launchPendingIntent(int displayId, PendingIntent pendingIntent,
ResultReceiver resultReceiver) {
+ Objects.requireNonNull(pendingIntent);
synchronized (mVirtualDeviceLock) {
if (!mVirtualDisplays.contains(displayId)) {
throw new SecurityException("Display ID " + displayId
@@ -404,6 +405,7 @@ final class VirtualDeviceImpl extends IVirtualDevice.Stub
super.close_enforcePermission();
// Remove about-to-be-closed virtual device from the service before butchering it.
mService.removeVirtualDevice(mDeviceId);
+ mDeviceId = Context.DEVICE_ID_INVALID;
VirtualDisplayWrapper[] virtualDisplaysToBeReleased;
synchronized (mVirtualDeviceLock) {
@@ -497,6 +499,7 @@ final class VirtualDeviceImpl extends IVirtualDevice.Stub
@EnforcePermission(android.Manifest.permission.CREATE_VIRTUAL_DEVICE)
public void createVirtualDpad(VirtualDpadConfig config, @NonNull IBinder deviceToken) {
super.createVirtualDpad_enforcePermission();
+ Objects.requireNonNull(config);
synchronized (mVirtualDeviceLock) {
if (!mVirtualDisplays.contains(config.getAssociatedDisplayId())) {
throw new SecurityException(
@@ -517,6 +520,7 @@ final class VirtualDeviceImpl extends IVirtualDevice.Stub
@EnforcePermission(android.Manifest.permission.CREATE_VIRTUAL_DEVICE)
public void createVirtualKeyboard(VirtualKeyboardConfig config, @NonNull IBinder deviceToken) {
super.createVirtualKeyboard_enforcePermission();
+ Objects.requireNonNull(config);
synchronized (mVirtualDeviceLock) {
if (!mVirtualDisplays.contains(config.getAssociatedDisplayId())) {
throw new SecurityException(
@@ -539,6 +543,7 @@ final class VirtualDeviceImpl extends IVirtualDevice.Stub
@EnforcePermission(android.Manifest.permission.CREATE_VIRTUAL_DEVICE)
public void createVirtualMouse(VirtualMouseConfig config, @NonNull IBinder deviceToken) {
super.createVirtualMouse_enforcePermission();
+ Objects.requireNonNull(config);
synchronized (mVirtualDeviceLock) {
if (!mVirtualDisplays.contains(config.getAssociatedDisplayId())) {
throw new SecurityException(
@@ -560,6 +565,7 @@ final class VirtualDeviceImpl extends IVirtualDevice.Stub
public void createVirtualTouchscreen(VirtualTouchscreenConfig config,
@NonNull IBinder deviceToken) {
super.createVirtualTouchscreen_enforcePermission();
+ Objects.requireNonNull(config);
synchronized (mVirtualDeviceLock) {
if (!mVirtualDisplays.contains(config.getAssociatedDisplayId())) {
throw new SecurityException(
@@ -590,6 +596,7 @@ final class VirtualDeviceImpl extends IVirtualDevice.Stub
public void createVirtualNavigationTouchpad(VirtualNavigationTouchpadConfig config,
@NonNull IBinder deviceToken) {
super.createVirtualNavigationTouchpad_enforcePermission();
+ Objects.requireNonNull(config);
synchronized (mVirtualDeviceLock) {
if (!mVirtualDisplays.contains(config.getAssociatedDisplayId())) {
throw new SecurityException(
diff --git a/services/companion/java/com/android/server/companion/virtual/VirtualDeviceManagerService.java b/services/companion/java/com/android/server/companion/virtual/VirtualDeviceManagerService.java
index 3b1983f55fb6..291c05877c17 100644
--- a/services/companion/java/com/android/server/companion/virtual/VirtualDeviceManagerService.java
+++ b/services/companion/java/com/android/server/companion/virtual/VirtualDeviceManagerService.java
@@ -66,7 +66,10 @@ import com.android.server.wm.ActivityTaskManagerInternal;
import java.io.FileDescriptor;
import java.io.PrintWriter;
import java.util.ArrayList;
+import java.util.HashSet;
import java.util.List;
+import java.util.Objects;
+import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.function.Consumer;
@@ -86,6 +89,14 @@ public class VirtualDeviceManagerService extends SystemService {
private static AtomicInteger sNextUniqueIndex = new AtomicInteger(
Context.DEVICE_ID_DEFAULT + 1);
+ private final CompanionDeviceManager.OnAssociationsChangedListener mCdmAssociationListener =
+ new CompanionDeviceManager.OnAssociationsChangedListener() {
+ @Override
+ public void onAssociationsChanged(@NonNull List<AssociationInfo> associations) {
+ syncVirtualDevicesToCdmAssociations(associations);
+ }
+ };
+
/**
* Mapping from device IDs to virtual devices.
*/
@@ -204,11 +215,56 @@ public class VirtualDeviceManagerService extends SystemService {
final long identity = Binder.clearCallingIdentity();
try {
getContext().sendBroadcastAsUser(i, UserHandle.ALL);
+
+ synchronized (mVirtualDeviceManagerLock) {
+ if (mVirtualDevices.size() == 0) {
+ unregisterCdmAssociationListener();
+ }
+ }
} finally {
Binder.restoreCallingIdentity(identity);
}
}
+ private void syncVirtualDevicesToCdmAssociations(List<AssociationInfo> associations) {
+ Set<VirtualDeviceImpl> virtualDevicesToRemove = new HashSet<>();
+ synchronized (mVirtualDeviceManagerLock) {
+ if (mVirtualDevices.size() == 0) {
+ return;
+ }
+
+ Set<Integer> activeAssociationIds = new HashSet<>(associations.size());
+ for (AssociationInfo association : associations) {
+ activeAssociationIds.add(association.getId());
+ }
+
+ for (int i = 0; i < mVirtualDevices.size(); i++) {
+ VirtualDeviceImpl virtualDevice = mVirtualDevices.valueAt(i);
+ if (!activeAssociationIds.contains(virtualDevice.getAssociationId())) {
+ virtualDevicesToRemove.add(virtualDevice);
+ }
+ }
+ }
+
+ for (VirtualDeviceImpl virtualDevice : virtualDevicesToRemove) {
+ virtualDevice.close();
+ }
+
+ }
+
+ private void registerCdmAssociationListener() {
+ final CompanionDeviceManager cdm = getContext().getSystemService(
+ CompanionDeviceManager.class);
+ cdm.addOnAssociationsChangedListener(getContext().getMainExecutor(),
+ mCdmAssociationListener);
+ }
+
+ private void unregisterCdmAssociationListener() {
+ final CompanionDeviceManager cdm = getContext().getSystemService(
+ CompanionDeviceManager.class);
+ cdm.removeOnAssociationsChangedListener(mCdmAssociationListener);
+ }
+
class VirtualDeviceManagerImpl extends IVirtualDeviceManager.Stub {
private final VirtualDeviceImpl.PendingTrampolineCallback mPendingTrampolineCallback =
@@ -254,7 +310,20 @@ public class VirtualDeviceManagerService extends SystemService {
if (associationInfo == null) {
throw new IllegalArgumentException("No association with ID " + associationId);
}
+ Objects.requireNonNull(params);
+ Objects.requireNonNull(activityListener);
+ Objects.requireNonNull(soundEffectListener);
+
synchronized (mVirtualDeviceManagerLock) {
+ if (mVirtualDevices.size() == 0) {
+ final long callindId = Binder.clearCallingIdentity();
+ try {
+ registerCdmAssociationListener();
+ } finally {
+ Binder.restoreCallingIdentity(callindId);
+ }
+ }
+
final UserHandle userHandle = getCallingUserHandle();
final CameraAccessController cameraAccessController =
getCameraAccessController(userHandle);
@@ -275,6 +344,7 @@ public class VirtualDeviceManagerService extends SystemService {
public int createVirtualDisplay(VirtualDisplayConfig virtualDisplayConfig,
IVirtualDisplayCallback callback, IVirtualDevice virtualDevice, String packageName)
throws RemoteException {
+ Objects.requireNonNull(virtualDisplayConfig);
final int callingUid = getCallingUid();
if (!PermissionUtils.validateCallingPackageName(getContext(), packageName)) {
throw new SecurityException(
diff --git a/services/core/java/com/android/server/display/AutomaticBrightnessController.java b/services/core/java/com/android/server/display/AutomaticBrightnessController.java
index af5609a68952..299f86550efd 100644
--- a/services/core/java/com/android/server/display/AutomaticBrightnessController.java
+++ b/services/core/java/com/android/server/display/AutomaticBrightnessController.java
@@ -75,10 +75,11 @@ public class AutomaticBrightnessController {
private static final int MSG_UPDATE_AMBIENT_LUX = 1;
private static final int MSG_BRIGHTNESS_ADJUSTMENT_SAMPLE = 2;
- private static final int MSG_INVALIDATE_SHORT_TERM_MODEL = 3;
+ private static final int MSG_INVALIDATE_CURRENT_SHORT_TERM_MODEL = 3;
private static final int MSG_UPDATE_FOREGROUND_APP = 4;
private static final int MSG_UPDATE_FOREGROUND_APP_SYNC = 5;
private static final int MSG_RUN_UPDATE = 6;
+ private static final int MSG_INVALIDATE_PAUSED_SHORT_TERM_MODEL = 7;
// Callbacks for requesting updates to the display's power state
private final Callbacks mCallbacks;
@@ -216,12 +217,11 @@ public class AutomaticBrightnessController {
private float mBrightnessAdjustmentSampleOldLux;
private float mBrightnessAdjustmentSampleOldBrightness;
- // When the short term model is invalidated, we don't necessarily reset it (i.e. clear the
- // user's adjustment) immediately, but wait for a drastic enough change in the ambient light.
- // The anchor determines what were the light levels when the user has set their preference, and
- // we use a relative threshold to determine when to revert to the OEM curve.
- private boolean mShortTermModelValid;
- private float mShortTermModelAnchor;
+ // The short term models, current and previous. Eg, we might use the "paused" one to save out
+ // the interactive short term model when switching to idle screen brightness mode, and
+ // vice-versa.
+ private final ShortTermModel mShortTermModel;
+ private final ShortTermModel mPausedShortTermModel;
// Controls High Brightness Mode.
private HighBrightnessModeController mHbmController;
@@ -309,8 +309,8 @@ public class AutomaticBrightnessController {
mAmbientBrightnessThresholdsIdle = ambientBrightnessThresholdsIdle;
mScreenBrightnessThresholds = screenBrightnessThresholds;
mScreenBrightnessThresholdsIdle = screenBrightnessThresholdsIdle;
- mShortTermModelValid = true;
- mShortTermModelAnchor = -1;
+ mShortTermModel = new ShortTermModel();
+ mPausedShortTermModel = new ShortTermModel();
mHandler = new AutomaticBrightnessHandler(looper);
mAmbientLightRingBuffer =
new AmbientLightRingBuffer(mNormalLightSensorRate, mAmbientLightHorizonLong, mClock);
@@ -492,10 +492,10 @@ public class AutomaticBrightnessController {
Slog.d(TAG, "Display policy transitioning from " + oldPolicy + " to " + policy);
}
if (!isInteractivePolicy(policy) && isInteractivePolicy(oldPolicy) && !isInIdleMode()) {
- mHandler.sendEmptyMessageDelayed(MSG_INVALIDATE_SHORT_TERM_MODEL,
+ mHandler.sendEmptyMessageDelayed(MSG_INVALIDATE_CURRENT_SHORT_TERM_MODEL,
mCurrentBrightnessMapper.getShortTermModelTimeout());
} else if (isInteractivePolicy(policy) && !isInteractivePolicy(oldPolicy)) {
- mHandler.removeMessages(MSG_INVALIDATE_SHORT_TERM_MODEL);
+ mHandler.removeMessages(MSG_INVALIDATE_CURRENT_SHORT_TERM_MODEL);
}
return true;
}
@@ -516,25 +516,13 @@ public class AutomaticBrightnessController {
private boolean setScreenBrightnessByUser(float lux, float brightness) {
mCurrentBrightnessMapper.addUserDataPoint(lux, brightness);
- mShortTermModelValid = true;
- mShortTermModelAnchor = lux;
- if (mLoggingEnabled) {
- Slog.d(TAG, "ShortTermModel: anchor=" + mShortTermModelAnchor);
- }
+ mShortTermModel.setUserBrightness(lux, brightness);
return true;
}
public void resetShortTermModel() {
mCurrentBrightnessMapper.clearUserDataPoints();
- mShortTermModelValid = true;
- mShortTermModelAnchor = -1;
- }
-
- private void invalidateShortTermModel() {
- if (mLoggingEnabled) {
- Slog.d(TAG, "ShortTermModel: invalidate user data");
- }
- mShortTermModelValid = false;
+ mShortTermModel.reset();
}
public boolean setBrightnessConfiguration(BrightnessConfiguration configuration,
@@ -595,8 +583,12 @@ public class AutomaticBrightnessController {
pw.println(" mShortTermModelTimeout(idle)="
+ mIdleModeBrightnessMapper.getShortTermModelTimeout());
}
- pw.println(" mShortTermModelAnchor=" + mShortTermModelAnchor);
- pw.println(" mShortTermModelValid=" + mShortTermModelValid);
+ pw.println(" mShortTermModel=");
+ mShortTermModel.dump(pw);
+ pw.println(" mPausedShortTermModel=");
+ mPausedShortTermModel.dump(pw);
+
+ pw.println();
pw.println(" mBrightnessAdjustmentSamplePending=" + mBrightnessAdjustmentSamplePending);
pw.println(" mBrightnessAdjustmentSampleOldLux=" + mBrightnessAdjustmentSampleOldLux);
pw.println(" mBrightnessAdjustmentSampleOldBrightness="
@@ -740,15 +732,9 @@ public class AutomaticBrightnessController {
}
mHbmController.onAmbientLuxChange(mAmbientLux);
+
// If the short term model was invalidated and the change is drastic enough, reset it.
- if (!mShortTermModelValid && mShortTermModelAnchor != -1) {
- if (mCurrentBrightnessMapper.shouldResetShortTermModel(
- mAmbientLux, mShortTermModelAnchor)) {
- resetShortTermModel();
- } else {
- mShortTermModelValid = true;
- }
- }
+ mShortTermModel.maybeReset(mAmbientLux);
}
private float calculateAmbientLux(long now, long horizon) {
@@ -1118,8 +1104,29 @@ public class AutomaticBrightnessController {
return;
}
Slog.i(TAG, "Switching to Idle Screen Brightness Mode");
+ // Stash short term model
+ ShortTermModel tempShortTermModel = new ShortTermModel();
+ tempShortTermModel.set(mCurrentBrightnessMapper.getUserLux(),
+ mCurrentBrightnessMapper.getUserBrightness(), /* valid= */ true);
+
+ // Send delayed timeout
+ mHandler.sendEmptyMessageAtTime(MSG_INVALIDATE_PAUSED_SHORT_TERM_MODEL,
+ mClock.uptimeMillis()
+ + mCurrentBrightnessMapper.getShortTermModelTimeout());
+
+ Slog.i(TAG, "mPreviousShortTermModel" + mPausedShortTermModel);
+ // new brightness mapper
mCurrentBrightnessMapper = mIdleModeBrightnessMapper;
- resetShortTermModel();
+
+ // if previous stm has been invalidated, and lux has drastically changed, just use
+ // the new, reset stm.
+ // if previous stm is still valid then revalidate it
+ if (mPausedShortTermModel != null && !mPausedShortTermModel.maybeReset(mAmbientLux)) {
+ setScreenBrightnessByUser(mPausedShortTermModel.mAnchor,
+ mPausedShortTermModel.mBrightness);
+ }
+ mPausedShortTermModel.copyFrom(tempShortTermModel);
+
update();
}
@@ -1128,8 +1135,28 @@ public class AutomaticBrightnessController {
return;
}
Slog.i(TAG, "Switching to Interactive Screen Brightness Mode");
+ ShortTermModel tempShortTermModel = new ShortTermModel();
+ tempShortTermModel.set(mCurrentBrightnessMapper.getUserLux(),
+ mCurrentBrightnessMapper.getUserBrightness(), /* valid= */ true);
+ mHandler.removeMessages(MSG_INVALIDATE_PAUSED_SHORT_TERM_MODEL);
+ // Send delayed timeout
+ mHandler.sendEmptyMessageAtTime(MSG_INVALIDATE_PAUSED_SHORT_TERM_MODEL,
+ mClock.uptimeMillis()
+ + mCurrentBrightnessMapper.getShortTermModelTimeout());
+ Slog.i(TAG, "mPreviousShortTermModel" + mPausedShortTermModel.toString());
+
+ // restore interactive mapper.
mCurrentBrightnessMapper = mInteractiveModeBrightnessMapper;
- resetShortTermModel();
+
+ // if previous stm has been invalidated, and lux has drastically changed, just use
+ // the new, reset stm.
+ // if previous stm is still valid then revalidate it
+ if (!mPausedShortTermModel.maybeReset(mAmbientLux)) {
+ setScreenBrightnessByUser(mPausedShortTermModel.mAnchor,
+ mPausedShortTermModel.mBrightness);
+ }
+ mPausedShortTermModel.copyFrom(tempShortTermModel);
+
update();
}
@@ -1164,6 +1191,77 @@ public class AutomaticBrightnessController {
}
}
+ private class ShortTermModel {
+ // When the short term model is invalidated, we don't necessarily reset it (i.e. clear the
+ // user's adjustment) immediately, but wait for a drastic enough change in the ambient
+ // light.
+ // The anchor determines what were the light levels when the user has set their preference,
+ // and we use a relative threshold to determine when to revert to the OEM curve.
+ private float mAnchor = -1f;
+ private float mBrightness;
+ private boolean mIsValid = true;
+
+ private void reset() {
+ mAnchor = -1f;
+ mBrightness = -1f;
+ mIsValid = true;
+ }
+
+ private void invalidate() {
+ mIsValid = false;
+ if (mLoggingEnabled) {
+ Slog.d(TAG, "ShortTermModel: invalidate user data");
+ }
+ }
+
+ private void setUserBrightness(float lux, float brightness) {
+ mAnchor = lux;
+ mBrightness = brightness;
+ mIsValid = true;
+ if (mLoggingEnabled) {
+ Slog.d(TAG, "ShortTermModel: anchor=" + mAnchor);
+ }
+ }
+
+ private boolean maybeReset(float currentLux) {
+ // If the short term model was invalidated and the change is drastic enough, reset it.
+ // Otherwise, we revalidate it.
+ if (!mIsValid && mAnchor != -1) {
+ if (mCurrentBrightnessMapper != null
+ && mCurrentBrightnessMapper.shouldResetShortTermModel(
+ currentLux, mAnchor)) {
+ resetShortTermModel();
+ } else {
+ mIsValid = true;
+ }
+ return mIsValid;
+ }
+ return false;
+ }
+
+ private void set(float anchor, float brightness, boolean valid) {
+ mAnchor = anchor;
+ mBrightness = brightness;
+ mIsValid = valid;
+ }
+ private void copyFrom(ShortTermModel from) {
+ mAnchor = from.mAnchor;
+ mBrightness = from.mBrightness;
+ mIsValid = from.mIsValid;
+ }
+
+ public String toString() {
+ return " mAnchor: " + mAnchor
+ + "\n mBrightness: " + mBrightness
+ + "\n mIsValid: " + mIsValid;
+ }
+
+ void dump(PrintWriter pw) {
+ pw.println(this);
+ }
+
+ }
+
private final class AutomaticBrightnessHandler extends Handler {
public AutomaticBrightnessHandler(Looper looper) {
super(looper, null, true /*async*/);
@@ -1184,8 +1282,8 @@ public class AutomaticBrightnessController {
collectBrightnessAdjustmentSample();
break;
- case MSG_INVALIDATE_SHORT_TERM_MODEL:
- invalidateShortTermModel();
+ case MSG_INVALIDATE_CURRENT_SHORT_TERM_MODEL:
+ mShortTermModel.invalidate();
break;
case MSG_UPDATE_FOREGROUND_APP:
@@ -1195,6 +1293,10 @@ public class AutomaticBrightnessController {
case MSG_UPDATE_FOREGROUND_APP_SYNC:
updateForegroundAppSync();
break;
+
+ case MSG_INVALIDATE_PAUSED_SHORT_TERM_MODEL:
+ mPausedShortTermModel.invalidate();
+ break;
}
}
}
diff --git a/services/core/java/com/android/server/display/BrightnessMappingStrategy.java b/services/core/java/com/android/server/display/BrightnessMappingStrategy.java
index d0471837d79b..3456e3e262de 100644
--- a/services/core/java/com/android/server/display/BrightnessMappingStrategy.java
+++ b/services/core/java/com/android/server/display/BrightnessMappingStrategy.java
@@ -363,13 +363,17 @@ public abstract class BrightnessMappingStrategy {
public abstract void recalculateSplines(boolean applyAdjustment, float[] adjustment);
/**
- * Returns the timeout for the short term model
+ * Returns the timeout, in milliseconds for the short term model
*
* Timeout after which we remove the effects any user interactions might've had on the
* brightness mapping. This timeout doesn't start until we transition to a non-interactive
* display policy so that we don't reset while users are using their devices, but also so that
* we don't erroneously keep the short-term model if the device is dozing but the
* display is fully on.
+ *
+ * This timeout is also used when the device switches from interactive screen brightness mode
+ * to idle screen brightness mode, to preserve the user's preference when they resume usage of
+ * the device, within the specified timeframe.
*/
public abstract long getShortTermModelTimeout();
diff --git a/services/core/java/com/android/server/display/BrightnessThrottler.java b/services/core/java/com/android/server/display/BrightnessThrottler.java
index eccee52f37aa..067a2d6d8b0d 100644
--- a/services/core/java/com/android/server/display/BrightnessThrottler.java
+++ b/services/core/java/com/android/server/display/BrightnessThrottler.java
@@ -16,7 +16,10 @@
package com.android.server.display;
+import static com.android.server.display.DisplayDeviceConfig.DEFAULT_ID;
+
import android.annotation.NonNull;
+import android.annotation.Nullable;
import android.content.Context;
import android.hardware.display.BrightnessInfo;
import android.hardware.display.DisplayManager;
@@ -63,8 +66,16 @@ class BrightnessThrottler {
private final DeviceConfigInterface mDeviceConfig;
private int mThrottlingStatus;
+
+ // Maps the throttling ID to the data. Sourced from DisplayDeviceConfig.
+ @NonNull
+ private HashMap<String, BrightnessThrottlingData> mDdcThrottlingDataMap;
+
+ // Current throttling data being used.
+ // Null if we do not support throttling.
+ @Nullable
private BrightnessThrottlingData mThrottlingData;
- private BrightnessThrottlingData mDdcThrottlingData;
+
private float mBrightnessCap = PowerManager.BRIGHTNESS_MAX;
private @BrightnessInfo.BrightnessMaxReason int mBrightnessMaxReason =
BrightnessInfo.BRIGHTNESS_MAX_REASON_NONE;
@@ -73,35 +84,45 @@ class BrightnessThrottler {
// The most recent string that has been set from DeviceConfig
private String mBrightnessThrottlingDataString;
+ // The brightness throttling configuration that should be used.
+ private String mBrightnessThrottlingDataId;
+
// This is a collection of brightness throttling data that has been written as overrides from
// the DeviceConfig. This will always take priority over the display device config data.
- private HashMap<String, BrightnessThrottlingData> mBrightnessThrottlingDataOverride =
- new HashMap<>(1);
-
- BrightnessThrottler(Handler handler, BrightnessThrottlingData throttlingData,
- Runnable throttlingChangeCallback, String uniqueDisplayId) {
- this(new Injector(), handler, handler, throttlingData, throttlingChangeCallback,
- uniqueDisplayId);
+ // We need to store the data for every display device, so we do not need to update this each
+ // time the underlying display device changes.
+ // This map is indexed by uniqueDisplayId, to provide maps for throttlingId -> throttlingData.
+ // HashMap< uniqueDisplayId, HashMap< throttlingDataId, BrightnessThrottlingData >>
+ private final HashMap<String, HashMap<String, BrightnessThrottlingData>>
+ mBrightnessThrottlingDataOverride = new HashMap<>(1);
+
+ BrightnessThrottler(Handler handler, Runnable throttlingChangeCallback, String uniqueDisplayId,
+ String throttlingDataId,
+ @NonNull HashMap<String, BrightnessThrottlingData> brightnessThrottlingDataMap) {
+ this(new Injector(), handler, handler, throttlingChangeCallback,
+ uniqueDisplayId, throttlingDataId, brightnessThrottlingDataMap);
}
@VisibleForTesting
BrightnessThrottler(Injector injector, Handler handler, Handler deviceConfigHandler,
- BrightnessThrottlingData throttlingData, Runnable throttlingChangeCallback,
- String uniqueDisplayId) {
+ Runnable throttlingChangeCallback, String uniqueDisplayId, String throttlingDataId,
+ @NonNull HashMap<String, BrightnessThrottlingData> brightnessThrottlingDataMap) {
mInjector = injector;
mHandler = handler;
mDeviceConfigHandler = deviceConfigHandler;
- mThrottlingData = throttlingData;
- mDdcThrottlingData = throttlingData;
+ mDdcThrottlingDataMap = brightnessThrottlingDataMap;
mThrottlingChangeCallback = throttlingChangeCallback;
mSkinThermalStatusObserver = new SkinThermalStatusObserver(mInjector, mHandler);
mUniqueDisplayId = uniqueDisplayId;
mDeviceConfig = injector.getDeviceConfig();
mDeviceConfigListener = new DeviceConfigListener();
-
- resetThrottlingData(mThrottlingData, mUniqueDisplayId);
+ mBrightnessThrottlingDataId = throttlingDataId;
+ mDdcThrottlingDataMap = brightnessThrottlingDataMap;
+ loadBrightnessThrottlingDataFromDeviceConfig();
+ loadBrightnessThrottlingDataFromDisplayDeviceConfig(mDdcThrottlingDataMap,
+ mBrightnessThrottlingDataId, mUniqueDisplayId);
}
boolean deviceSupportsThrottling() {
@@ -133,23 +154,14 @@ class BrightnessThrottler {
mThrottlingStatus = THROTTLING_INVALID;
}
- private void resetThrottlingData() {
- resetThrottlingData(mDdcThrottlingData, mUniqueDisplayId);
- }
-
- void resetThrottlingData(BrightnessThrottlingData throttlingData, String displayId) {
- stop();
-
- mUniqueDisplayId = displayId;
- mDdcThrottlingData = throttlingData;
- mDeviceConfigListener.startListening();
- reloadBrightnessThrottlingDataOverride();
- mThrottlingData = mBrightnessThrottlingDataOverride.getOrDefault(mUniqueDisplayId,
- throttlingData);
-
- if (deviceSupportsThrottling()) {
- mSkinThermalStatusObserver.startObserving();
- }
+ void loadBrightnessThrottlingDataFromDisplayDeviceConfig(
+ HashMap<String, BrightnessThrottlingData> ddcThrottlingDataMap,
+ String brightnessThrottlingDataId,
+ String uniqueDisplayId) {
+ mDdcThrottlingDataMap = ddcThrottlingDataMap;
+ mBrightnessThrottlingDataId = brightnessThrottlingDataId;
+ mUniqueDisplayId = uniqueDisplayId;
+ resetThrottlingData();
}
private float verifyAndConstrainBrightnessCap(float brightness) {
@@ -183,7 +195,7 @@ class BrightnessThrottler {
float brightnessCap = PowerManager.BRIGHTNESS_MAX;
int brightnessMaxReason = BrightnessInfo.BRIGHTNESS_MAX_REASON_NONE;
- if (mThrottlingStatus != THROTTLING_INVALID) {
+ if (mThrottlingStatus != THROTTLING_INVALID && mThrottlingData != null) {
// Throttling levels are sorted by increasing severity
for (ThrottlingLevel level : mThrottlingData.throttlingLevels) {
if (level.thermalStatus <= mThrottlingStatus) {
@@ -218,13 +230,14 @@ class BrightnessThrottler {
private void dumpLocal(PrintWriter pw) {
pw.println("BrightnessThrottler:");
+ pw.println(" mBrightnessThrottlingDataId=" + mBrightnessThrottlingDataId);
pw.println(" mThrottlingData=" + mThrottlingData);
- pw.println(" mDdcThrottlingData=" + mDdcThrottlingData);
pw.println(" mUniqueDisplayId=" + mUniqueDisplayId);
pw.println(" mThrottlingStatus=" + mThrottlingStatus);
pw.println(" mBrightnessCap=" + mBrightnessCap);
pw.println(" mBrightnessMaxReason=" +
BrightnessInfo.briMaxReasonToString(mBrightnessMaxReason));
+ pw.println(" mDdcThrottlingDataMap=" + mDdcThrottlingDataMap);
pw.println(" mBrightnessThrottlingDataOverride=" + mBrightnessThrottlingDataOverride);
pw.println(" mBrightnessThrottlingDataString=" + mBrightnessThrottlingDataString);
@@ -237,8 +250,18 @@ class BrightnessThrottler {
/* defaultValue= */ null);
}
- private boolean parseAndSaveData(@NonNull String strArray,
- @NonNull HashMap<String, BrightnessThrottlingData> tempBrightnessThrottlingData) {
+ // The brightness throttling data id may or may not be specified in the string that is passed
+ // in, if there is none specified, we assume it is for the default case. Each string passed in
+ // here must be for one display and one throttling id.
+ // 123,1,critical,0.8
+ // 456,2,moderate,0.9,critical,0.7
+ // 456,2,moderate,0.9,critical,0.7,default
+ // 456,2,moderate,0.9,critical,0.7,id_2
+ // displayId, number, <state, val> * number
+ // displayId, <number, <state, val> * number>, throttlingId
+ private boolean parseAndAddData(@NonNull String strArray,
+ @NonNull HashMap<String, HashMap<String, BrightnessThrottlingData>>
+ displayIdToThrottlingIdToBtd) {
boolean validConfig = true;
String[] items = strArray.split(",");
int i = 0;
@@ -254,29 +277,42 @@ class BrightnessThrottler {
for (int j = 0; j < noOfThrottlingPoints; j++) {
String severity = items[i++];
int status = parseThermalStatus(severity);
-
float brightnessPoint = parseBrightness(items[i++]);
-
throttlingLevels.add(new ThrottlingLevel(status, brightnessPoint));
}
- BrightnessThrottlingData toSave =
+
+ String throttlingDataId = (i < items.length) ? items[i++] : DEFAULT_ID;
+ BrightnessThrottlingData throttlingLevelsData =
DisplayDeviceConfig.BrightnessThrottlingData.create(throttlingLevels);
- tempBrightnessThrottlingData.put(uniqueDisplayId, toSave);
+
+ // Add throttlingLevelsData to inner map where necessary.
+ HashMap<String, BrightnessThrottlingData> throttlingMapForDisplay =
+ displayIdToThrottlingIdToBtd.get(uniqueDisplayId);
+ if (throttlingMapForDisplay == null) {
+ throttlingMapForDisplay = new HashMap<>();
+ throttlingMapForDisplay.put(throttlingDataId, throttlingLevelsData);
+ displayIdToThrottlingIdToBtd.put(uniqueDisplayId, throttlingMapForDisplay);
+ } else if (throttlingMapForDisplay.containsKey(throttlingDataId)) {
+ Slog.e(TAG, "Throttling data for display " + uniqueDisplayId
+ + "contains duplicate throttling ids: '" + throttlingDataId + "'");
+ return false;
+ } else {
+ throttlingMapForDisplay.put(throttlingDataId, throttlingLevelsData);
+ }
} catch (NumberFormatException | IndexOutOfBoundsException
| UnknownThermalStatusException e) {
- validConfig = false;
Slog.e(TAG, "Throttling data is invalid array: '" + strArray + "'", e);
+ validConfig = false;
}
if (i != items.length) {
validConfig = false;
}
-
return validConfig;
}
- public void reloadBrightnessThrottlingDataOverride() {
- HashMap<String, BrightnessThrottlingData> tempBrightnessThrottlingData =
+ private void loadBrightnessThrottlingDataFromDeviceConfig() {
+ HashMap<String, HashMap<String, BrightnessThrottlingData>> tempThrottlingData =
new HashMap<>(1);
mBrightnessThrottlingDataString = getBrightnessThrottlingDataString();
boolean validConfig = true;
@@ -284,15 +320,15 @@ class BrightnessThrottler {
if (mBrightnessThrottlingDataString != null) {
String[] throttlingDataSplits = mBrightnessThrottlingDataString.split(";");
for (String s : throttlingDataSplits) {
- if (!parseAndSaveData(s, tempBrightnessThrottlingData)) {
+ if (!parseAndAddData(s, tempThrottlingData)) {
validConfig = false;
break;
}
}
if (validConfig) {
- mBrightnessThrottlingDataOverride.putAll(tempBrightnessThrottlingData);
- tempBrightnessThrottlingData.clear();
+ mBrightnessThrottlingDataOverride.putAll(tempThrottlingData);
+ tempThrottlingData.clear();
}
} else {
@@ -300,15 +336,50 @@ class BrightnessThrottler {
}
}
+ private void resetThrottlingData() {
+ stop();
+
+ mDeviceConfigListener.startListening();
+
+ // Get throttling data for this id, if it exists
+ mThrottlingData = getConfigFromId(mBrightnessThrottlingDataId);
+
+ // Fallback to default id otherwise.
+ if (!DEFAULT_ID.equals(mBrightnessThrottlingDataId) && mThrottlingData == null) {
+ mThrottlingData = getConfigFromId(DEFAULT_ID);
+ Slog.d(TAG, "Falling back to default throttling Id");
+ }
+
+ if (deviceSupportsThrottling()) {
+ mSkinThermalStatusObserver.startObserving();
+ }
+ }
+
+ private BrightnessThrottlingData getConfigFromId(String id) {
+ BrightnessThrottlingData returnValue;
+
+ // Fallback pattern for fetching correct throttling data for this display and id.
+ // 1) throttling data from device config for this throttling data id
+ returnValue = mBrightnessThrottlingDataOverride.get(mUniqueDisplayId) == null
+ ? null
+ : mBrightnessThrottlingDataOverride.get(mUniqueDisplayId).get(id);
+ // 2) throttling data from ddc for this throttling data id
+ returnValue = returnValue == null
+ ? mDdcThrottlingDataMap.get(id)
+ : returnValue;
+
+ return returnValue;
+ }
+
/**
* Listens to config data change and updates the brightness throttling data using
* DisplayManager#KEY_BRIGHTNESS_THROTTLING_DATA.
* The format should be a string similar to: "local:4619827677550801152,2,moderate,0.5,severe,
* 0.379518072;local:4619827677550801151,1,moderate,0.75"
* In this order:
- * <displayId>,<no of throttling levels>,[<severity as string>,<brightness cap>]
- * Where the latter part is repeated for each throttling level, and the entirety is repeated
- * for each display, separated by a semicolon.
+ * <displayId>,<no of throttling levels>,[<severity as string>,<brightness cap>][,throttlingId]?
+ * Where [<severity as string>,<brightness cap>] is repeated for each throttling level, and the
+ * entirety is repeated for each display & throttling data id, separated by a semicolon.
*/
public class DeviceConfigListener implements DeviceConfig.OnPropertiesChangedListener {
public Executor mExecutor = new HandlerExecutor(mDeviceConfigHandler);
@@ -320,7 +391,7 @@ class BrightnessThrottler {
@Override
public void onPropertiesChanged(DeviceConfig.Properties properties) {
- reloadBrightnessThrottlingDataOverride();
+ loadBrightnessThrottlingDataFromDeviceConfig();
resetThrottlingData();
}
}
diff --git a/services/core/java/com/android/server/display/DisplayDeviceConfig.java b/services/core/java/com/android/server/display/DisplayDeviceConfig.java
index f4b3f1ab7b11..da021158eb65 100644
--- a/services/core/java/com/android/server/display/DisplayDeviceConfig.java
+++ b/services/core/java/com/android/server/display/DisplayDeviceConfig.java
@@ -143,17 +143,17 @@ import javax.xml.datatype.DatatypeConfigurationException;
* <brightness>0.01</brightness>
* </brightnessThrottlingPoint>
* </brightnessThrottlingMap>
- * <concurrentDisplaysBrightnessThrottlingMap>
- * <brightnessThrottlingPoint>
- * <thermalStatus>severe</thermalStatus>
- * <brightness>0.07</brightness>
- * </brightnessThrottlingPoint>
- * <brightnessThrottlingPoint>
- * <thermalStatus>critical</thermalStatus>
- * <brightness>0.005</brightness>
- * </brightnessThrottlingPoint>
- * </concurrentDisplaysBrightnessThrottlingMap>
- * <refreshRateThrottlingMap>
+ * <brightnessThrottlingMap id="id_2"> // optional attribute, leave blank for default
+ * <brightnessThrottlingPoint>
+ * <thermalStatus>moderate</thermalStatus>
+ * <brightness>0.2</brightness>
+ * </brightnessThrottlingPoint>
+ * <brightnessThrottlingPoint>
+ * <thermalStatus>severe</thermalStatus>
+ * <brightness>0.1</brightness>
+ * </brightnessThrottlingPoint>
+ * </brightnessThrottlingMap>
+ <refreshRateThrottlingMap>
* <refreshRateThrottlingPoint>
* <thermalStatus>critical</thermalStatus>
* <refreshRateRange>
@@ -687,8 +687,8 @@ public class DisplayDeviceConfig {
private int[] mHighDisplayBrightnessThresholds = DEFAULT_BRIGHTNESS_THRESHOLDS;
private int[] mHighAmbientBrightnessThresholds = DEFAULT_BRIGHTNESS_THRESHOLDS;
- private final Map<String, BrightnessThrottlingData> mBrightnessThrottlingDataMap =
- new HashMap<>();
+ private final HashMap<String, BrightnessThrottlingData>
+ mBrightnessThrottlingDataMapByThrottlingId = new HashMap<>();
private final Map<String, SparseArray<SurfaceControl.RefreshRateRange>>
mRefreshRateThrottlingMap = new HashMap<>();
@@ -1346,11 +1346,11 @@ public class DisplayDeviceConfig {
}
/**
- * @param id The ID of the throttling data
- * @return brightness throttling configuration data for the display.
+ * @return brightness throttling configuration data for this display, for each throttling id.
*/
- public BrightnessThrottlingData getBrightnessThrottlingData(String id) {
- return BrightnessThrottlingData.create(mBrightnessThrottlingDataMap.get(id));
+ public HashMap<String, BrightnessThrottlingData>
+ getBrightnessThrottlingDataMapByThrottlingId() {
+ return mBrightnessThrottlingDataMapByThrottlingId;
}
/**
@@ -1525,7 +1525,8 @@ public class DisplayDeviceConfig {
+ ", isHbmEnabled=" + mIsHighBrightnessModeEnabled
+ ", mHbmData=" + mHbmData
+ ", mSdrToHdrRatioSpline=" + mSdrToHdrRatioSpline
- + ", mBrightnessThrottlingData=" + mBrightnessThrottlingDataMap
+ + ", mBrightnessThrottlingDataMapByThrottlingId="
+ + mBrightnessThrottlingDataMapByThrottlingId
+ "\n"
+ ", mBrightnessRampFastDecrease=" + mBrightnessRampFastDecrease
+ ", mBrightnessRampFastIncrease=" + mBrightnessRampFastIncrease
@@ -1918,11 +1919,11 @@ public class DisplayDeviceConfig {
if (!badConfig) {
String id = map.getId() == null ? DEFAULT_ID
: map.getId();
- if (mBrightnessThrottlingDataMap.containsKey(id)) {
+ if (mBrightnessThrottlingDataMapByThrottlingId.containsKey(id)) {
throw new RuntimeException("Brightness throttling data with ID " + id
+ " already exists");
}
- mBrightnessThrottlingDataMap.put(id,
+ mBrightnessThrottlingDataMapByThrottlingId.put(id,
BrightnessThrottlingData.create(throttlingLevels));
}
}
@@ -1971,8 +1972,8 @@ public class DisplayDeviceConfig {
));
}
if (refreshRates.size() == 0) {
- Slog.w(TAG, "RefreshRateThrottling: no valid throttling points fond for map, mapId="
- + id);
+ Slog.w(TAG, "RefreshRateThrottling: no valid throttling points found for map, "
+ + "mapId=" + id);
continue;
}
mRefreshRateThrottlingMap.put(id, refreshRates);
@@ -3077,7 +3078,7 @@ public class DisplayDeviceConfig {
/**
- * Creates multiple teperature based throttling levels of brightness
+ * Creates multiple temperature based throttling levels of brightness
*/
public static BrightnessThrottlingData create(List<ThrottlingLevel> throttlingLevels) {
if (throttlingLevels == null || throttlingLevels.size() == 0) {
@@ -3120,15 +3121,6 @@ public class DisplayDeviceConfig {
return new BrightnessThrottlingData(throttlingLevels);
}
- static public BrightnessThrottlingData create(BrightnessThrottlingData other) {
- if (other == null) {
- return null;
- }
-
- return BrightnessThrottlingData.create(other.throttlingLevels);
- }
-
-
@Override
public String toString() {
return "BrightnessThrottlingData{"
diff --git a/services/core/java/com/android/server/display/DisplayPowerController.java b/services/core/java/com/android/server/display/DisplayPowerController.java
index f5859eed34f1..2322e03d6d37 100644
--- a/services/core/java/com/android/server/display/DisplayPowerController.java
+++ b/services/core/java/com/android/server/display/DisplayPowerController.java
@@ -505,7 +505,7 @@ final class DisplayPowerController implements AutomaticBrightnessController.Call
private DisplayDeviceConfig mDisplayDeviceConfig;
- // Identifiers for suspend blocker acuisition requests
+ // Identifiers for suspend blocker acquisition requests
private final String mSuspendBlockerIdUnfinishedBusiness;
private final String mSuspendBlockerIdOnStateChanged;
private final String mSuspendBlockerIdProxPositive;
@@ -515,6 +515,7 @@ final class DisplayPowerController implements AutomaticBrightnessController.Call
private boolean mIsEnabled;
private boolean mIsInTransition;
+ // The id of the brightness throttling policy that should be used.
private String mBrightnessThrottlingDataId;
// DPCs following the brightness of this DPC. This is used in concurrent displays mode - there
@@ -905,14 +906,15 @@ final class DisplayPowerController implements AutomaticBrightnessController.Call
loadNitBasedBrightnessSetting();
/// Since the underlying display-device changed, we really don't know the
- // last command that was sent to change it's state. Lets assume it is unknown so
+ // last command that was sent to change it's state. Let's assume it is unknown so
// that we trigger a change immediately.
mPowerState.resetScreenState();
} else if (!mBrightnessThrottlingDataId.equals(brightnessThrottlingDataId)) {
changed = true;
mBrightnessThrottlingDataId = brightnessThrottlingDataId;
- mBrightnessThrottler.resetThrottlingData(
- config.getBrightnessThrottlingData(mBrightnessThrottlingDataId),
+ mBrightnessThrottler.loadBrightnessThrottlingDataFromDisplayDeviceConfig(
+ config.getBrightnessThrottlingDataMapByThrottlingId(),
+ mBrightnessThrottlingDataId,
mUniqueDisplayId);
}
if (mIsEnabled != isEnabled || mIsInTransition != isInTransition) {
@@ -981,9 +983,9 @@ final class DisplayPowerController implements AutomaticBrightnessController.Call
sdrBrightness, maxDesiredHdrSdrRatio);
}
});
- mBrightnessThrottler.resetThrottlingData(
- mDisplayDeviceConfig.getBrightnessThrottlingData(mBrightnessThrottlingDataId),
- mUniqueDisplayId);
+ mBrightnessThrottler.loadBrightnessThrottlingDataFromDisplayDeviceConfig(
+ mDisplayDeviceConfig.getBrightnessThrottlingDataMapByThrottlingId(),
+ mBrightnessThrottlingDataId, mUniqueDisplayId);
}
private void sendUpdatePowerState() {
@@ -2116,11 +2118,11 @@ final class DisplayPowerController implements AutomaticBrightnessController.Call
final DisplayDevice device = mLogicalDisplay.getPrimaryDisplayDeviceLocked();
final DisplayDeviceConfig ddConfig = device.getDisplayDeviceConfig();
return new BrightnessThrottler(mHandler,
- ddConfig.getBrightnessThrottlingData(mBrightnessThrottlingDataId),
() -> {
sendUpdatePowerState();
postBrightnessChangeRunnable();
- }, mUniqueDisplayId);
+ }, mUniqueDisplayId, mLogicalDisplay.getBrightnessThrottlingDataIdLocked(),
+ ddConfig.getBrightnessThrottlingDataMapByThrottlingId());
}
private void blockScreenOn() {
diff --git a/services/core/java/com/android/server/display/DisplayPowerController2.java b/services/core/java/com/android/server/display/DisplayPowerController2.java
index 8ce4b66eba28..d2af88b1c6c9 100644
--- a/services/core/java/com/android/server/display/DisplayPowerController2.java
+++ b/services/core/java/com/android/server/display/DisplayPowerController2.java
@@ -400,6 +400,7 @@ final class DisplayPowerController2 implements AutomaticBrightnessController.Cal
private boolean mIsEnabled;
private boolean mIsInTransition;
+ // The id of the brightness throttling policy that should be used.
private String mBrightnessThrottlingDataId;
// DPCs following the brightness of this DPC. This is used in concurrent displays mode - there
@@ -722,14 +723,15 @@ final class DisplayPowerController2 implements AutomaticBrightnessController.Cal
mDisplayPowerProximityStateController.notifyDisplayDeviceChanged(config);
// Since the underlying display-device changed, we really don't know the
- // last command that was sent to change it's state. Lets assume it is unknown so
+ // last command that was sent to change it's state. Let's assume it is unknown so
// that we trigger a change immediately.
mPowerState.resetScreenState();
} else if (!mBrightnessThrottlingDataId.equals(brightnessThrottlingDataId)) {
changed = true;
mBrightnessThrottlingDataId = brightnessThrottlingDataId;
- mBrightnessThrottler.resetThrottlingData(
- config.getBrightnessThrottlingData(mBrightnessThrottlingDataId),
+ mBrightnessThrottler.loadBrightnessThrottlingDataFromDisplayDeviceConfig(
+ config.getBrightnessThrottlingDataMapByThrottlingId(),
+ mBrightnessThrottlingDataId,
mUniqueDisplayId);
}
if (mIsEnabled != isEnabled || mIsInTransition != isInTransition) {
@@ -795,9 +797,9 @@ final class DisplayPowerController2 implements AutomaticBrightnessController.Cal
sdrBrightness, maxDesiredHdrSdrRatio);
}
});
- mBrightnessThrottler.resetThrottlingData(
- mDisplayDeviceConfig.getBrightnessThrottlingData(mBrightnessThrottlingDataId),
- mUniqueDisplayId);
+ mBrightnessThrottler.loadBrightnessThrottlingDataFromDisplayDeviceConfig(
+ mDisplayDeviceConfig.getBrightnessThrottlingDataMapByThrottlingId(),
+ mBrightnessThrottlingDataId, mUniqueDisplayId);
}
private void sendUpdatePowerState() {
@@ -1757,11 +1759,11 @@ final class DisplayPowerController2 implements AutomaticBrightnessController.Cal
final DisplayDevice device = mLogicalDisplay.getPrimaryDisplayDeviceLocked();
final DisplayDeviceConfig ddConfig = device.getDisplayDeviceConfig();
return new BrightnessThrottler(mHandler,
- ddConfig.getBrightnessThrottlingData(mBrightnessThrottlingDataId),
() -> {
sendUpdatePowerState();
postBrightnessChangeRunnable();
- }, mUniqueDisplayId);
+ }, mUniqueDisplayId, mLogicalDisplay.getBrightnessThrottlingDataIdLocked(),
+ ddConfig.getBrightnessThrottlingDataMapByThrottlingId());
}
private void blockScreenOn() {
diff --git a/services/core/java/com/android/server/display/layout/Layout.java b/services/core/java/com/android/server/display/layout/Layout.java
index f86ee249408c..634f31d6268c 100644
--- a/services/core/java/com/android/server/display/layout/Layout.java
+++ b/services/core/java/com/android/server/display/layout/Layout.java
@@ -338,7 +338,9 @@ public class Layout {
}
/**
- * @return The ID of the brightness throttling map that this display should use.
+ * Gets the id of the brightness throttling map that should be used.
+ * @return The ID of the brightness throttling map that this display should use, null if
+ * unspecified, will fall back to default.
*/
public String getBrightnessThrottlingMapId() {
return mBrightnessThrottlingMapId;
diff --git a/services/core/java/com/android/server/notification/NotificationManagerService.java b/services/core/java/com/android/server/notification/NotificationManagerService.java
index 81cca50a4d29..87070595f172 100755
--- a/services/core/java/com/android/server/notification/NotificationManagerService.java
+++ b/services/core/java/com/android/server/notification/NotificationManagerService.java
@@ -6625,20 +6625,15 @@ public class NotificationManagerService extends SystemService {
|| r.getImportance() == IMPORTANCE_NONE)) {
// Increase the importance of foreground service notifications unless the user had
// an opinion otherwise (and the channel hasn't yet shown a fg service).
- if (TextUtils.isEmpty(channelId)
- || NotificationChannel.DEFAULT_CHANNEL_ID.equals(channelId)) {
- r.setSystemImportance(IMPORTANCE_LOW);
- } else {
- channel.setImportance(IMPORTANCE_LOW);
- r.setSystemImportance(IMPORTANCE_LOW);
- if (!fgServiceShown) {
- channel.unlockFields(NotificationChannel.USER_LOCKED_IMPORTANCE);
- channel.setFgServiceShown(true);
- }
- mPreferencesHelper.updateNotificationChannel(
- pkg, notificationUid, channel, false);
- r.updateNotificationChannel(channel);
- }
+ channel.setImportance(IMPORTANCE_LOW);
+ r.setSystemImportance(IMPORTANCE_LOW);
+ if (!fgServiceShown) {
+ channel.unlockFields(NotificationChannel.USER_LOCKED_IMPORTANCE);
+ channel.setFgServiceShown(true);
+ }
+ mPreferencesHelper.updateNotificationChannel(
+ pkg, notificationUid, channel, false);
+ r.updateNotificationChannel(channel);
} else if (!fgServiceShown && !TextUtils.isEmpty(channelId)
&& !NotificationChannel.DEFAULT_CHANNEL_ID.equals(channelId)) {
channel.setFgServiceShown(true);
diff --git a/services/core/java/com/android/server/wm/ActivityRecord.java b/services/core/java/com/android/server/wm/ActivityRecord.java
index 5f56923e2f53..8346e7c83190 100644
--- a/services/core/java/com/android/server/wm/ActivityRecord.java
+++ b/services/core/java/com/android/server/wm/ActivityRecord.java
@@ -4068,7 +4068,7 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A
}
void finishRelaunching() {
- mLetterboxUiController.setRelauchingAfterRequestedOrientationChanged(false);
+ mLetterboxUiController.setRelaunchingAfterRequestedOrientationChanged(false);
mTaskSupervisor.getActivityMetricsLogger().notifyActivityRelaunched(this);
if (mPendingRelaunchCount > 0) {
@@ -9500,7 +9500,7 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A
mRelaunchReason = RELAUNCH_REASON_NONE;
}
if (isRequestedOrientationChanged) {
- mLetterboxUiController.setRelauchingAfterRequestedOrientationChanged(true);
+ mLetterboxUiController.setRelaunchingAfterRequestedOrientationChanged(true);
}
if (mState == PAUSING) {
// A little annoying: we are waiting for this activity to finish pausing. Let's not
diff --git a/services/core/java/com/android/server/wm/BackgroundActivityStartController.java b/services/core/java/com/android/server/wm/BackgroundActivityStartController.java
index 6773bcd6fac8..e447049a7362 100644
--- a/services/core/java/com/android/server/wm/BackgroundActivityStartController.java
+++ b/services/core/java/com/android/server/wm/BackgroundActivityStartController.java
@@ -487,7 +487,7 @@ public class BackgroundActivityStartController {
// The verdict changed from allow (resultIfPiSenderAllowsBal) to block, PI sender
// default change is on (otherwise we would have fallen into if above) and we'd
// allow if it were off
- Slog.wtf(TAG, "Without BAL hardening this activity start would NOT be allowed!"
+ Slog.wtf(TAG, "Without BAL hardening this activity start would be allowed!"
+ stateDumpLog);
}
}
diff --git a/services/core/java/com/android/server/wm/DisplayArea.java b/services/core/java/com/android/server/wm/DisplayArea.java
index c2ddb4158846..00299c286b08 100644
--- a/services/core/java/com/android/server/wm/DisplayArea.java
+++ b/services/core/java/com/android/server/wm/DisplayArea.java
@@ -148,7 +148,7 @@ public class DisplayArea<T extends WindowContainer> extends WindowContainer<T> {
@ScreenOrientation
int getOrientation(int candidate) {
final int orientation = super.getOrientation(candidate);
- if (getIgnoreOrientationRequest(orientation)) {
+ if (shouldIgnoreOrientationRequest(orientation)) {
// In all the other case, mLastOrientationSource will be reassigned to a new value
mLastOrientationSource = null;
return SCREEN_ORIENTATION_UNSET;
@@ -158,7 +158,7 @@ public class DisplayArea<T extends WindowContainer> extends WindowContainer<T> {
@Override
boolean handlesOrientationChangeFromDescendant(@ScreenOrientation int orientation) {
- return !getIgnoreOrientationRequest(orientation)
+ return !shouldIgnoreOrientationRequest(orientation)
&& super.handlesOrientationChangeFromDescendant(orientation);
}
@@ -169,7 +169,7 @@ public class DisplayArea<T extends WindowContainer> extends WindowContainer<T> {
final int orientation = requestingContainer != null
? requestingContainer.getOverrideOrientation()
: SCREEN_ORIENTATION_UNSET;
- return !getIgnoreOrientationRequest(orientation)
+ return !shouldIgnoreOrientationRequest(orientation)
&& super.onDescendantOrientationChanged(requestingContainer);
}
@@ -236,8 +236,7 @@ public class DisplayArea<T extends WindowContainer> extends WindowContainer<T> {
/**
* @return {@value true} if we need to ignore the orientation in input.
*/
- // TODO(b/262366204): Rename getIgnoreOrientationRequest to shouldIgnoreOrientationRequest
- boolean getIgnoreOrientationRequest(@ScreenOrientation int orientation) {
+ boolean shouldIgnoreOrientationRequest(@ScreenOrientation int orientation) {
// We always respect orientation request for ActivityInfo.SCREEN_ORIENTATION_LOCKED
// ActivityInfo.SCREEN_ORIENTATION_NOSENSOR.
// Main use case why this is important is Camera apps that rely on those
diff --git a/services/core/java/com/android/server/wm/DisplayContent.java b/services/core/java/com/android/server/wm/DisplayContent.java
index ab109fcaa673..bec58b848478 100644
--- a/services/core/java/com/android/server/wm/DisplayContent.java
+++ b/services/core/java/com/android/server/wm/DisplayContent.java
@@ -1648,7 +1648,7 @@ class DisplayContent extends RootDisplayArea implements WindowManagerPolicy.Disp
@Override
boolean handlesOrientationChangeFromDescendant(@ScreenOrientation int orientation) {
- return !getIgnoreOrientationRequest(orientation)
+ return !shouldIgnoreOrientationRequest(orientation)
&& !getDisplayRotation().isFixedToUserRotation();
}
@@ -1752,7 +1752,7 @@ class DisplayContent extends RootDisplayArea implements WindowManagerPolicy.Disp
}
final int activityOrientation = r.getOverrideOrientation();
if (!WindowManagerService.ENABLE_FIXED_ROTATION_TRANSFORM
- || getIgnoreOrientationRequest(activityOrientation)) {
+ || shouldIgnoreOrientationRequest(activityOrientation)) {
return ROTATION_UNDEFINED;
}
if (activityOrientation == ActivityInfo.SCREEN_ORIENTATION_BEHIND) {
@@ -5149,7 +5149,7 @@ class DisplayContent extends RootDisplayArea implements WindowManagerPolicy.Disp
@ScreenOrientation
int getOrientation(@ScreenOrientation int candidate) {
// IME does not participate in orientation.
- return getIgnoreOrientationRequest(candidate) ? SCREEN_ORIENTATION_UNSET : candidate;
+ return shouldIgnoreOrientationRequest(candidate) ? SCREEN_ORIENTATION_UNSET : candidate;
}
@Override
diff --git a/services/core/java/com/android/server/wm/EmbeddedWindowController.java b/services/core/java/com/android/server/wm/EmbeddedWindowController.java
index d65f464590c1..44d67687e260 100644
--- a/services/core/java/com/android/server/wm/EmbeddedWindowController.java
+++ b/services/core/java/com/android/server/wm/EmbeddedWindowController.java
@@ -292,7 +292,9 @@ class EmbeddedWindowController {
private void handleTap(boolean grantFocus) {
if (mInputChannel != null) {
if (mHostWindowState != null) {
- mWmService.grantEmbeddedWindowFocus(mSession, mHostWindowState.mClient,
+ // Use null session since this is being granted by system server and doesn't
+ // require the host session to be passed in
+ mWmService.grantEmbeddedWindowFocus(null, mHostWindowState.mClient,
mFocusGrantToken, grantFocus);
if (grantFocus) {
// If granting focus to the embedded when tapped, we need to ensure the host
diff --git a/services/core/java/com/android/server/wm/LetterboxUiController.java b/services/core/java/com/android/server/wm/LetterboxUiController.java
index b0c384dcd7ac..93233dd4bda8 100644
--- a/services/core/java/com/android/server/wm/LetterboxUiController.java
+++ b/services/core/java/com/android/server/wm/LetterboxUiController.java
@@ -50,6 +50,7 @@ import static android.view.WindowManager.PROPERTY_CAMERA_COMPAT_ENABLE_REFRESH_V
import static android.view.WindowManager.PROPERTY_COMPAT_ALLOW_DISPLAY_ORIENTATION_OVERRIDE;
import static android.view.WindowManager.PROPERTY_COMPAT_ALLOW_ORIENTATION_OVERRIDE;
import static android.view.WindowManager.PROPERTY_COMPAT_ENABLE_FAKE_FOCUS;
+import static android.view.WindowManager.PROPERTY_COMPAT_IGNORE_ORIENTATION_REQUEST_WHEN_LOOP_DETECTED;
import static android.view.WindowManager.PROPERTY_COMPAT_IGNORE_REQUESTED_ORIENTATION;
import static com.android.internal.util.FrameworkStatsLog.APP_COMPAT_STATE_CHANGED__LETTERBOX_POSITION__BOTTOM;
@@ -235,9 +236,14 @@ final class LetterboxUiController {
private final Boolean mBooleanPropertyIgnoreRequestedOrientation;
@Nullable
+ private final Boolean mBooleanPropertyIgnoreOrientationRequestWhenLoopDetected;
+
+ @Nullable
private final Boolean mBooleanPropertyFakeFocus;
- private boolean mIsRelauchingAfterRequestedOrientationChanged;
+ private boolean mIsRelaunchingAfterRequestedOrientationChanged;
+
+ private boolean mLastShouldShowLetterboxUi;
private boolean mDoubleTapEvent;
@@ -253,6 +259,10 @@ final class LetterboxUiController {
readComponentProperty(packageManager, mActivityRecord.packageName,
mLetterboxConfiguration::isPolicyForIgnoringRequestedOrientationEnabled,
PROPERTY_COMPAT_IGNORE_REQUESTED_ORIENTATION);
+ mBooleanPropertyIgnoreOrientationRequestWhenLoopDetected =
+ readComponentProperty(packageManager, mActivityRecord.packageName,
+ mLetterboxConfiguration::isPolicyForIgnoringRequestedOrientationEnabled,
+ PROPERTY_COMPAT_IGNORE_ORIENTATION_REQUEST_WHEN_LOOP_DETECTED);
mBooleanPropertyFakeFocus =
readComponentProperty(packageManager, mActivityRecord.packageName,
mLetterboxConfiguration::isCompatFakeFocusEnabled,
@@ -387,7 +397,7 @@ final class LetterboxUiController {
::isPolicyForIgnoringRequestedOrientationEnabled,
mIsOverrideEnableCompatIgnoreRequestedOrientationEnabled,
mBooleanPropertyIgnoreRequestedOrientation)) {
- if (mIsRelauchingAfterRequestedOrientationChanged) {
+ if (mIsRelaunchingAfterRequestedOrientationChanged) {
Slog.w(TAG, "Ignoring orientation update to "
+ screenOrientationToString(requestedOrientation)
+ " due to relaunching after setRequestedOrientation for "
@@ -422,6 +432,8 @@ final class LetterboxUiController {
*
* <p>This treatment is enabled when the following conditions are met:
* <ul>
+ * <li>Flag gating the treatment is enabled
+ * <li>Opt-out component property isn't enabled
* <li>Per-app override is enabled
* <li>App has requested orientation more than 2 times within 1-second
* timer and activity is not letterboxed for fixed orientation
@@ -429,7 +441,11 @@ final class LetterboxUiController {
*/
@VisibleForTesting
boolean shouldIgnoreOrientationRequestLoop() {
- if (!mIsOverrideEnableCompatIgnoreOrientationRequestWhenLoopDetectedEnabled) {
+ if (!shouldEnableWithOptInOverrideAndOptOutProperty(
+ /* gatingCondition */ mLetterboxConfiguration
+ ::isPolicyForIgnoringRequestedOrientationEnabled,
+ mIsOverrideEnableCompatIgnoreOrientationRequestWhenLoopDetectedEnabled,
+ mBooleanPropertyIgnoreOrientationRequestWhenLoopDetected)) {
return false;
}
@@ -476,8 +492,8 @@ final class LetterboxUiController {
* Sets whether an activity is relaunching after the app has called {@link
* android.app.Activity#setRequestedOrientation}.
*/
- void setRelauchingAfterRequestedOrientationChanged(boolean isRelaunching) {
- mIsRelauchingAfterRequestedOrientationChanged = isRelaunching;
+ void setRelaunchingAfterRequestedOrientationChanged(boolean isRelaunching) {
+ mIsRelaunchingAfterRequestedOrientationChanged = isRelaunching;
}
/**
@@ -1154,12 +1170,28 @@ final class LetterboxUiController {
@VisibleForTesting
boolean shouldShowLetterboxUi(WindowState mainWindow) {
- return (mActivityRecord.isInLetterboxAnimation() || isSurfaceVisible(mainWindow))
+ if (mIsRelaunchingAfterRequestedOrientationChanged || !isSurfaceReadyToShow(mainWindow)) {
+ return mLastShouldShowLetterboxUi;
+ }
+
+ final boolean shouldShowLetterboxUi =
+ (mActivityRecord.isInLetterboxAnimation() || isSurfaceVisible(mainWindow))
&& mainWindow.areAppWindowBoundsLetterboxed()
// Check for FLAG_SHOW_WALLPAPER explicitly instead of using
// WindowContainer#showWallpaper because the later will return true when this
// activity is using blurred wallpaper for letterbox background.
&& (mainWindow.getAttrs().flags & FLAG_SHOW_WALLPAPER) == 0;
+
+ mLastShouldShowLetterboxUi = shouldShowLetterboxUi;
+
+ return shouldShowLetterboxUi;
+ }
+
+ @VisibleForTesting
+ boolean isSurfaceReadyToShow(WindowState mainWindow) {
+ return mainWindow.isDrawn() // Regular case
+ // Waiting for relayoutWindow to call preserveSurface
+ || mainWindow.isDragResizeChanged();
}
@VisibleForTesting
@@ -1297,6 +1329,10 @@ final class LetterboxUiController {
return null;
}
+ boolean getIsRelaunchingAfterRequestedOrientationChanged() {
+ return mIsRelaunchingAfterRequestedOrientationChanged;
+ }
+
private void adjustBoundsForTaskbar(final WindowState mainWindow, final Rect bounds) {
// Rounded corners should be displayed above the taskbar. When taskbar is hidden,
// an insets frame is equal to a navigation bar which shouldn't affect position of
diff --git a/services/core/java/com/android/server/wm/TaskDisplayArea.java b/services/core/java/com/android/server/wm/TaskDisplayArea.java
index 76759ba53f5a..b0a879e96dcf 100644
--- a/services/core/java/com/android/server/wm/TaskDisplayArea.java
+++ b/services/core/java/com/android/server/wm/TaskDisplayArea.java
@@ -1883,7 +1883,7 @@ final class TaskDisplayArea extends DisplayArea<WindowContainer> {
// Only allow to specify orientation if this TDA is the last focused one on this logical
// display that can request orientation request.
return mDisplayContent.getOrientationRequestingTaskDisplayArea() == this
- && !getIgnoreOrientationRequest(orientation);
+ && !shouldIgnoreOrientationRequest(orientation);
}
void clearPreferredTopFocusableRootTask() {
diff --git a/services/core/java/com/android/server/wm/Transition.java b/services/core/java/com/android/server/wm/Transition.java
index 0fe1f923e4e5..1fb353476592 100644
--- a/services/core/java/com/android/server/wm/Transition.java
+++ b/services/core/java/com/android/server/wm/Transition.java
@@ -33,8 +33,6 @@ import static android.view.WindowManager.TRANSIT_CHANGE;
import static android.view.WindowManager.TRANSIT_CLOSE;
import static android.view.WindowManager.TRANSIT_FLAG_IS_RECENTS;
import static android.view.WindowManager.TRANSIT_FLAG_KEYGUARD_LOCKED;
-import static android.view.WindowManager.TRANSIT_KEYGUARD_OCCLUDE;
-import static android.view.WindowManager.TRANSIT_KEYGUARD_UNOCCLUDE;
import static android.view.WindowManager.TRANSIT_OPEN;
import static android.view.WindowManager.TRANSIT_TO_BACK;
import static android.view.WindowManager.TRANSIT_TO_FRONT;
@@ -167,6 +165,9 @@ class Transition implements BLASTSyncEngine.TransactionReadyListener {
private SurfaceControl.Transaction mStartTransaction = null;
private SurfaceControl.Transaction mFinishTransaction = null;
+ /** Used for failsafe clean-up to prevent leaks due to misbehaving player impls. */
+ private SurfaceControl.Transaction mCleanupTransaction = null;
+
/**
* Contains change infos for both participants and all remote-animatable ancestors. The
* ancestors can be the promotion candidates so their start-states need to be captured.
@@ -787,6 +788,24 @@ class Transition implements BLASTSyncEngine.TransactionReadyListener {
}
/**
+ * Build a transaction that cleans-up transition-only surfaces (transition root and snapshots).
+ * This will ALWAYS be applied on transition finish just in-case
+ */
+ private static void buildCleanupTransaction(SurfaceControl.Transaction t, TransitionInfo info) {
+ for (int i = info.getChanges().size() - 1; i >= 0; --i) {
+ final TransitionInfo.Change c = info.getChanges().get(i);
+ if (c.getSnapshot() != null) {
+ t.reparent(c.getSnapshot(), null);
+ }
+ }
+ for (int i = info.getRootCount() - 1; i >= 0; --i) {
+ final SurfaceControl leash = info.getRoot(i).getLeash();
+ if (leash == null) continue;
+ t.reparent(leash, null);
+ }
+ }
+
+ /**
* Set whether this transition can start a pip-enter transition when finished. This is usually
* true, but gets set to false when recents decides that it wants to finish its animation but
* not actually finish its animation (yeah...).
@@ -863,6 +882,10 @@ class Transition implements BLASTSyncEngine.TransactionReadyListener {
if (mStartTransaction != null) mStartTransaction.close();
if (mFinishTransaction != null) mFinishTransaction.close();
mStartTransaction = mFinishTransaction = null;
+ if (mCleanupTransaction != null) {
+ mCleanupTransaction.apply();
+ mCleanupTransaction = null;
+ }
if (mState < STATE_PLAYING) {
throw new IllegalStateException("Can't finish a non-playing transition " + mSyncId);
}
@@ -1286,6 +1309,8 @@ class Transition implements BLASTSyncEngine.TransactionReadyListener {
}
}
buildFinishTransaction(mFinishTransaction, info);
+ mCleanupTransaction = mController.mAtm.mWindowManager.mTransactionFactory.get();
+ buildCleanupTransaction(mCleanupTransaction, info);
if (mController.getTransitionPlayer() != null && mIsPlayerEnabled) {
mController.dispatchLegacyAppTransitionStarting(info, mStatusBarTransitionDelay);
try {
@@ -1385,6 +1410,10 @@ class Transition implements BLASTSyncEngine.TransactionReadyListener {
ci.mSnapshot.release();
}
}
+ if (mCleanupTransaction != null) {
+ mCleanupTransaction.apply();
+ mCleanupTransaction = null;
+ }
}
/** The transition is ready to play. Make the start transaction show the surfaces. */
diff --git a/services/core/java/com/android/server/wm/WindowState.java b/services/core/java/com/android/server/wm/WindowState.java
index 23934e00408a..736f489cf99d 100644
--- a/services/core/java/com/android/server/wm/WindowState.java
+++ b/services/core/java/com/android/server/wm/WindowState.java
@@ -5230,8 +5230,17 @@ class WindowState extends WindowContainer<WindowState> implements WindowManagerP
if (surfaceInsetsChanged) {
mLastSurfaceInsets.set(mAttrs.surfaceInsets);
}
- if (surfaceSizeChanged && mWinAnimator.getShown() && !canPlayMoveAnimation()
- && okToDisplay() && mSyncState == SYNC_STATE_NONE) {
+ final boolean surfaceResizedWithoutMoveAnimation = surfaceSizeChanged
+ && mWinAnimator.getShown() && !canPlayMoveAnimation() && okToDisplay()
+ && mSyncState == SYNC_STATE_NONE;
+ final ActivityRecord activityRecord = getActivityRecord();
+ // If this window belongs to an activity that is relaunching due to an orientation
+ // change then delay the position update until it has redrawn to avoid any flickers.
+ final boolean isLetterboxedAndRelaunching = activityRecord != null
+ && activityRecord.areBoundsLetterboxed()
+ && activityRecord.mLetterboxUiController
+ .getIsRelaunchingAfterRequestedOrientationChanged();
+ if (surfaceResizedWithoutMoveAnimation || isLetterboxedAndRelaunching) {
applyWithNextDraw(mSetSurfacePositionConsumer);
} else {
mSetSurfacePositionConsumer.accept(t);
diff --git a/services/credentials/java/com/android/server/credentials/ClearRequestSession.java b/services/credentials/java/com/android/server/credentials/ClearRequestSession.java
index dce7b87c0328..bbebbf2383f5 100644
--- a/services/credentials/java/com/android/server/credentials/ClearRequestSession.java
+++ b/services/credentials/java/com/android/server/credentials/ClearRequestSession.java
@@ -40,11 +40,13 @@ public final class ClearRequestSession extends RequestSession<ClearCredentialSta
implements ProviderSession.ProviderInternalCallback<Void> {
private static final String TAG = "GetRequestSession";
- public ClearRequestSession(Context context, int userId, int callingUid,
+ public ClearRequestSession(Context context, RequestSession.SessionLifetime sessionCallback,
+ Object lock, int userId, int callingUid,
IClearCredentialStateCallback callback, ClearCredentialStateRequest request,
CallingAppInfo callingAppInfo, CancellationSignal cancellationSignal,
long startedTimestamp) {
- super(context, userId, callingUid, request, callback, RequestInfo.TYPE_UNDEFINED,
+ super(context, sessionCallback, lock, userId, callingUid, request, callback,
+ RequestInfo.TYPE_UNDEFINED,
callingAppInfo, cancellationSignal, startedTimestamp);
}
diff --git a/services/credentials/java/com/android/server/credentials/CreateRequestSession.java b/services/credentials/java/com/android/server/credentials/CreateRequestSession.java
index 98dc8ab8aa9c..4c456a88b00b 100644
--- a/services/credentials/java/com/android/server/credentials/CreateRequestSession.java
+++ b/services/credentials/java/com/android/server/credentials/CreateRequestSession.java
@@ -49,13 +49,15 @@ public final class CreateRequestSession extends RequestSession<CreateCredentialR
implements ProviderSession.ProviderInternalCallback<CreateCredentialResponse> {
private static final String TAG = "CreateRequestSession";
- CreateRequestSession(@NonNull Context context, int userId, int callingUid,
+ CreateRequestSession(@NonNull Context context, RequestSession.SessionLifetime sessionCallback,
+ Object lock, int userId, int callingUid,
CreateCredentialRequest request,
ICreateCredentialCallback callback,
CallingAppInfo callingAppInfo,
CancellationSignal cancellationSignal,
long startedTimestamp) {
- super(context, userId, callingUid, request, callback, RequestInfo.TYPE_CREATE,
+ super(context, sessionCallback, lock, userId, callingUid, request, callback,
+ RequestInfo.TYPE_CREATE,
callingAppInfo, cancellationSignal, startedTimestamp);
}
@@ -83,6 +85,7 @@ public final class CreateRequestSession extends RequestSession<CreateCredentialR
@Override
protected void launchUiWithProviderData(ArrayList<ProviderData> providerDataList) {
mRequestSessionMetric.collectUiCallStartTime(System.nanoTime());
+ mCredentialManagerUi.setStatus(CredentialManagerUi.UiStatus.USER_INTERACTION);
try {
mClientCallback.onPendingIntent(mCredentialManagerUi.createPendingIntent(
RequestInfo.newCreateRequestInfo(
@@ -93,6 +96,7 @@ public final class CreateRequestSession extends RequestSession<CreateCredentialR
providerDataList));
} catch (RemoteException e) {
mRequestSessionMetric.collectUiReturnedFinalPhase(/*uiReturned=*/ false);
+ mCredentialManagerUi.setStatus(CredentialManagerUi.UiStatus.TERMINATED);
respondToClientWithErrorAndFinish(
CreateCredentialException.TYPE_UNKNOWN,
"Unable to invoke selector");
diff --git a/services/credentials/java/com/android/server/credentials/CredentialManagerService.java b/services/credentials/java/com/android/server/credentials/CredentialManagerService.java
index de06d440fa9d..ae6eaf09bec7 100644
--- a/services/credentials/java/com/android/server/credentials/CredentialManagerService.java
+++ b/services/credentials/java/com/android/server/credentials/CredentialManagerService.java
@@ -33,7 +33,6 @@ import android.content.pm.PackageManager;
import android.credentials.ClearCredentialStateRequest;
import android.credentials.CreateCredentialException;
import android.credentials.CreateCredentialRequest;
-import android.credentials.CredentialManager;
import android.credentials.CredentialOption;
import android.credentials.CredentialProviderInfo;
import android.credentials.GetCredentialException;
@@ -50,6 +49,7 @@ import android.credentials.UnregisterCredentialDescriptionRequest;
import android.credentials.ui.IntentFactory;
import android.os.Binder;
import android.os.CancellationSignal;
+import android.os.IBinder;
import android.os.ICancellationSignal;
import android.os.RemoteException;
import android.os.UserHandle;
@@ -70,9 +70,11 @@ import com.android.server.infra.AbstractMasterSystemService;
import com.android.server.infra.SecureSettingsServiceNameResolver;
import java.util.ArrayList;
+import java.util.HashMap;
import java.util.HashSet;
import java.util.LinkedHashSet;
import java.util.List;
+import java.util.Map;
import java.util.Set;
import java.util.function.Consumer;
import java.util.stream.Collectors;
@@ -102,6 +104,13 @@ public final class CredentialManagerService
private final SparseArray<List<CredentialManagerServiceImpl>> mSystemServicesCacheList =
new SparseArray<>();
+ /** Cache of all ongoing request sessions per user id. */
+ @GuardedBy("mLock")
+ private final SparseArray<Map<IBinder, RequestSession>> mRequestSessions =
+ new SparseArray<>();
+
+ private final SessionManager mSessionManager = new SessionManager();
+
public CredentialManagerService(@NonNull Context context) {
super(
context,
@@ -331,7 +340,7 @@ public final class CredentialManagerService
@NonNull
private Set<Pair<CredentialOption, CredentialDescriptionRegistry.FilterResult>>
- getFilteredResultFromRegistry(List<CredentialOption> options) {
+ getFilteredResultFromRegistry(List<CredentialOption> options) {
// Session for active/provisioned credential descriptions;
CredentialDescriptionRegistry registry =
CredentialDescriptionRegistry.forUser(UserHandle.getCallingUserId());
@@ -389,14 +398,6 @@ public final class CredentialManagerService
return providerSessions;
}
- private List<CredentialProviderInfo> getServicesForCredentialDescription(int userId) {
- return CredentialProviderInfoFactory.getCredentialProviderServices(
- mContext,
- userId,
- CredentialManager.PROVIDER_FILTER_ALL_PROVIDERS,
- new HashSet<>());
- }
-
@Override
@GuardedBy("CredentialDescriptionRegistry.sLock")
public void onUserStopped(@NonNull TargetUser user) {
@@ -448,6 +449,8 @@ public final class CredentialManagerService
final GetRequestSession session =
new GetRequestSession(
getContext(),
+ mSessionManager,
+ mLock,
userId,
callingUid,
callback,
@@ -455,6 +458,7 @@ public final class CredentialManagerService
constructCallingAppInfo(callingPackage, userId, request.getOrigin()),
CancellationSignal.fromTransport(cancelTransport),
timestampBegan);
+ addSessionLocked(userId, session);
List<ProviderSession> providerSessions =
prepareProviderSessions(request, session);
@@ -499,6 +503,8 @@ public final class CredentialManagerService
final PrepareGetRequestSession session =
new PrepareGetRequestSession(
getContext(),
+ mSessionManager,
+ mLock,
userId,
callingUid,
getCredentialCallback,
@@ -515,8 +521,8 @@ public final class CredentialManagerService
// TODO: fix
prepareGetCredentialCallback.onResponse(
new PrepareGetCredentialResponseInternal(
- false, null,
- false, false, null));
+ false, null,
+ false, false, null));
} catch (RemoteException e) {
Log.i(
TAG,
@@ -540,10 +546,10 @@ public final class CredentialManagerService
List<CredentialOption> optionsThatRequireActiveCredentials =
request.getCredentialOptions().stream()
.filter(credentialOption -> credentialOption
- .getCredentialRetrievalData()
- .getStringArrayList(
- CredentialOption
- .SUPPORTED_ELEMENT_KEYS) != null)
+ .getCredentialRetrievalData()
+ .getStringArrayList(
+ CredentialOption
+ .SUPPORTED_ELEMENT_KEYS) != null)
.toList();
List<CredentialOption> optionsThatDoNotRequireActiveCredentials =
@@ -614,6 +620,8 @@ public final class CredentialManagerService
final CreateRequestSession session =
new CreateRequestSession(
getContext(),
+ mSessionManager,
+ mLock,
userId,
callingUid,
request,
@@ -621,6 +629,7 @@ public final class CredentialManagerService
constructCallingAppInfo(callingPackage, userId, request.getOrigin()),
CancellationSignal.fromTransport(cancelTransport),
timestampBegan);
+ addSessionLocked(userId, session);
processCreateCredential(request, callback, session);
return cancelTransport;
@@ -775,6 +784,19 @@ public final class CredentialManagerService
mContext, userId, providerFilter, getEnabledProviders());
}
+ @Override
+ public boolean isServiceEnabled() {
+ final long origId = Binder.clearCallingIdentity();
+ try {
+ return DeviceConfig.getBoolean(
+ DeviceConfig.NAMESPACE_CREDENTIAL,
+ CredentialManager.DEVICE_CONFIG_ENABLE_CREDENTIAL_MANAGER,
+ false);
+ } finally {
+ Binder.restoreCallingIdentity(origId);
+ }
+ }
+
@SuppressWarnings("GuardedBy") // ErrorProne requires service.mLock which is the same
// this.mLock
private Set<ComponentName> getEnabledProviders() {
@@ -815,6 +837,8 @@ public final class CredentialManagerService
final ClearRequestSession session =
new ClearRequestSession(
getContext(),
+ mSessionManager,
+ mLock,
userId,
callingUid,
callback,
@@ -822,6 +846,7 @@ public final class CredentialManagerService
constructCallingAppInfo(callingPackage, userId, null),
CancellationSignal.fromTransport(cancelTransport),
timestampBegan);
+ addSessionLocked(userId, session);
// Initiate all provider sessions
// TODO: Determine if provider needs to have clear capability in their manifest
@@ -905,6 +930,13 @@ public final class CredentialManagerService
}
}
+ private void addSessionLocked(@UserIdInt int userId,
+ RequestSession requestSession) {
+ synchronized (mLock) {
+ mSessionManager.addSession(userId, requestSession.mRequestId, requestSession);
+ }
+ }
+
private void enforceCallingPackage(String callingPackage, int callingUid) {
int packageUid;
PackageManager pm = mContext.createContextAsUser(
@@ -919,4 +951,23 @@ public final class CredentialManagerService
throw new SecurityException(callingPackage + " does not belong to uid " + callingUid);
}
}
+
+ private class SessionManager implements RequestSession.SessionLifetime {
+ @Override
+ @GuardedBy("mLock")
+ public void onFinishRequestSession(@UserIdInt int userId, IBinder token) {
+ Log.i(TAG, "In onFinishRequestSession");
+ if (mRequestSessions.get(userId) != null) {
+ mRequestSessions.get(userId).remove(token);
+ }
+ }
+
+ @GuardedBy("mLock")
+ public void addSession(int userId, IBinder token, RequestSession requestSession) {
+ if (mRequestSessions.get(userId) == null) {
+ mRequestSessions.put(userId, new HashMap<>());
+ }
+ mRequestSessions.get(userId).put(token, requestSession);
+ }
+ }
}
diff --git a/services/credentials/java/com/android/server/credentials/CredentialManagerUi.java b/services/credentials/java/com/android/server/credentials/CredentialManagerUi.java
index 546c37ff95af..e16d48e0a680 100644
--- a/services/credentials/java/com/android/server/credentials/CredentialManagerUi.java
+++ b/services/credentials/java/com/android/server/credentials/CredentialManagerUi.java
@@ -30,6 +30,7 @@ import android.credentials.ui.RequestInfo;
import android.credentials.ui.UserSelectionDialogResult;
import android.os.Bundle;
import android.os.Handler;
+import android.os.IBinder;
import android.os.Looper;
import android.os.ResultReceiver;
import android.service.credentials.CredentialProviderInfoFactory;
@@ -50,6 +51,20 @@ public class CredentialManagerUi {
@NonNull private final Context mContext;
// TODO : Use for starting the activity for this user
private final int mUserId;
+
+ private UiStatus mStatus;
+
+ /** Creates intent that is ot be invoked to cancel an in-progress UI session. */
+ public Intent createCancelIntent(IBinder requestId, String packageName) {
+ return IntentFactory.createCancelUiIntent(requestId, /*shouldShowCancellationUi=*/ true,
+ packageName);
+ }
+
+ enum UiStatus {
+ IN_PROGRESS,
+ USER_INTERACTION,
+ NOT_STARTED, TERMINATED
+ }
@NonNull private final ResultReceiver mResultReceiver = new ResultReceiver(
new Handler(Looper.getMainLooper())) {
@Override
@@ -61,6 +76,7 @@ public class CredentialManagerUi {
private void handleUiResult(int resultCode, Bundle resultData) {
switch (resultCode) {
case UserSelectionDialogResult.RESULT_CODE_DIALOG_COMPLETE_WITH_SELECTION:
+ mStatus = UiStatus.IN_PROGRESS;
UserSelectionDialogResult selection = UserSelectionDialogResult
.fromResultData(resultData);
if (selection != null) {
@@ -70,16 +86,20 @@ public class CredentialManagerUi {
}
break;
case UserSelectionDialogResult.RESULT_CODE_DIALOG_USER_CANCELED:
+ mStatus = UiStatus.TERMINATED;
mCallbacks.onUiCancellation(/* isUserCancellation= */ true);
break;
case UserSelectionDialogResult.RESULT_CODE_CANCELED_AND_LAUNCHED_SETTINGS:
+ mStatus = UiStatus.TERMINATED;
mCallbacks.onUiCancellation(/* isUserCancellation= */ false);
break;
case UserSelectionDialogResult.RESULT_CODE_DATA_PARSING_FAILURE:
+ mStatus = UiStatus.TERMINATED;
mCallbacks.onUiSelectorInvocationFailure();
break;
default:
Slog.i(TAG, "Unknown error code returned from the UI");
+ mStatus = UiStatus.IN_PROGRESS;
mCallbacks.onUiSelectorInvocationFailure();
break;
}
@@ -103,6 +123,17 @@ public class CredentialManagerUi {
mContext = context;
mUserId = userId;
mCallbacks = callbacks;
+ mStatus = UiStatus.IN_PROGRESS;
+ }
+
+ /** Set status for credential manager UI */
+ public void setStatus(UiStatus status) {
+ mStatus = status;
+ }
+
+ /** Returns status for credential manager UI */
+ public UiStatus getStatus() {
+ return mStatus;
}
/**
diff --git a/services/credentials/java/com/android/server/credentials/GetRequestSession.java b/services/credentials/java/com/android/server/credentials/GetRequestSession.java
index c0c7be9d80e2..2548bd888b9d 100644
--- a/services/credentials/java/com/android/server/credentials/GetRequestSession.java
+++ b/services/credentials/java/com/android/server/credentials/GetRequestSession.java
@@ -45,12 +45,13 @@ public class GetRequestSession extends RequestSession<GetCredentialRequest,
IGetCredentialCallback, GetCredentialResponse>
implements ProviderSession.ProviderInternalCallback<GetCredentialResponse> {
private static final String TAG = "GetRequestSession";
- public GetRequestSession(Context context, int userId, int callingUid,
+ public GetRequestSession(Context context, RequestSession.SessionLifetime sessionCallback,
+ Object lock, int userId, int callingUid,
IGetCredentialCallback callback, GetCredentialRequest request,
CallingAppInfo callingAppInfo, CancellationSignal cancellationSignal,
long startedTimestamp) {
- super(context, userId, callingUid, request, callback, RequestInfo.TYPE_GET,
- callingAppInfo, cancellationSignal, startedTimestamp);
+ super(context, sessionCallback, lock, userId, callingUid, request, callback,
+ RequestInfo.TYPE_GET, callingAppInfo, cancellationSignal, startedTimestamp);
int numTypes = (request.getCredentialOptions().stream()
.map(CredentialOption::getType).collect(
Collectors.toSet())).size(); // Dedupe type strings
@@ -81,6 +82,7 @@ public class GetRequestSession extends RequestSession<GetCredentialRequest,
@Override
protected void launchUiWithProviderData(ArrayList<ProviderData> providerDataList) {
mRequestSessionMetric.collectUiCallStartTime(System.nanoTime());
+ mCredentialManagerUi.setStatus(CredentialManagerUi.UiStatus.USER_INTERACTION);
try {
mClientCallback.onPendingIntent(mCredentialManagerUi.createPendingIntent(
RequestInfo.newGetRequestInfo(
@@ -88,6 +90,7 @@ public class GetRequestSession extends RequestSession<GetCredentialRequest,
providerDataList));
} catch (RemoteException e) {
mRequestSessionMetric.collectUiReturnedFinalPhase(/*uiReturned=*/ false);
+ mCredentialManagerUi.setStatus(CredentialManagerUi.UiStatus.TERMINATED);
respondToClientWithErrorAndFinish(
GetCredentialException.TYPE_UNKNOWN, "Unable to instantiate selector");
}
diff --git a/services/credentials/java/com/android/server/credentials/PrepareGetRequestSession.java b/services/credentials/java/com/android/server/credentials/PrepareGetRequestSession.java
index c4e480a8e609..88f3e6c92947 100644
--- a/services/credentials/java/com/android/server/credentials/PrepareGetRequestSession.java
+++ b/services/credentials/java/com/android/server/credentials/PrepareGetRequestSession.java
@@ -49,14 +49,13 @@ public class PrepareGetRequestSession extends GetRequestSession {
private final IPrepareGetCredentialCallback mPrepareGetCredentialCallback;
- public PrepareGetRequestSession(Context context, int userId, int callingUid,
- IGetCredentialCallback callback,
- GetCredentialRequest request,
- CallingAppInfo callingAppInfo,
- CancellationSignal cancellationSignal, long startedTimestamp,
- IPrepareGetCredentialCallback prepareGetCredentialCallback) {
- super(context, userId, callingUid, callback, request, callingAppInfo, cancellationSignal,
- startedTimestamp);
+ public PrepareGetRequestSession(Context context,
+ RequestSession.SessionLifetime sessionCallback, Object lock, int userId,
+ int callingUid, IGetCredentialCallback getCredCallback, GetCredentialRequest request,
+ CallingAppInfo callingAppInfo, CancellationSignal cancellationSignal,
+ long startedTimestamp, IPrepareGetCredentialCallback prepareGetCredentialCallback) {
+ super(context, sessionCallback, lock, userId, callingUid, getCredCallback, request,
+ callingAppInfo, cancellationSignal, startedTimestamp);
int numTypes = (request.getCredentialOptions().stream()
.map(CredentialOption::getType).collect(
Collectors.toSet())).size(); // Dedupe type strings
diff --git a/services/credentials/java/com/android/server/credentials/ProviderClearSession.java b/services/credentials/java/com/android/server/credentials/ProviderClearSession.java
index 1b736e01c842..eaf58f13e2fa 100644
--- a/services/credentials/java/com/android/server/credentials/ProviderClearSession.java
+++ b/services/credentials/java/com/android/server/credentials/ProviderClearSession.java
@@ -126,7 +126,8 @@ public final class ProviderClearSession extends ProviderSession<ClearCredentialS
protected void invokeSession() {
if (mRemoteCredentialService != null) {
startCandidateMetrics();
- mRemoteCredentialService.onClearCredentialState(mProviderRequest, this);
+ mProviderCancellationSignal =
+ mRemoteCredentialService.onClearCredentialState(mProviderRequest, this);
}
}
}
diff --git a/services/credentials/java/com/android/server/credentials/ProviderCreateSession.java b/services/credentials/java/com/android/server/credentials/ProviderCreateSession.java
index bef045f8f890..c657e3b1b389 100644
--- a/services/credentials/java/com/android/server/credentials/ProviderCreateSession.java
+++ b/services/credentials/java/com/android/server/credentials/ProviderCreateSession.java
@@ -236,7 +236,8 @@ public final class ProviderCreateSession extends ProviderSession<
protected void invokeSession() {
if (mRemoteCredentialService != null) {
startCandidateMetrics();
- mRemoteCredentialService.onCreateCredential(mProviderRequest, this);
+ mProviderCancellationSignal =
+ mRemoteCredentialService.onCreateCredential(mProviderRequest, this);
}
}
diff --git a/services/credentials/java/com/android/server/credentials/ProviderGetSession.java b/services/credentials/java/com/android/server/credentials/ProviderGetSession.java
index 427a8945c573..9c9c0c212d0c 100644
--- a/services/credentials/java/com/android/server/credentials/ProviderGetSession.java
+++ b/services/credentials/java/com/android/server/credentials/ProviderGetSession.java
@@ -302,7 +302,9 @@ public final class ProviderGetSession extends ProviderSession<BeginGetCredential
protected void invokeSession() {
if (mRemoteCredentialService != null) {
startCandidateMetrics();
- mRemoteCredentialService.onBeginGetCredential(mProviderRequest, this);
+ mProviderCancellationSignal =
+ mRemoteCredentialService.onBeginGetCredential(mProviderRequest, this);
+ boolean foundSig = mProviderCancellationSignal == null;
}
}
diff --git a/services/credentials/java/com/android/server/credentials/ProviderSession.java b/services/credentials/java/com/android/server/credentials/ProviderSession.java
index 8c0e1c1511e6..d165756b3811 100644
--- a/services/credentials/java/com/android/server/credentials/ProviderSession.java
+++ b/services/credentials/java/com/android/server/credentials/ProviderSession.java
@@ -30,6 +30,7 @@ import android.credentials.ui.ProviderPendingIntentResponse;
import android.os.ICancellationSignal;
import android.os.RemoteException;
import android.util.Log;
+import android.util.Slog;
import com.android.server.credentials.metrics.ProviderSessionMetric;
@@ -189,7 +190,7 @@ public abstract class ProviderSession<T, R>
}
setStatus(Status.CANCELED);
} catch (RemoteException e) {
- Log.i(TAG, "Issue while cancelling provider session: " + e.getMessage());
+ Slog.e(TAG, "Issue while cancelling provider session: ", e);
}
}
diff --git a/services/credentials/java/com/android/server/credentials/RequestSession.java b/services/credentials/java/com/android/server/credentials/RequestSession.java
index 04c4bc4c7c4f..ed175ed9601f 100644
--- a/services/credentials/java/com/android/server/credentials/RequestSession.java
+++ b/services/credentials/java/com/android/server/credentials/RequestSession.java
@@ -20,6 +20,7 @@ import android.annotation.NonNull;
import android.annotation.UserIdInt;
import android.content.ComponentName;
import android.content.Context;
+import android.content.Intent;
import android.credentials.CredentialProviderInfo;
import android.credentials.ui.ProviderData;
import android.credentials.ui.UserSelectionDialogResult;
@@ -29,8 +30,10 @@ import android.os.Handler;
import android.os.IBinder;
import android.os.Looper;
import android.os.RemoteException;
+import android.os.UserHandle;
import android.service.credentials.CallingAppInfo;
import android.util.Log;
+import android.util.Slog;
import com.android.internal.R;
import com.android.server.credentials.metrics.ApiName;
@@ -39,8 +42,8 @@ import com.android.server.credentials.metrics.ProviderStatusForMetrics;
import com.android.server.credentials.metrics.RequestSessionMetric;
import java.util.ArrayList;
-import java.util.HashMap;
import java.util.Map;
+import java.util.concurrent.ConcurrentHashMap;
/**
* Base class of a request session, that listens to UI events. This class must be extended
@@ -49,6 +52,11 @@ import java.util.Map;
abstract class RequestSession<T, U, V> implements CredentialManagerUi.CredentialManagerUiCallback {
private static final String TAG = "RequestSession";
+ public interface SessionLifetime {
+ /** Called when the user makes a selection. */
+ void onFinishRequestSession(@UserIdInt int userId, IBinder token);
+ }
+
// TODO: Revise access levels of attributes
@NonNull
protected final T mClientRequest;
@@ -72,10 +80,14 @@ abstract class RequestSession<T, U, V> implements CredentialManagerUi.Credential
@NonNull
protected final CancellationSignal mCancellationSignal;
- protected final Map<String, ProviderSession> mProviders = new HashMap<>();
+ protected final Map<String, ProviderSession> mProviders = new ConcurrentHashMap<>();
protected final RequestSessionMetric mRequestSessionMetric = new RequestSessionMetric();
protected final String mHybridService;
+ protected final Object mLock;
+
+ protected final SessionLifetime mSessionCallback;
+
@NonNull
protected RequestSessionStatus mRequestSessionStatus =
RequestSessionStatus.IN_PROGRESS;
@@ -91,11 +103,15 @@ abstract class RequestSession<T, U, V> implements CredentialManagerUi.Credential
}
protected RequestSession(@NonNull Context context,
- @UserIdInt int userId, int callingUid, @NonNull T clientRequest, U clientCallback,
+ RequestSession.SessionLifetime sessionCallback,
+ Object lock, @UserIdInt int userId, int callingUid,
+ @NonNull T clientRequest, U clientCallback,
@NonNull String requestType,
CallingAppInfo callingAppInfo,
CancellationSignal cancellationSignal, long timestampStarted) {
mContext = context;
+ mLock = lock;
+ mSessionCallback = sessionCallback;
mUserId = userId;
mCallingUid = callingUid;
mClientRequest = clientRequest;
@@ -111,6 +127,32 @@ abstract class RequestSession<T, U, V> implements CredentialManagerUi.Credential
R.string.config_defaultCredentialManagerHybridService);
mRequestSessionMetric.collectInitialPhaseMetricInfo(timestampStarted, mRequestId,
mCallingUid, ApiName.getMetricCodeFromRequestInfo(mRequestType));
+ setCancellationListener();
+ }
+
+ private void setCancellationListener() {
+ mCancellationSignal.setOnCancelListener(
+ () -> {
+ boolean isUiActive = maybeCancelUi();
+ finishSession(!isUiActive);
+ }
+ );
+ }
+
+ private boolean maybeCancelUi() {
+ if (mCredentialManagerUi.getStatus()
+ == CredentialManagerUi.UiStatus.USER_INTERACTION) {
+ final long originalCallingUidToken = Binder.clearCallingIdentity();
+ try {
+ mContext.startActivityAsUser(mCredentialManagerUi.createCancelIntent(
+ mRequestId, mClientAppInfo.getPackageName())
+ .addFlags(Intent.FLAG_ACTIVITY_NEW_TASK), UserHandle.of(mUserId));
+ return true;
+ } finally {
+ Binder.restoreCallingIdentity(originalCallingUidToken);
+ }
+ }
+ return false;
}
public abstract ProviderSession initiateProviderSession(CredentialProviderInfo providerInfo,
@@ -154,12 +196,19 @@ abstract class RequestSession<T, U, V> implements CredentialManagerUi.Credential
}
protected void finishSession(boolean propagateCancellation) {
- Log.i(TAG, "finishing session");
+ Slog.d(TAG, "finishing session with propagateCancellation " + propagateCancellation);
if (propagateCancellation) {
mProviders.values().forEach(ProviderSession::cancelProviderRemoteSession);
}
mRequestSessionStatus = RequestSessionStatus.COMPLETE;
mProviders.clear();
+ clearRequestSessionLocked();
+ }
+
+ private void clearRequestSessionLocked() {
+ synchronized (mLock) {
+ mSessionCallback.onFinishRequestSession(mUserId, mRequestId);
+ }
}
protected boolean isAnyProviderPending() {
diff --git a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
index a109dee73fe8..b2156414b122 100644
--- a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
+++ b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
@@ -92,6 +92,8 @@ import static android.app.AppOpsManager.OPSTR_SYSTEM_EXEMPT_FROM_HIBERNATION;
import static android.app.AppOpsManager.OPSTR_SYSTEM_EXEMPT_FROM_POWER_RESTRICTIONS;
import static android.app.AppOpsManager.OPSTR_SYSTEM_EXEMPT_FROM_SUSPENSION;
import static android.app.admin.DeviceAdminInfo.HEADLESS_DEVICE_OWNER_MODE_AFFILIATED;
+import static android.app.admin.DeviceAdminInfo.USES_POLICY_FORCE_LOCK;
+import static android.app.admin.DeviceAdminInfo.USES_POLICY_WIPE_DATA;
import static android.app.admin.DeviceAdminReceiver.ACTION_COMPLIANCE_ACKNOWLEDGEMENT_REQUIRED;
import static android.app.admin.DeviceAdminReceiver.EXTRA_TRANSFER_OWNERSHIP_ADMIN_EXTRAS_BUNDLE;
import static android.app.admin.DevicePolicyIdentifiers.AUTO_TIMEZONE_POLICY;
@@ -439,6 +441,7 @@ import android.util.AtomicFile;
import android.util.DebugUtils;
import android.util.IndentingPrintWriter;
import android.util.IntArray;
+import android.util.Log;
import android.util.Pair;
import android.util.Slog;
import android.util.SparseArray;
@@ -773,6 +776,14 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub {
@EnabledSince(targetSdkVersion = Build.VERSION_CODES.UPSIDE_DOWN_CAKE)
public static final long EXPLICIT_WIPE_BEHAVIOUR = 242193913L;
+ /**
+ * Apps targetting U+ should now expect that attempts to grant sensor permissions without
+ * authorisation will result in a security exception.
+ */
+ @ChangeId
+ @EnabledSince(targetSdkVersion = Build.VERSION_CODES.UPSIDE_DOWN_CAKE)
+ public static final long THROW_SECURITY_EXCEPTION_FOR_SENSOR_PERMISSIONS = 277035314L;
+
// Only add to the end of the list. Do not change or rearrange these values, that will break
// historical data. Do not use negative numbers or zero, logger only handles positive
// integers.
@@ -2819,6 +2830,16 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub {
return doAdmin;
}
+ ActiveAdmin getDefaultDeviceOwnerLocked(@UserIdInt int userId) {
+ ensureLocked();
+ ComponentName doComponent = mOwners.getDeviceOwnerComponent();
+ if (mOwners.getDeviceOwnerType(doComponent.getPackageName()) == DEFAULT_DEVICE_OWNER) {
+ ActiveAdmin doAdmin = getUserData(userId).mAdminMap.get(doComponent);
+ return doAdmin;
+ }
+ return null;
+ }
+
ActiveAdmin getProfileOwnerLocked(@UserIdInt int userId) {
ensureLocked();
final ComponentName poAdminComponent = mOwners.getProfileOwnerComponent(userId);
@@ -2848,6 +2869,18 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub {
return getDeviceOwnerLocked(userId);
}
+ ActiveAdmin getProfileOwnerOrDefaultDeviceOwnerLocked(@UserIdInt int userId) {
+ ensureLocked();
+ // Try to find an admin which can use reqPolicy
+ final ComponentName poAdminComponent = mOwners.getProfileOwnerComponent(userId);
+
+ if (poAdminComponent != null) {
+ return getProfileOwnerLocked(userId);
+ }
+
+ return getDefaultDeviceOwnerLocked(userId);
+ }
+
@NonNull ActiveAdmin getParentOfAdminIfRequired(ActiveAdmin admin, boolean parent) {
Objects.requireNonNull(admin);
return parent ? admin.getParentActiveAdmin() : admin;
@@ -5337,9 +5370,12 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub {
saveSettingsLocked(caller.getUserId());
});
+
+ //TODO(b/276855301): caller.getPackageName() will be null when the coexistence flags are
+ // turned off. Change back to caller.getPackageName once this API is unflagged.
DevicePolicyEventLogger
.createEvent(DevicePolicyEnums.SET_PASSWORD_COMPLEXITY)
- .setAdmin(caller.getPackageName())
+ .setAdmin(admin.info.getPackageName())
.setInt(passwordComplexity)
.setBoolean(calledOnParent)
.write();
@@ -5974,8 +6010,13 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub {
}
@Override
- public void lockNow(int flags, boolean parent) {
- final CallerIdentity caller = getCallerIdentity();
+ public void lockNow(int flags, String callerPackageName, boolean parent) {
+ CallerIdentity caller;
+ if (isPermissionCheckFlagEnabled()) {
+ caller = getCallerIdentity(callerPackageName);
+ } else {
+ caller = getCallerIdentity();
+ }
final int callingUserId = caller.getUserId();
ComponentName adminComponent = null;
@@ -5984,11 +6025,13 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub {
// Make sure the caller has any active admin with the right policy or
// the required permission.
if (isPermissionCheckFlagEnabled()) {
- admin = getActiveAdminOrCheckPermissionsForCallerLocked(
- null,
- DeviceAdminInfo.USES_POLICY_FORCE_LOCK,
- parent,
- Set.of(MANAGE_DEVICE_POLICY_LOCK, LOCK_DEVICE));
+ admin = enforcePermissionAndGetEnforcingAdmin(
+ /* admin= */ null,
+ /* permission= */ MANAGE_DEVICE_POLICY_LOCK,
+ USES_POLICY_FORCE_LOCK,
+ caller.getPackageName(),
+ getAffectedUser(parent)
+ ).getActiveAdmin();
} else {
admin = getActiveAdminOrCheckPermissionForCallerLocked(
null,
@@ -7481,7 +7524,8 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub {
if (isPolicyEngineForFinanceFlagEnabled()) {
EnforcingAdmin enforcingAdmin = enforcePermissionAndGetEnforcingAdmin(
/*admin=*/ null,
- MANAGE_DEVICE_POLICY_WIPE_DATA,
+ /*permission= */ MANAGE_DEVICE_POLICY_WIPE_DATA,
+ USES_POLICY_WIPE_DATA,
caller.getPackageName(),
factoryReset ? UserHandle.USER_ALL : getAffectedUser(calledOnParentInstance));
admin = enforcingAdmin.getActiveAdmin();
@@ -8511,7 +8555,7 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub {
isProfileOwnerOfOrganizationOwnedDevice(caller));
} else {
Preconditions.checkCallAuthorization(isProfileOwner(caller)
- || isDeviceOwner(caller));
+ || isDefaultDeviceOwner(caller));
}
}
@@ -8525,7 +8569,7 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub {
targetUserId).getActiveAdmin();
} else {
ap = getParentOfAdminIfRequired(
- getProfileOwnerOrDeviceOwnerLocked(caller.getUserId()), parent);
+ getProfileOwnerOrDefaultDeviceOwnerLocked(caller.getUserId()), parent);
}
if (ap.disableScreenCapture != disabled) {
@@ -8557,15 +8601,21 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub {
}
if (admin != null && admin.disableScreenCapture) {
setScreenCaptureDisabled(UserHandle.USER_ALL);
- } else {
- // Otherwise, update screen capture only for the calling user.
- admin = getProfileOwnerAdminLocked(adminUserId);
- if (admin != null && admin.disableScreenCapture) {
- setScreenCaptureDisabled(adminUserId);
- } else {
- setScreenCaptureDisabled(UserHandle.USER_NULL);
- }
+ return;
+ }
+ // Otherwise, update screen capture only for the calling user.
+ admin = getProfileOwnerAdminLocked(adminUserId);
+ if (admin != null && admin.disableScreenCapture) {
+ setScreenCaptureDisabled(adminUserId);
+ return;
}
+ // If the admin is permission based, update only for the calling user.
+ admin = getUserData(adminUserId).createOrGetPermissionBasedAdmin(adminUserId);
+ if (admin != null && admin.disableScreenCapture) {
+ setScreenCaptureDisabled(adminUserId);
+ return;
+ }
+ setScreenCaptureDisabled(UserHandle.USER_NULL);
}
// Set the latest screen capture policy, overriding any existing ones.
@@ -11424,7 +11474,7 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub {
RoleManager.ROLE_DIALER, packageName, 0, UserHandle.of(callerUserId),
AsyncTask.THREAD_POOL_EXECUTOR, callback);
try {
- future.get(5, TimeUnit.SECONDS);
+ future.get(20, TimeUnit.SECONDS);
} catch (TimeoutException e) {
throw new IllegalArgumentException("Timeout when setting the app as the dialer", e);
} catch (ExecutionException e) {
@@ -16466,6 +16516,25 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub {
MANAGE_DEVICE_POLICY_RUNTIME_PERMISSIONS,
callerPackage,
caller.getUserId());
+ if (SENSOR_PERMISSIONS.contains(permission)
+ && grantState == PERMISSION_GRANT_STATE_GRANTED
+ && (!canAdminGrantSensorsPermissions() || isCallerDelegate(caller))) {
+ if (mInjector.isChangeEnabled(THROW_SECURITY_EXCEPTION_FOR_SENSOR_PERMISSIONS,
+ caller.getPackageName(), caller.getUserId())) {
+ throw new SecurityException(
+ "Caller not permitted to grant sensor permissions.");
+ } else {
+ // This is to match the legacy behaviour.
+ callback.sendResult(Bundle.EMPTY);
+ return;
+ }
+ }
+ // Check all the states where Exceptions aren't thrown but the permission
+ // isn't granted either.
+ if (!canGrantPermission(caller, permission, packageName)) {
+ callback.sendResult(null);
+ return;
+ }
// TODO(b/266924257): decide how to handle the internal state if the package doesn't
// exist, or the permission isn't requested by the app, because we could end up with
// inconsistent state between the policy engine and package manager. Also a package
@@ -16541,6 +16610,41 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub {
}
}
+ private static final List<String> SENSOR_PERMISSIONS = new ArrayList<>();
+ {
+ SENSOR_PERMISSIONS.add(Manifest.permission.ACCESS_FINE_LOCATION);
+ SENSOR_PERMISSIONS.add(Manifest.permission.ACCESS_BACKGROUND_LOCATION);
+ SENSOR_PERMISSIONS.add(Manifest.permission.ACCESS_COARSE_LOCATION);
+ SENSOR_PERMISSIONS.add(Manifest.permission.CAMERA);
+ SENSOR_PERMISSIONS.add(Manifest.permission.RECORD_AUDIO);
+ SENSOR_PERMISSIONS.add(Manifest.permission.ACTIVITY_RECOGNITION);
+ SENSOR_PERMISSIONS.add(Manifest.permission.BODY_SENSORS);
+ SENSOR_PERMISSIONS.add(Manifest.permission.BACKGROUND_CAMERA);
+ SENSOR_PERMISSIONS.add(Manifest.permission.RECORD_BACKGROUND_AUDIO);
+ SENSOR_PERMISSIONS.add(Manifest.permission.BODY_SENSORS_BACKGROUND);
+ SENSOR_PERMISSIONS.add(
+ Manifest.permission.BODY_SENSORS_WRIST_TEMPERATURE);
+ SENSOR_PERMISSIONS.add(
+ Manifest.permission.BODY_SENSORS_WRIST_TEMPERATURE_BACKGROUND);
+ }
+
+ private boolean canGrantPermission(CallerIdentity caller, String permission,
+ String targetPackageName) {
+ boolean isPostQAdmin = getTargetSdk(caller.getPackageName(), caller.getUserId())
+ >= android.os.Build.VERSION_CODES.Q;
+ if (!isPostQAdmin) {
+ // Legacy admins assume that they cannot control pre-M apps
+ if (getTargetSdk(targetPackageName, caller.getUserId())
+ < android.os.Build.VERSION_CODES.M) {
+ return false;
+ }
+ }
+ if (!isRuntimePermission(permission)) {
+ return false;
+ }
+ return true;
+ }
+
private void enforcePermissionGrantStateOnFinancedDevice(
String packageName, String permission) {
if (!Manifest.permission.READ_PHONE_STATE.equals(permission)) {
@@ -17637,7 +17741,6 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub {
synchronized (getLockObject()) {
if (isPermissionCheckFlagEnabled()) {
- // TODO: add support for DELEGATION_SECURITY_LOGGING
enforcePermission(MANAGE_DEVICE_POLICY_SECURITY_LOGGING, caller.getPackageName(),
UserHandle.USER_ALL);
} else {
@@ -17718,7 +17821,8 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub {
final CallerIdentity caller = getCallerIdentity(admin, packageName);
if (isPermissionCheckFlagEnabled()) {
- // TODO: Restore the "affiliated users" check
+ Preconditions.checkCallAuthorization(isOrganizationOwnedDeviceWithManagedProfile()
+ || areAllUsersAffiliatedWithDeviceLocked());
enforcePermission(MANAGE_DEVICE_POLICY_SECURITY_LOGGING, caller.getPackageName(),
UserHandle.USER_ALL);
} else {
@@ -17770,7 +17874,9 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub {
final CallerIdentity caller = getCallerIdentity(admin, packageName);
if (isPermissionCheckFlagEnabled()) {
- // TODO: Restore the "affiliated users" check
+ Preconditions.checkCallAuthorization(isOrganizationOwnedDeviceWithManagedProfile()
+ || areAllUsersAffiliatedWithDeviceLocked());
+
enforcePermission(MANAGE_DEVICE_POLICY_SECURITY_LOGGING, caller.getPackageName(),
UserHandle.USER_ALL);
} else {
@@ -22321,244 +22427,208 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub {
// Permissions of existing DPC types.
private static final List<String> DEFAULT_DEVICE_OWNER_PERMISSIONS = List.of(
- MANAGE_DEVICE_POLICY_ACROSS_USERS_FULL,
+ MANAGE_DEVICE_POLICY_ACCOUNT_MANAGEMENT,
MANAGE_DEVICE_POLICY_ACROSS_USERS,
+ MANAGE_DEVICE_POLICY_ACROSS_USERS_FULL,
MANAGE_DEVICE_POLICY_ACROSS_USERS_SECURITY_CRITICAL,
- SET_TIME,
- SET_TIME_ZONE,
- MANAGE_DEVICE_POLICY_ORGANIZATION_IDENTITY,
- MANAGE_DEVICE_POLICY_RUNTIME_PERMISSIONS,
- MANAGE_DEVICE_POLICY_WIFI,
- MANAGE_DEVICE_POLICY_WIPE_DATA,
- MANAGE_DEVICE_POLICY_SCREEN_CAPTURE,
- MANAGE_DEVICE_POLICY_SYSTEM_UPDATES,
- MANAGE_DEVICE_POLICY_SECURITY_LOGGING,
- MANAGE_DEVICE_POLICY_USB_DATA_SIGNALLING,
- MANAGE_DEVICE_POLICY_MTE,
- MANAGE_DEVICE_POLICY_LOCK_CREDENTIALS,
- MANAGE_DEVICE_POLICY_PACKAGE_STATE,
- MANAGE_DEVICE_POLICY_LOCK,
- MANAGE_DEVICE_POLICY_FACTORY_RESET,
- MANAGE_DEVICE_POLICY_KEYGUARD,
- MANAGE_DEVICE_POLICY_CERTIFICATES,
- MANAGE_DEVICE_POLICY_KEYGUARD,
- MANAGE_DEVICE_POLICY_RUNTIME_PERMISSIONS,
- MANAGE_DEVICE_POLICY_SUPPORT_MESSAGE,
- MANAGE_DEVICE_POLICY_APPS_CONTROL,
- MANAGE_DEVICE_POLICY_LOCK_TASK,
- MANAGE_DEVICE_POLICY_ACCOUNT_MANAGEMENT,
- MANAGE_DEVICE_POLICY_CAMERA,
- MANAGE_DEVICE_POLICY_COMMON_CRITERIA_MODE,
- MANAGE_DEVICE_POLICY_DEFAULT_SMS,
- MANAGE_DEVICE_POLICY_PACKAGE_STATE,
- MANAGE_DEVICE_POLICY_PROFILE_INTERACTION,
- MANAGE_DEVICE_POLICY_RESET_PASSWORD,
- MANAGE_DEVICE_POLICY_STATUS_BAR,
- MANAGE_DEVICE_POLICY_LOCK_TASK,
- MANAGE_DEVICE_POLICY_ACCOUNT_MANAGEMENT,
MANAGE_DEVICE_POLICY_AIRPLANE_MODE,
+ MANAGE_DEVICE_POLICY_APPS_CONTROL,
+ MANAGE_DEVICE_POLICY_APP_RESTRICTIONS,
MANAGE_DEVICE_POLICY_AUDIO_OUTPUT,
MANAGE_DEVICE_POLICY_AUTOFILL,
MANAGE_DEVICE_POLICY_BLUETOOTH,
MANAGE_DEVICE_POLICY_CALLS,
MANAGE_DEVICE_POLICY_CAMERA,
+ MANAGE_DEVICE_POLICY_CERTIFICATES,
+ MANAGE_DEVICE_POLICY_COMMON_CRITERIA_MODE,
MANAGE_DEVICE_POLICY_DEBUGGING_FEATURES,
+ MANAGE_DEVICE_POLICY_DEFAULT_SMS,
MANAGE_DEVICE_POLICY_DISPLAY,
MANAGE_DEVICE_POLICY_FACTORY_RESET,
MANAGE_DEVICE_POLICY_FUN,
MANAGE_DEVICE_POLICY_INSTALL_UNKNOWN_SOURCES,
+ MANAGE_DEVICE_POLICY_KEYGUARD,
MANAGE_DEVICE_POLICY_LOCALE,
MANAGE_DEVICE_POLICY_LOCATION,
+ MANAGE_DEVICE_POLICY_LOCK,
MANAGE_DEVICE_POLICY_LOCK_CREDENTIALS,
+ MANAGE_DEVICE_POLICY_LOCK_TASK,
MANAGE_DEVICE_POLICY_MICROPHONE,
MANAGE_DEVICE_POLICY_MOBILE_NETWORK,
+ MANAGE_DEVICE_POLICY_MTE,
MANAGE_DEVICE_POLICY_NEARBY_COMMUNICATION,
+ MANAGE_DEVICE_POLICY_ORGANIZATION_IDENTITY,
+ MANAGE_DEVICE_POLICY_PACKAGE_STATE,
MANAGE_DEVICE_POLICY_PHYSICAL_MEDIA,
MANAGE_DEVICE_POLICY_PRINTING,
- MANAGE_DEVICE_POLICY_RESTRICT_PRIVATE_DNS,
MANAGE_DEVICE_POLICY_PROFILES,
MANAGE_DEVICE_POLICY_PROFILE_INTERACTION,
+ MANAGE_DEVICE_POLICY_RESET_PASSWORD,
+ MANAGE_DEVICE_POLICY_RESTRICT_PRIVATE_DNS,
+ MANAGE_DEVICE_POLICY_RUNTIME_PERMISSIONS,
MANAGE_DEVICE_POLICY_SAFE_BOOT,
+ MANAGE_DEVICE_POLICY_SCREEN_CAPTURE,
MANAGE_DEVICE_POLICY_SCREEN_CONTENT,
+ MANAGE_DEVICE_POLICY_SECURITY_LOGGING,
MANAGE_DEVICE_POLICY_SMS,
+ MANAGE_DEVICE_POLICY_STATUS_BAR,
+ MANAGE_DEVICE_POLICY_SUPPORT_MESSAGE,
MANAGE_DEVICE_POLICY_SYSTEM_DIALOGS,
+ MANAGE_DEVICE_POLICY_SYSTEM_UPDATES,
MANAGE_DEVICE_POLICY_TIME,
+ MANAGE_DEVICE_POLICY_USB_DATA_SIGNALLING,
MANAGE_DEVICE_POLICY_USB_FILE_TRANSFER,
MANAGE_DEVICE_POLICY_USERS,
MANAGE_DEVICE_POLICY_VPN,
MANAGE_DEVICE_POLICY_WALLPAPER,
MANAGE_DEVICE_POLICY_WIFI,
MANAGE_DEVICE_POLICY_WINDOWS,
- MANAGE_DEVICE_POLICY_APP_RESTRICTIONS
+ MANAGE_DEVICE_POLICY_WIPE_DATA,
+ SET_TIME,
+ SET_TIME_ZONE
);
private static final List<String> FINANCED_DEVICE_OWNER_PERMISSIONS = List.of(
- MANAGE_DEVICE_POLICY_ACROSS_USERS_FULL,
MANAGE_DEVICE_POLICY_ACROSS_USERS,
+ MANAGE_DEVICE_POLICY_ACROSS_USERS_FULL,
MANAGE_DEVICE_POLICY_ACROSS_USERS_SECURITY_CRITICAL,
- MANAGE_DEVICE_POLICY_ORGANIZATION_IDENTITY,
- MANAGE_DEVICE_POLICY_RUNTIME_PERMISSIONS,
- MANAGE_DEVICE_POLICY_ORGANIZATION_IDENTITY,
- MANAGE_DEVICE_POLICY_FACTORY_RESET,
- MANAGE_DEVICE_POLICY_KEYGUARD,
- MANAGE_DEVICE_POLICY_RUNTIME_PERMISSIONS,
- MANAGE_DEVICE_POLICY_SUPPORT_MESSAGE,
MANAGE_DEVICE_POLICY_APPS_CONTROL,
- MANAGE_DEVICE_POLICY_LOCK_TASK,
MANAGE_DEVICE_POLICY_CALLS,
MANAGE_DEVICE_POLICY_DEBUGGING_FEATURES,
+ MANAGE_DEVICE_POLICY_FACTORY_RESET,
MANAGE_DEVICE_POLICY_INSTALL_UNKNOWN_SOURCES,
- MANAGE_DEVICE_POLICY_USERS,
+ MANAGE_DEVICE_POLICY_KEYGUARD,
+ MANAGE_DEVICE_POLICY_LOCK_TASK,
+ MANAGE_DEVICE_POLICY_ORGANIZATION_IDENTITY,
+ MANAGE_DEVICE_POLICY_RUNTIME_PERMISSIONS,
MANAGE_DEVICE_POLICY_SAFE_BOOT,
+ MANAGE_DEVICE_POLICY_SUPPORT_MESSAGE,
MANAGE_DEVICE_POLICY_TIME,
- MANAGE_DEVICE_POLICY_LOCK_CREDENTIALS);
- private static final List<String> PROFILE_OWNER_OF_ORGANIZATION_OWNED_DEVICE_PERMISSIONS =
+ MANAGE_DEVICE_POLICY_USERS,
+ MANAGE_DEVICE_POLICY_LOCK_CREDENTIALS
+ );
+
+ /**
+ * All the permisisons granted to a profile owner.
+ */
+ private static final List<String> PROFILE_OWNER_PERMISSIONS =
List.of(
- MANAGE_DEVICE_POLICY_ACROSS_USERS,
+ MANAGE_DEVICE_POLICY_ACCOUNT_MANAGEMENT,
MANAGE_DEVICE_POLICY_ACROSS_USERS_SECURITY_CRITICAL,
- SET_TIME,
- SET_TIME_ZONE,
- MANAGE_DEVICE_POLICY_ORGANIZATION_IDENTITY,
- MANAGE_DEVICE_POLICY_RUNTIME_PERMISSIONS,
- MANAGE_DEVICE_POLICY_SUPPORT_MESSAGE,
MANAGE_DEVICE_POLICY_APPS_CONTROL,
- MANAGE_DEVICE_POLICY_WIFI,
- MANAGE_DEVICE_POLICY_WIPE_DATA,
- MANAGE_DEVICE_POLICY_SCREEN_CAPTURE,
- MANAGE_DEVICE_POLICY_SYSTEM_UPDATES,
- MANAGE_DEVICE_POLICY_SECURITY_LOGGING,
- MANAGE_DEVICE_POLICY_USB_DATA_SIGNALLING,
- MANAGE_DEVICE_POLICY_MTE,
- MANAGE_DEVICE_POLICY_LOCK_CREDENTIALS,
- MANAGE_DEVICE_POLICY_PACKAGE_STATE,
- MANAGE_DEVICE_POLICY_LOCK,
- MANAGE_DEVICE_POLICY_FACTORY_RESET,
- MANAGE_DEVICE_POLICY_KEYGUARD,
- MANAGE_DEVICE_POLICY_AIRPLANE_MODE,
- MANAGE_DEVICE_POLICY_ACCOUNT_MANAGEMENT,
+ MANAGE_DEVICE_POLICY_APP_RESTRICTIONS,
MANAGE_DEVICE_POLICY_AUDIO_OUTPUT,
MANAGE_DEVICE_POLICY_AUTOFILL,
- MANAGE_DEVICE_POLICY_BLUETOOTH,
MANAGE_DEVICE_POLICY_CALLS,
- MANAGE_DEVICE_POLICY_CAMERA,
MANAGE_DEVICE_POLICY_DEBUGGING_FEATURES,
MANAGE_DEVICE_POLICY_DISPLAY,
MANAGE_DEVICE_POLICY_FACTORY_RESET,
MANAGE_DEVICE_POLICY_INSTALL_UNKNOWN_SOURCES,
+ MANAGE_DEVICE_POLICY_KEYGUARD,
MANAGE_DEVICE_POLICY_LOCALE,
MANAGE_DEVICE_POLICY_LOCATION,
+ MANAGE_DEVICE_POLICY_LOCK,
MANAGE_DEVICE_POLICY_LOCK_CREDENTIALS,
- MANAGE_DEVICE_POLICY_MICROPHONE,
- MANAGE_DEVICE_POLICY_MOBILE_NETWORK,
MANAGE_DEVICE_POLICY_NEARBY_COMMUNICATION,
- MANAGE_DEVICE_POLICY_PHYSICAL_MEDIA,
+ MANAGE_DEVICE_POLICY_ORGANIZATION_IDENTITY,
+ MANAGE_DEVICE_POLICY_PACKAGE_STATE,
MANAGE_DEVICE_POLICY_PRINTING,
MANAGE_DEVICE_POLICY_PROFILES,
MANAGE_DEVICE_POLICY_PROFILE_INTERACTION,
- MANAGE_DEVICE_POLICY_RESTRICT_PRIVATE_DNS,
- MANAGE_DEVICE_POLICY_SAFE_BOOT,
+ MANAGE_DEVICE_POLICY_RESET_PASSWORD,
+ MANAGE_DEVICE_POLICY_RUNTIME_PERMISSIONS,
+ MANAGE_DEVICE_POLICY_SCREEN_CAPTURE,
MANAGE_DEVICE_POLICY_SCREEN_CONTENT,
- MANAGE_DEVICE_POLICY_SMS,
+ MANAGE_DEVICE_POLICY_SUPPORT_MESSAGE,
MANAGE_DEVICE_POLICY_SYSTEM_DIALOGS,
MANAGE_DEVICE_POLICY_TIME,
MANAGE_DEVICE_POLICY_VPN,
- MANAGE_DEVICE_POLICY_USB_FILE_TRANSFER,
- MANAGE_DEVICE_POLICY_COMMON_CRITERIA_MODE,
- MANAGE_DEVICE_POLICY_DEFAULT_SMS,
- MANAGE_DEVICE_POLICY_PACKAGE_STATE,
- MANAGE_DEVICE_POLICY_RESET_PASSWORD,
- MANAGE_DEVICE_POLICY_APP_RESTRICTIONS,
- MANAGE_DEVICE_POLICY_USB_FILE_TRANSFER,
- MANAGE_DEVICE_POLICY_KEYGUARD,
- MANAGE_DEVICE_POLICY_WIFI,
- MANAGE_DEVICE_POLICY_WIPE_DATA,
- MANAGE_DEVICE_POLICY_SCREEN_CAPTURE,
- MANAGE_DEVICE_POLICY_SYSTEM_UPDATES,
- MANAGE_DEVICE_POLICY_SECURITY_LOGGING,
- MANAGE_DEVICE_POLICY_USB_DATA_SIGNALLING,
- MANAGE_DEVICE_POLICY_MTE,
- MANAGE_DEVICE_POLICY_PACKAGE_STATE,
- MANAGE_DEVICE_POLICY_LOCK,
- MANAGE_DEVICE_POLICY_FACTORY_RESET,
- MANAGE_DEVICE_POLICY_KEYGUARD,
- MANAGE_DEVICE_POLICY_CERTIFICATES);
- private static final List<String> PROFILE_OWNER_ON_USER_0_PERMISSIONS = List.of(
- SET_TIME,
- SET_TIME_ZONE,
- MANAGE_DEVICE_POLICY_RUNTIME_PERMISSIONS,
- MANAGE_DEVICE_POLICY_SUPPORT_MESSAGE,
- MANAGE_DEVICE_POLICY_APPS_CONTROL,
- MANAGE_DEVICE_POLICY_LOCK_TASK,
- MANAGE_DEVICE_POLICY_RUNTIME_PERMISSIONS,
- MANAGE_DEVICE_POLICY_WIPE_DATA,
- MANAGE_DEVICE_POLICY_SCREEN_CAPTURE,
- MANAGE_DEVICE_POLICY_LOCK_CREDENTIALS,
- MANAGE_DEVICE_POLICY_PACKAGE_STATE,
- MANAGE_DEVICE_POLICY_LOCK,
- MANAGE_DEVICE_POLICY_KEYGUARD,
- MANAGE_DEVICE_POLICY_LOCK_TASK,
- MANAGE_DEVICE_POLICY_AIRPLANE_MODE,
- MANAGE_DEVICE_POLICY_BLUETOOTH,
- MANAGE_DEVICE_POLICY_DEBUGGING_FEATURES,
- MANAGE_DEVICE_POLICY_FACTORY_RESET,
- MANAGE_DEVICE_POLICY_FUN,
- MANAGE_DEVICE_POLICY_INSTALL_UNKNOWN_SOURCES,
- MANAGE_DEVICE_POLICY_MOBILE_NETWORK,
- MANAGE_DEVICE_POLICY_USERS,
- MANAGE_DEVICE_POLICY_PHYSICAL_MEDIA,
- MANAGE_DEVICE_POLICY_SAFE_BOOT,
- MANAGE_DEVICE_POLICY_SMS,
- MANAGE_DEVICE_POLICY_TIME,
- MANAGE_DEVICE_POLICY_USB_FILE_TRANSFER,
- MANAGE_DEVICE_POLICY_WINDOWS,
- MANAGE_DEVICE_POLICY_LOCK_TASK,
- MANAGE_DEVICE_POLICY_ACCOUNT_MANAGEMENT,
- MANAGE_DEVICE_POLICY_CAMERA,
- MANAGE_DEVICE_POLICY_PACKAGE_STATE,
- MANAGE_DEVICE_POLICY_RESET_PASSWORD,
- MANAGE_DEVICE_POLICY_STATUS_BAR,
- MANAGE_DEVICE_POLICY_APP_RESTRICTIONS,
- MANAGE_DEVICE_POLICY_SYSTEM_DIALOGS);
- private static final List<String> PROFILE_OWNER_PERMISSIONS = List.of(
- MANAGE_DEVICE_POLICY_ACROSS_USERS_SECURITY_CRITICAL,
- MANAGE_DEVICE_POLICY_ORGANIZATION_IDENTITY,
- MANAGE_DEVICE_POLICY_RUNTIME_PERMISSIONS,
- MANAGE_DEVICE_POLICY_SUPPORT_MESSAGE,
- MANAGE_DEVICE_POLICY_APPS_CONTROL,
- MANAGE_DEVICE_POLICY_RUNTIME_PERMISSIONS,
- MANAGE_DEVICE_POLICY_WIPE_DATA,
- MANAGE_DEVICE_POLICY_SCREEN_CAPTURE,
- MANAGE_DEVICE_POLICY_LOCK_CREDENTIALS,
- MANAGE_DEVICE_POLICY_PACKAGE_STATE,
- MANAGE_DEVICE_POLICY_LOCK,
- MANAGE_DEVICE_POLICY_KEYGUARD,
- MANAGE_DEVICE_POLICY_APPS_CONTROL,
- MANAGE_DEVICE_POLICY_ACCOUNT_MANAGEMENT,
- MANAGE_DEVICE_POLICY_AUDIO_OUTPUT,
- MANAGE_DEVICE_POLICY_AUTOFILL,
- MANAGE_DEVICE_POLICY_CALLS,
- MANAGE_DEVICE_POLICY_DEBUGGING_FEATURES,
- MANAGE_DEVICE_POLICY_DISPLAY,
- MANAGE_DEVICE_POLICY_FACTORY_RESET,
- MANAGE_DEVICE_POLICY_INSTALL_UNKNOWN_SOURCES,
- MANAGE_DEVICE_POLICY_LOCALE,
- MANAGE_DEVICE_POLICY_LOCATION,
- MANAGE_DEVICE_POLICY_LOCK_CREDENTIALS,
- MANAGE_DEVICE_POLICY_NEARBY_COMMUNICATION,
- MANAGE_DEVICE_POLICY_PRINTING,
- MANAGE_DEVICE_POLICY_PROFILES,
- MANAGE_DEVICE_POLICY_PROFILE_INTERACTION,
- MANAGE_DEVICE_POLICY_SCREEN_CONTENT,
- MANAGE_DEVICE_POLICY_SYSTEM_DIALOGS,
- MANAGE_DEVICE_POLICY_TIME,
- MANAGE_DEVICE_POLICY_VPN,
- MANAGE_DEVICE_POLICY_PACKAGE_STATE,
- MANAGE_DEVICE_POLICY_PROFILE_INTERACTION,
- MANAGE_DEVICE_POLICY_RESET_PASSWORD,
- MANAGE_DEVICE_POLICY_APP_RESTRICTIONS
+ MANAGE_DEVICE_POLICY_WIPE_DATA
);
+ /**
+ * All the additional permissions granted to an organisation owned profile owner.
+ */
+ private static final List<String>
+ ADDITIONAL_PROFILE_OWNER_OF_ORGANIZATION_OWNED_DEVICE_PERMISSIONS =
+ List.of(
+ MANAGE_DEVICE_POLICY_ACROSS_USERS,
+ MANAGE_DEVICE_POLICY_AIRPLANE_MODE,
+ MANAGE_DEVICE_POLICY_APPS_CONTROL,
+ MANAGE_DEVICE_POLICY_BLUETOOTH,
+ MANAGE_DEVICE_POLICY_CAMERA,
+ MANAGE_DEVICE_POLICY_CERTIFICATES,
+ MANAGE_DEVICE_POLICY_COMMON_CRITERIA_MODE,
+ MANAGE_DEVICE_POLICY_DEFAULT_SMS,
+ MANAGE_DEVICE_POLICY_LOCALE,
+ MANAGE_DEVICE_POLICY_MICROPHONE,
+ MANAGE_DEVICE_POLICY_MOBILE_NETWORK,
+ MANAGE_DEVICE_POLICY_MTE,
+ MANAGE_DEVICE_POLICY_NEARBY_COMMUNICATION,
+ MANAGE_DEVICE_POLICY_PHYSICAL_MEDIA,
+ MANAGE_DEVICE_POLICY_RESTRICT_PRIVATE_DNS,
+ MANAGE_DEVICE_POLICY_SAFE_BOOT,
+ MANAGE_DEVICE_POLICY_SECURITY_LOGGING,
+ MANAGE_DEVICE_POLICY_SMS,
+ MANAGE_DEVICE_POLICY_SYSTEM_UPDATES,
+ MANAGE_DEVICE_POLICY_USB_DATA_SIGNALLING,
+ MANAGE_DEVICE_POLICY_USB_FILE_TRANSFER,
+ MANAGE_DEVICE_POLICY_WIFI,
+ SET_TIME,
+ SET_TIME_ZONE
+ );
+
+
+ private static final List<String> ADDITIONAL_PROFILE_OWNER_ON_USER_0_PERMISSIONS =
+ List.of(
+ MANAGE_DEVICE_POLICY_AIRPLANE_MODE,
+ MANAGE_DEVICE_POLICY_BLUETOOTH,
+ MANAGE_DEVICE_POLICY_CAMERA,
+ MANAGE_DEVICE_POLICY_DISPLAY,
+ MANAGE_DEVICE_POLICY_FUN,
+ MANAGE_DEVICE_POLICY_LOCK_TASK,
+ MANAGE_DEVICE_POLICY_MOBILE_NETWORK,
+ MANAGE_DEVICE_POLICY_PHYSICAL_MEDIA,
+ MANAGE_DEVICE_POLICY_PRINTING,
+ MANAGE_DEVICE_POLICY_PROFILES,
+ MANAGE_DEVICE_POLICY_PROFILE_INTERACTION,
+ MANAGE_DEVICE_POLICY_SAFE_BOOT,
+ MANAGE_DEVICE_POLICY_SMS,
+ MANAGE_DEVICE_POLICY_STATUS_BAR,
+ MANAGE_DEVICE_POLICY_SYSTEM_DIALOGS,
+ MANAGE_DEVICE_POLICY_USB_FILE_TRANSFER,
+ MANAGE_DEVICE_POLICY_USERS,
+ MANAGE_DEVICE_POLICY_WINDOWS,
+ SET_TIME,
+ SET_TIME_ZONE
+ );
+
+ /**
+ * Combination of {@link PROFILE_OWNER_PERMISSIONS} and
+ * {@link ADDITIONAL_PROFILE_OWNER_OF_ORGANIZATION_OWNED_DEVICE_PERMISSIONS}.
+ */
+ private static final List<String> PROFILE_OWNER_OF_ORGANIZATION_OWNED_DEVICE_PERMISSIONS =
+ new ArrayList();
+
+ /**
+ * Combination of {@link PROFILE_OWNER_PERMISSIONS} and
+ * {@link ADDITIONAL_PROFILE_OWNER_ON_USER_0_PERMISSIONS}.
+ */
+ private static final List<String> PROFILE_OWNER_ON_USER_0_PERMISSIONS =
+ new ArrayList();
+
+
private static final HashMap<Integer, List<String>> DPC_PERMISSIONS = new HashMap<>();
{
+ // Organisation owned profile owners have all the permission of a profile owner plus
+ // some extra permissions.
+ PROFILE_OWNER_OF_ORGANIZATION_OWNED_DEVICE_PERMISSIONS.addAll(PROFILE_OWNER_PERMISSIONS);
+ PROFILE_OWNER_OF_ORGANIZATION_OWNED_DEVICE_PERMISSIONS.addAll(
+ ADDITIONAL_PROFILE_OWNER_OF_ORGANIZATION_OWNED_DEVICE_PERMISSIONS);
+ // Profile owners on user 0 have all the permission of a profile owner plus
+ // some extra permissions.
+ PROFILE_OWNER_ON_USER_0_PERMISSIONS.addAll(PROFILE_OWNER_PERMISSIONS);
+ PROFILE_OWNER_ON_USER_0_PERMISSIONS.addAll(ADDITIONAL_PROFILE_OWNER_ON_USER_0_PERMISSIONS);
+
DPC_PERMISSIONS.put(DEFAULT_DEVICE_OWNER, DEFAULT_DEVICE_OWNER_PERMISSIONS);
DPC_PERMISSIONS.put(FINANCED_DEVICE_OWNER, FINANCED_DEVICE_OWNER_PERMISSIONS);
DPC_PERMISSIONS.put(PROFILE_OWNER_OF_ORGANIZATION_OWNED_DEVICE,
@@ -22566,14 +22636,6 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub {
DPC_PERMISSIONS.put(PROFILE_OWNER_ON_USER_0, PROFILE_OWNER_ON_USER_0_PERMISSIONS);
DPC_PERMISSIONS.put(PROFILE_OWNER, PROFILE_OWNER_PERMISSIONS);
}
-
- // Map of permission Active admin DEVICE_POLICY.
- //TODO(b/254253251) Fill this map in as new permissions are added for policies.
- private static final HashMap<String, Integer> ACTIVE_ADMIN_POLICIES = new HashMap<>();
- {
- //Any ActiveAdmin is able to call the support message APIs without certain policies.
- ACTIVE_ADMIN_POLICIES.put(MANAGE_DEVICE_POLICY_SUPPORT_MESSAGE, null);
- }
//Map of Permission to Delegate Scope.
private static final HashMap<String, String> DELEGATE_SCOPES = new HashMap<>();
{
@@ -22587,123 +22649,119 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub {
private static final HashMap<String, String> CROSS_USER_PERMISSIONS =
new HashMap<>();
{
- // Time and Timezone is intrinsically global so there is no cross-user permission.
- CROSS_USER_PERMISSIONS.put(SET_TIME, null);
- CROSS_USER_PERMISSIONS.put(SET_TIME_ZONE, null);
- // system updates are intrinsically global so there is no cross-user permission
- CROSS_USER_PERMISSIONS.put(MANAGE_DEVICE_POLICY_SYSTEM_UPDATES, null);
- // security logs are intrinsically global so there is no cross-user permission
- CROSS_USER_PERMISSIONS.put(MANAGE_DEVICE_POLICY_SECURITY_LOGGING, null);
- // usb signalling is intrinsically global so there is no cross-user permission
- CROSS_USER_PERMISSIONS.put(MANAGE_DEVICE_POLICY_USB_DATA_SIGNALLING, null);
- // mte is intrinsically global so there is no cross-user permission
- CROSS_USER_PERMISSIONS.put(MANAGE_DEVICE_POLICY_MTE, null);
+ // The permissions are all intrinsically global and therefore have no cross-user permission.
CROSS_USER_PERMISSIONS.put(MANAGE_DEVICE_POLICY_FACTORY_RESET, null);
+ CROSS_USER_PERMISSIONS.put(MANAGE_DEVICE_POLICY_MTE, null);
+ CROSS_USER_PERMISSIONS.put(MANAGE_DEVICE_POLICY_SECURITY_LOGGING, null);
CROSS_USER_PERMISSIONS.put(MANAGE_DEVICE_POLICY_STATUS_BAR, null);
- // Organisation identity policy will involve data of other organisations on the device and
- // therefore the FULL cross-user permission is required.
- CROSS_USER_PERMISSIONS.put(MANAGE_DEVICE_POLICY_ORGANIZATION_IDENTITY,
- MANAGE_DEVICE_POLICY_ACROSS_USERS_FULL);
- CROSS_USER_PERMISSIONS.put(MANAGE_DEVICE_POLICY_WIFI,
- MANAGE_DEVICE_POLICY_ACROSS_USERS);
- CROSS_USER_PERMISSIONS.put(MANAGE_DEVICE_POLICY_WIPE_DATA,
- MANAGE_DEVICE_POLICY_ACROSS_USERS);
- CROSS_USER_PERMISSIONS.put(MANAGE_DEVICE_POLICY_SCREEN_CAPTURE,
- MANAGE_DEVICE_POLICY_ACROSS_USERS);
+ CROSS_USER_PERMISSIONS.put(MANAGE_DEVICE_POLICY_SYSTEM_UPDATES, null);
+ CROSS_USER_PERMISSIONS.put(MANAGE_DEVICE_POLICY_USB_DATA_SIGNALLING, null);
+ CROSS_USER_PERMISSIONS.put(SET_TIME, null);
+ CROSS_USER_PERMISSIONS.put(SET_TIME_ZONE, null);
+
+ // The permissions are all critical for securing data within the current user and
+ // therefore are protected with MANAGE_DEVICE_POLICY_ACROSS_USERS_SECURITY_CRITICAL for
+ // cross-user calls.
+ CROSS_USER_PERMISSIONS.put(MANAGE_DEVICE_POLICY_INSTALL_UNKNOWN_SOURCES,
+ MANAGE_DEVICE_POLICY_ACROSS_USERS_SECURITY_CRITICAL);
+ CROSS_USER_PERMISSIONS.put(MANAGE_DEVICE_POLICY_KEYGUARD,
+ MANAGE_DEVICE_POLICY_ACROSS_USERS_SECURITY_CRITICAL);
CROSS_USER_PERMISSIONS.put(MANAGE_DEVICE_POLICY_LOCK_CREDENTIALS,
MANAGE_DEVICE_POLICY_ACROSS_USERS_SECURITY_CRITICAL);
- CROSS_USER_PERMISSIONS.put(MANAGE_DEVICE_POLICY_PACKAGE_STATE,
- MANAGE_DEVICE_POLICY_ACROSS_USERS);
- CROSS_USER_PERMISSIONS.put(
- MANAGE_DEVICE_POLICY_LOCK, MANAGE_DEVICE_POLICY_ACROSS_USERS_FULL);
- CROSS_USER_PERMISSIONS.put(
- MANAGE_DEVICE_POLICY_KEYGUARD, MANAGE_DEVICE_POLICY_ACROSS_USERS_SECURITY_CRITICAL);
- // Granting runtime permissions can grant applications significant powers therefore the FULL
- // cross-user permission is required.
- CROSS_USER_PERMISSIONS.put(MANAGE_DEVICE_POLICY_RUNTIME_PERMISSIONS,
- MANAGE_DEVICE_POLICY_ACROSS_USERS_FULL);
- CROSS_USER_PERMISSIONS.put(MANAGE_DEVICE_POLICY_SUPPORT_MESSAGE,
- MANAGE_DEVICE_POLICY_ACROSS_USERS_FULL);
- CROSS_USER_PERMISSIONS.put(MANAGE_DEVICE_POLICY_APPS_CONTROL,
- MANAGE_DEVICE_POLICY_ACROSS_USERS_FULL);
- CROSS_USER_PERMISSIONS.put(MANAGE_DEVICE_POLICY_LOCK_TASK,
- MANAGE_DEVICE_POLICY_ACROSS_USERS_FULL);
+
+ // These permissions are required for securing device ownership without accessing user data
+ // and therefore are protected with MANAGE_DEVICE_POLICY_ACROSS_USERS for cross-user calls.
CROSS_USER_PERMISSIONS.put(MANAGE_DEVICE_POLICY_ACCOUNT_MANAGEMENT,
MANAGE_DEVICE_POLICY_ACROSS_USERS);
CROSS_USER_PERMISSIONS.put(MANAGE_DEVICE_POLICY_AIRPLANE_MODE,
MANAGE_DEVICE_POLICY_ACROSS_USERS);
- CROSS_USER_PERMISSIONS.put(MANAGE_DEVICE_POLICY_AUDIO_OUTPUT,
- MANAGE_DEVICE_POLICY_ACROSS_USERS_FULL);
- CROSS_USER_PERMISSIONS.put(MANAGE_DEVICE_POLICY_AUTOFILL,
- MANAGE_DEVICE_POLICY_ACROSS_USERS_FULL);
CROSS_USER_PERMISSIONS.put(MANAGE_DEVICE_POLICY_BLUETOOTH,
MANAGE_DEVICE_POLICY_ACROSS_USERS);
CROSS_USER_PERMISSIONS.put(MANAGE_DEVICE_POLICY_CALLS,
MANAGE_DEVICE_POLICY_ACROSS_USERS);
CROSS_USER_PERMISSIONS.put(MANAGE_DEVICE_POLICY_CAMERA,
MANAGE_DEVICE_POLICY_ACROSS_USERS);
+ CROSS_USER_PERMISSIONS.put(MANAGE_DEVICE_POLICY_DEFAULT_SMS,
+ MANAGE_DEVICE_POLICY_ACROSS_USERS);
+ CROSS_USER_PERMISSIONS.put(MANAGE_DEVICE_POLICY_MICROPHONE,
+ MANAGE_DEVICE_POLICY_ACROSS_USERS);
+ CROSS_USER_PERMISSIONS.put(MANAGE_DEVICE_POLICY_MOBILE_NETWORK,
+ MANAGE_DEVICE_POLICY_ACROSS_USERS);
+ CROSS_USER_PERMISSIONS.put(MANAGE_DEVICE_POLICY_NEARBY_COMMUNICATION,
+ MANAGE_DEVICE_POLICY_ACROSS_USERS);
+ CROSS_USER_PERMISSIONS.put(MANAGE_DEVICE_POLICY_PHYSICAL_MEDIA,
+ MANAGE_DEVICE_POLICY_ACROSS_USERS);
+ CROSS_USER_PERMISSIONS.put(MANAGE_DEVICE_POLICY_PACKAGE_STATE,
+ MANAGE_DEVICE_POLICY_ACROSS_USERS);
+ CROSS_USER_PERMISSIONS.put(MANAGE_DEVICE_POLICY_RESTRICT_PRIVATE_DNS,
+ MANAGE_DEVICE_POLICY_ACROSS_USERS);
+ CROSS_USER_PERMISSIONS.put(MANAGE_DEVICE_POLICY_SCREEN_CAPTURE,
+ MANAGE_DEVICE_POLICY_ACROSS_USERS);
+ CROSS_USER_PERMISSIONS.put(MANAGE_DEVICE_POLICY_SMS,
+ MANAGE_DEVICE_POLICY_ACROSS_USERS);
+ CROSS_USER_PERMISSIONS.put(MANAGE_DEVICE_POLICY_SAFE_BOOT,
+ MANAGE_DEVICE_POLICY_ACROSS_USERS);
+ CROSS_USER_PERMISSIONS.put(MANAGE_DEVICE_POLICY_TIME,
+ MANAGE_DEVICE_POLICY_ACROSS_USERS);
+ CROSS_USER_PERMISSIONS.put(MANAGE_DEVICE_POLICY_USB_FILE_TRANSFER,
+ MANAGE_DEVICE_POLICY_ACROSS_USERS);
+ CROSS_USER_PERMISSIONS.put(MANAGE_DEVICE_POLICY_WIFI,
+ MANAGE_DEVICE_POLICY_ACROSS_USERS);
+ CROSS_USER_PERMISSIONS.put(MANAGE_DEVICE_POLICY_WIPE_DATA,
+ MANAGE_DEVICE_POLICY_ACROSS_USERS);
+
+ // These permissions may grant access to user data and therefore must be protected with
+ // MANAGE_DEVICE_POLICY_ACROSS_USERS_FULL for cross-user calls.
+ CROSS_USER_PERMISSIONS.put(MANAGE_DEVICE_POLICY_APPS_CONTROL,
+ MANAGE_DEVICE_POLICY_ACROSS_USERS_FULL);
+ CROSS_USER_PERMISSIONS.put(MANAGE_DEVICE_POLICY_APP_RESTRICTIONS,
+ MANAGE_DEVICE_POLICY_ACROSS_USERS_FULL);
+ CROSS_USER_PERMISSIONS.put(MANAGE_DEVICE_POLICY_AUDIO_OUTPUT,
+ MANAGE_DEVICE_POLICY_ACROSS_USERS_FULL);
+ CROSS_USER_PERMISSIONS.put(MANAGE_DEVICE_POLICY_AUTOFILL,
+ MANAGE_DEVICE_POLICY_ACROSS_USERS_FULL);
+ CROSS_USER_PERMISSIONS.put(MANAGE_DEVICE_POLICY_COMMON_CRITERIA_MODE,
+ MANAGE_DEVICE_POLICY_ACROSS_USERS_FULL);
CROSS_USER_PERMISSIONS.put(MANAGE_DEVICE_POLICY_DEBUGGING_FEATURES,
MANAGE_DEVICE_POLICY_ACROSS_USERS_FULL);
CROSS_USER_PERMISSIONS.put(MANAGE_DEVICE_POLICY_DISPLAY,
MANAGE_DEVICE_POLICY_ACROSS_USERS_FULL);
- CROSS_USER_PERMISSIONS.put(MANAGE_DEVICE_POLICY_FACTORY_RESET,
- MANAGE_DEVICE_POLICY_ACROSS_USERS_FULL);
CROSS_USER_PERMISSIONS.put(MANAGE_DEVICE_POLICY_FUN,
MANAGE_DEVICE_POLICY_ACROSS_USERS_FULL);
- CROSS_USER_PERMISSIONS.put(MANAGE_DEVICE_POLICY_INSTALL_UNKNOWN_SOURCES,
- MANAGE_DEVICE_POLICY_ACROSS_USERS_SECURITY_CRITICAL);
CROSS_USER_PERMISSIONS.put(MANAGE_DEVICE_POLICY_LOCALE,
MANAGE_DEVICE_POLICY_ACROSS_USERS_FULL);
CROSS_USER_PERMISSIONS.put(MANAGE_DEVICE_POLICY_LOCATION,
MANAGE_DEVICE_POLICY_ACROSS_USERS_FULL);
- CROSS_USER_PERMISSIONS.put(MANAGE_DEVICE_POLICY_MICROPHONE,
- MANAGE_DEVICE_POLICY_ACROSS_USERS);
- CROSS_USER_PERMISSIONS.put(MANAGE_DEVICE_POLICY_MOBILE_NETWORK,
- MANAGE_DEVICE_POLICY_ACROSS_USERS);
- CROSS_USER_PERMISSIONS.put(MANAGE_DEVICE_POLICY_NEARBY_COMMUNICATION,
- MANAGE_DEVICE_POLICY_ACROSS_USERS);
- CROSS_USER_PERMISSIONS.put(MANAGE_DEVICE_POLICY_PHYSICAL_MEDIA,
- MANAGE_DEVICE_POLICY_ACROSS_USERS);
- CROSS_USER_PERMISSIONS.put(MANAGE_DEVICE_POLICY_PRINTING,
+ CROSS_USER_PERMISSIONS.put(MANAGE_DEVICE_POLICY_LOCK,
+ MANAGE_DEVICE_POLICY_ACROSS_USERS_FULL);
+ CROSS_USER_PERMISSIONS.put(MANAGE_DEVICE_POLICY_LOCK_TASK,
+ MANAGE_DEVICE_POLICY_ACROSS_USERS_FULL);
+ CROSS_USER_PERMISSIONS.put(MANAGE_DEVICE_POLICY_ORGANIZATION_IDENTITY,
MANAGE_DEVICE_POLICY_ACROSS_USERS_FULL);
- CROSS_USER_PERMISSIONS.put(MANAGE_DEVICE_POLICY_RESTRICT_PRIVATE_DNS,
- MANAGE_DEVICE_POLICY_ACROSS_USERS);
CROSS_USER_PERMISSIONS.put(MANAGE_DEVICE_POLICY_PROFILES,
MANAGE_DEVICE_POLICY_ACROSS_USERS_FULL);
CROSS_USER_PERMISSIONS.put(MANAGE_DEVICE_POLICY_PROFILE_INTERACTION,
MANAGE_DEVICE_POLICY_ACROSS_USERS_FULL);
- CROSS_USER_PERMISSIONS.put(MANAGE_DEVICE_POLICY_SAFE_BOOT,
- MANAGE_DEVICE_POLICY_ACROSS_USERS);
+ CROSS_USER_PERMISSIONS.put(MANAGE_DEVICE_POLICY_PRINTING,
+ MANAGE_DEVICE_POLICY_ACROSS_USERS_FULL);
+ CROSS_USER_PERMISSIONS.put(MANAGE_DEVICE_POLICY_RESET_PASSWORD,
+ MANAGE_DEVICE_POLICY_ACROSS_USERS_FULL);
+ CROSS_USER_PERMISSIONS.put(MANAGE_DEVICE_POLICY_RUNTIME_PERMISSIONS,
+ MANAGE_DEVICE_POLICY_ACROSS_USERS_FULL);
CROSS_USER_PERMISSIONS.put(MANAGE_DEVICE_POLICY_SCREEN_CONTENT,
MANAGE_DEVICE_POLICY_ACROSS_USERS_FULL);
- CROSS_USER_PERMISSIONS.put(MANAGE_DEVICE_POLICY_SMS,
- MANAGE_DEVICE_POLICY_ACROSS_USERS);
+ CROSS_USER_PERMISSIONS.put(MANAGE_DEVICE_POLICY_SUPPORT_MESSAGE,
+ MANAGE_DEVICE_POLICY_ACROSS_USERS_FULL);
CROSS_USER_PERMISSIONS.put(MANAGE_DEVICE_POLICY_SYSTEM_DIALOGS,
MANAGE_DEVICE_POLICY_ACROSS_USERS_FULL);
- CROSS_USER_PERMISSIONS.put(MANAGE_DEVICE_POLICY_TIME,
- MANAGE_DEVICE_POLICY_ACROSS_USERS);
- CROSS_USER_PERMISSIONS.put(MANAGE_DEVICE_POLICY_USB_FILE_TRANSFER,
- MANAGE_DEVICE_POLICY_ACROSS_USERS);
CROSS_USER_PERMISSIONS.put(MANAGE_DEVICE_POLICY_USERS,
MANAGE_DEVICE_POLICY_ACROSS_USERS_FULL);
CROSS_USER_PERMISSIONS.put(MANAGE_DEVICE_POLICY_VPN,
MANAGE_DEVICE_POLICY_ACROSS_USERS_FULL);
CROSS_USER_PERMISSIONS.put(MANAGE_DEVICE_POLICY_WALLPAPER,
MANAGE_DEVICE_POLICY_ACROSS_USERS_FULL);
- CROSS_USER_PERMISSIONS.put(MANAGE_DEVICE_POLICY_WIFI,
- MANAGE_DEVICE_POLICY_ACROSS_USERS);
CROSS_USER_PERMISSIONS.put(MANAGE_DEVICE_POLICY_WINDOWS,
MANAGE_DEVICE_POLICY_ACROSS_USERS_FULL);
- CROSS_USER_PERMISSIONS.put(MANAGE_DEVICE_POLICY_APP_RESTRICTIONS,
- MANAGE_DEVICE_POLICY_ACROSS_USERS_FULL);
- CROSS_USER_PERMISSIONS.put(MANAGE_DEVICE_POLICY_COMMON_CRITERIA_MODE,
- MANAGE_DEVICE_POLICY_ACROSS_USERS_FULL);
- CROSS_USER_PERMISSIONS.put(MANAGE_DEVICE_POLICY_DEFAULT_SMS,
- MANAGE_DEVICE_POLICY_ACROSS_USERS);
- CROSS_USER_PERMISSIONS.put(MANAGE_DEVICE_POLICY_PACKAGE_STATE,
- MANAGE_DEVICE_POLICY_ACROSS_USERS);
- CROSS_USER_PERMISSIONS.put(MANAGE_DEVICE_POLICY_RESET_PASSWORD,
- MANAGE_DEVICE_POLICY_ACROSS_USERS_FULL);
}
/**
@@ -22727,6 +22785,26 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub {
}
/**
+ * Checks if the calling process has been granted permission to apply a device policy on a
+ * specific user.
+ * The given permission will be checked along with its associated cross-user permission if it
+ * exists and the target user is different to the calling user.
+ * Returns an {@link EnforcingAdmin} for the caller.
+ *
+ * @param admin the component name of the admin.
+ * @param callerPackageName The package name of the calling application.
+ * @param permission The name of the permission being checked.
+ * @param deviceAdminPolicy The userId of the user which the caller needs permission to act on.
+ * @throws SecurityException if the caller has not been granted the given permission,
+ * the associated cross-user permission if the caller's user is different to the target user.
+ */
+ private EnforcingAdmin enforcePermissionAndGetEnforcingAdmin(@Nullable ComponentName admin,
+ String permission, int deviceAdminPolicy, String callerPackageName, int targetUserId) {
+ enforcePermission(permission, deviceAdminPolicy, callerPackageName, targetUserId);
+ return getEnforcingAdminForCaller(admin, callerPackageName);
+ }
+
+ /**
* Checks whether the calling process has been granted permission to query a device policy on
* a specific user.
* The given permission will be checked along with its associated cross-user permission if it
@@ -22748,6 +22826,9 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub {
POLICY_IDENTIFIER_TO_PERMISSION.put(AUTO_TIMEZONE_POLICY, SET_TIME_ZONE);
}
+ private static final HashMap<String, Integer> POLICY_IDENTIFIER_TO_ACTIVE_ADMIN_POLICY =
+ new HashMap<>();
+
/**
* Checks if the calling process has been granted permission to apply a device policy on a
* specific user.
@@ -22763,6 +22844,36 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub {
private void enforcePermission(String permission, String callerPackageName, int targetUserId)
throws SecurityException {
if (!hasPermission(permission, callerPackageName, targetUserId)) {
+ // TODO(b/276920002): Split the error messages so that the cross-user permission
+ // is only mentioned when it is needed.
+ throw new SecurityException("Caller does not have the required permissions for "
+ + "this user. Permissions required: {"
+ + permission
+ + ", "
+ + CROSS_USER_PERMISSIONS.get(permission)
+ + "(if calling cross-user)"
+ + "}");
+ }
+ }
+
+ /**
+ * Checks if the calling process has been granted permission to apply a device policy on a
+ * specific user.
+ * The given permission will be checked along with its associated cross-user permission if it
+ * exists and the target user is different to the calling user.
+ *
+ * @param callerPackageName The package name of the calling application.
+ * @param permission The name of the permission being checked.
+ * @param targetUserId The userId of the user which the caller needs permission to act on.
+ * @throws SecurityException if the caller has not been granted the given permission,
+ * the associated cross-user permission if the caller's user is different to the target user.
+ */
+ private void enforcePermission(String permission, int adminPolicy,
+ String callerPackageName, int targetUserId)
+ throws SecurityException {
+ if (!hasPermissionOrAdminPolicy(permission, callerPackageName, adminPolicy, targetUserId)) {
+ // TODO(b/276920002): Split the error messages so that the cross-user permission
+ // is only mentioned when it is needed.
throw new SecurityException("Caller does not have the required permissions for "
+ "this user. Permissions required: {"
+ permission
@@ -22804,16 +22915,26 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub {
*/
private boolean hasPermission(String permission, String callerPackageName, int targetUserId) {
CallerIdentity caller = getCallerIdentity(callerPackageName);
- boolean hasPermissionOnOwnUser = hasPermission(permission, callerPackageName);
+ boolean hasPermissionOnOwnUser = hasPermission(permission, caller.getPackageName());
boolean hasPermissionOnTargetUser = true;
if (hasPermissionOnOwnUser & caller.getUserId() != targetUserId) {
hasPermissionOnTargetUser = hasPermission(CROSS_USER_PERMISSIONS.get(permission),
- callerPackageName);
+ caller.getPackageName());
}
return hasPermissionOnOwnUser && hasPermissionOnTargetUser;
}
+ private boolean hasPermissionOrAdminPolicy(String permission, String callerPackageName,
+ int adminPolicy, int targetUserId) {
+ CallerIdentity caller = getCallerIdentity(callerPackageName);
+ if (hasPermission(permission, caller.getPackageName(), targetUserId)) {
+ return true;
+ }
+ ActiveAdmin deviceAdmin = getActiveAdminForCaller(null, caller);
+ return deviceAdmin != null && deviceAdmin.info.usesPolicy(adminPolicy);
+ }
+
/**
* Return whether the calling process has been granted the given permission.
*
@@ -22856,23 +22977,6 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub {
if (DELEGATE_SCOPES.containsKey(permission)) {
return isCallerDelegate(caller, DELEGATE_SCOPES.get(permission));
}
- // Check if the caller is an active admin that uses a certain policy.
- if (ACTIVE_ADMIN_POLICIES.containsKey(permission)) {
- try {
- if (ACTIVE_ADMIN_POLICIES.get(permission) != null) {
- return getActiveAdminForCallerLocked(
- null, ACTIVE_ADMIN_POLICIES.get(permission), false) != null;
- } else {
- // If the permission maps to no policy (null) this means that any active admin
- // has permission.
- return isCallerActiveAdminOrDelegate(caller, null);
- }
- } catch (SecurityException e) {
- // A security exception means there is not an active admin with permission and
- // therefore
- return false;
- }
- }
return false;
}
@@ -22925,9 +23029,7 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub {
if (admin != null) {
return EnforcingAdmin.createDeviceAdminEnforcingAdmin(who, userId, admin);
}
- if (admin == null) {
- admin = getUserData(userId).createOrGetPermissionBasedAdmin(userId);
- }
+ admin = getUserData(userId).createOrGetPermissionBasedAdmin(userId);
return EnforcingAdmin.createEnforcingAdmin(caller.getPackageName(), userId, admin);
}
@@ -23476,15 +23578,13 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub {
// We need to add a mapping of policyId to permission in POLICY_IDENTIFIER_TO_PERMISSION
// for each migrated permission.
private List<ActiveAdmin> getNonDPCActiveAdminsForPolicyLocked(String policyIdentifier) {
- String permission = POLICY_IDENTIFIER_TO_PERMISSION.get(policyIdentifier);
- if (permission == null) {
- Slogf.e(LOG_TAG, "Can't find a permission for %s in POLICY_IDENTIFIER_TO_PERMISSION",
+ Integer activeAdminPolicy = POLICY_IDENTIFIER_TO_ACTIVE_ADMIN_POLICY.get(policyIdentifier);
+ if (activeAdminPolicy == null) {
+ Slogf.e(LOG_TAG,
+ "Can't find a active admin policy for %s in POLICY_IDENTIFIER_TO_PERMISSION",
policyIdentifier);
return new ArrayList<>();
}
- if (!ACTIVE_ADMIN_POLICIES.containsKey(permission)) {
- return new ArrayList<>();
- }
List<ActiveAdmin> admins = new ArrayList<>();
for (UserInfo userInfo : mUserManager.getUsers()) {
@@ -23495,7 +23595,7 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub {
}
DevicePolicyData policy = getUserDataUnchecked(userInfo.id);
if (isActiveAdminWithPolicyForUserLocked(
- policy.mAdminMap.get(admin), ACTIVE_ADMIN_POLICIES.get(permission),
+ policy.mAdminMap.get(admin), activeAdminPolicy,
userInfo.id)) {
admins.add(policy.mAdminMap.get(admin));
}
diff --git a/services/tests/servicestests/src/com/android/server/display/AutomaticBrightnessControllerTest.java b/services/tests/servicestests/src/com/android/server/display/AutomaticBrightnessControllerTest.java
index fc251526476e..3bef413a3e72 100644
--- a/services/tests/servicestests/src/com/android/server/display/AutomaticBrightnessControllerTest.java
+++ b/services/tests/servicestests/src/com/android/server/display/AutomaticBrightnessControllerTest.java
@@ -126,7 +126,7 @@ public class AutomaticBrightnessControllerTest {
return mClock::now;
}
- }, // pass in test looper instead, pass in offsetable clock
+ }, // pass in test looper instead, pass in offsettable clock
() -> { }, mTestLooper.getLooper(), mSensorManager, lightSensor,
mBrightnessMappingStrategy, LIGHT_SENSOR_WARMUP_TIME, BRIGHTNESS_MIN_FLOAT,
BRIGHTNESS_MAX_FLOAT, DOZE_SCALE_FACTOR, LIGHT_SENSOR_RATE,
@@ -300,6 +300,179 @@ public class AutomaticBrightnessControllerTest {
}
@Test
+ public void testShortTermModelTimesOut() throws Exception {
+ ArgumentCaptor<SensorEventListener> listenerCaptor =
+ ArgumentCaptor.forClass(SensorEventListener.class);
+ verify(mSensorManager).registerListener(listenerCaptor.capture(), eq(mLightSensor),
+ eq(INITIAL_LIGHT_SENSOR_RATE * 1000), any(Handler.class));
+ SensorEventListener listener = listenerCaptor.getValue();
+
+ // Sensor reads 123 lux,
+ listener.onSensorChanged(TestUtils.createSensorEvent(mLightSensor, 123));
+ // User sets brightness to 100
+ mController.configure(AUTO_BRIGHTNESS_ENABLED, /* configuration= */ null,
+ /* brightness= */ 0.5f, /* userChangedBrightness= */ true, /* adjustment= */ 0,
+ /* userChanged= */ false, DisplayPowerRequest.POLICY_BRIGHT,
+ /* shouldResetShortTermModel= */ true);
+
+ when(mBrightnessMappingStrategy.getShortTermModelTimeout()).thenReturn(2000L);
+
+ mController.switchToIdleMode();
+ when(mIdleBrightnessMappingStrategy.isForIdleMode()).thenReturn(true);
+ when(mBrightnessMappingStrategy.shouldResetShortTermModel(
+ 123f, 0.5f)).thenReturn(true);
+
+ // Sensor reads 1000 lux,
+ listener.onSensorChanged(TestUtils.createSensorEvent(mLightSensor, 1000));
+ mTestLooper.moveTimeForward(
+ mBrightnessMappingStrategy.getShortTermModelTimeout() + 1000);
+ mTestLooper.dispatchAll();
+
+ mController.switchToInteractiveScreenBrightnessMode();
+ mTestLooper.moveTimeForward(4000);
+ mTestLooper.dispatchAll();
+
+ // Verify only happens on the first configure. (i.e. not again when switching back)
+ // Intentionally using any() to ensure it's not called whatsoever.
+ verify(mBrightnessMappingStrategy, times(1))
+ .addUserDataPoint(123.0f, 0.5f);
+ verify(mBrightnessMappingStrategy, times(1))
+ .addUserDataPoint(anyFloat(), anyFloat());
+ }
+
+ @Test
+ public void testShortTermModelDoesntTimeOut() throws Exception {
+ ArgumentCaptor<SensorEventListener> listenerCaptor =
+ ArgumentCaptor.forClass(SensorEventListener.class);
+ verify(mSensorManager).registerListener(listenerCaptor.capture(), eq(mLightSensor),
+ eq(INITIAL_LIGHT_SENSOR_RATE * 1000), any(Handler.class));
+ SensorEventListener listener = listenerCaptor.getValue();
+
+ // Sensor reads 123 lux,
+ listener.onSensorChanged(TestUtils.createSensorEvent(mLightSensor, 123));
+ // User sets brightness to 100
+ mController.configure(AUTO_BRIGHTNESS_ENABLED, null /* configuration= */,
+ 0.51f /* brightness= */, true /* userChangedBrightness= */, 0 /* adjustment= */,
+ false /* userChanged= */, DisplayPowerRequest.POLICY_BRIGHT,
+ /* shouldResetShortTermModel= */ true);
+
+ when(mBrightnessMappingStrategy.shouldResetShortTermModel(
+ anyFloat(), anyFloat())).thenReturn(true);
+ when(mBrightnessMappingStrategy.getShortTermModelTimeout()).thenReturn(2000L);
+ when(mBrightnessMappingStrategy.getUserBrightness()).thenReturn(0.51f);
+ when(mBrightnessMappingStrategy.getUserLux()).thenReturn(123.0f);
+
+ mController.switchToIdleMode();
+ when(mIdleBrightnessMappingStrategy.isForIdleMode()).thenReturn(true);
+
+ // Time does not move forward, since clock is doesn't increment naturally.
+ mTestLooper.dispatchAll();
+
+ // Sensor reads 100000 lux,
+ listener.onSensorChanged(TestUtils.createSensorEvent(mLightSensor, 678910));
+ mController.switchToInteractiveScreenBrightnessMode();
+
+ // Verify short term model is not reset.
+ verify(mBrightnessMappingStrategy, never()).clearUserDataPoints();
+
+ // Verify that we add the data point once when the user sets it, and again when we return
+ // interactive mode.
+ verify(mBrightnessMappingStrategy, times(2))
+ .addUserDataPoint(123.0f, 0.51f);
+ }
+
+ @Test
+ public void testShortTermModelIsRestoredWhenSwitchingWithinTimeout() throws Exception {
+ ArgumentCaptor<SensorEventListener> listenerCaptor =
+ ArgumentCaptor.forClass(SensorEventListener.class);
+ verify(mSensorManager).registerListener(listenerCaptor.capture(), eq(mLightSensor),
+ eq(INITIAL_LIGHT_SENSOR_RATE * 1000), any(Handler.class));
+ SensorEventListener listener = listenerCaptor.getValue();
+
+ // Sensor reads 123 lux,
+ listener.onSensorChanged(TestUtils.createSensorEvent(mLightSensor, 123));
+ // User sets brightness to 100
+ mController.configure(AUTO_BRIGHTNESS_ENABLED, /* configuration= */ null,
+ /* brightness= */ 0.5f, /* userChangedBrightness= */ true, /* adjustment= */ 0,
+ /* userChanged= */ false, DisplayPowerRequest.POLICY_BRIGHT,
+ /* shouldResetShortTermModel= */ true);
+
+ when(mBrightnessMappingStrategy.getShortTermModelTimeout()).thenReturn(2000L);
+ when(mBrightnessMappingStrategy.getUserBrightness()).thenReturn(0.5f);
+ when(mBrightnessMappingStrategy.getUserLux()).thenReturn(123f);
+
+ mController.switchToIdleMode();
+ when(mIdleBrightnessMappingStrategy.isForIdleMode()).thenReturn(true);
+ when(mIdleBrightnessMappingStrategy.getUserBrightness()).thenReturn(-1f);
+ when(mIdleBrightnessMappingStrategy.getUserLux()).thenReturn(-1f);
+ when(mBrightnessMappingStrategy.shouldResetShortTermModel(
+ 123f, 0.5f)).thenReturn(true);
+
+ // Sensor reads 1000 lux,
+ listener.onSensorChanged(TestUtils.createSensorEvent(mLightSensor, 1000));
+ mTestLooper.moveTimeForward(
+ mBrightnessMappingStrategy.getShortTermModelTimeout() + 1000);
+ mTestLooper.dispatchAll();
+
+ mController.switchToInteractiveScreenBrightnessMode();
+ mTestLooper.moveTimeForward(4000);
+ mTestLooper.dispatchAll();
+
+ // Verify only happens on the first configure. (i.e. not again when switching back)
+ // Intentionally using any() to ensure it's not called whatsoever.
+ verify(mBrightnessMappingStrategy, times(1))
+ .addUserDataPoint(123.0f, 0.5f);
+ verify(mBrightnessMappingStrategy, times(1))
+ .addUserDataPoint(anyFloat(), anyFloat());
+ }
+
+ @Test
+ public void testShortTermModelNotRestoredAfterTimeout() throws Exception {
+ ArgumentCaptor<SensorEventListener> listenerCaptor =
+ ArgumentCaptor.forClass(SensorEventListener.class);
+ verify(mSensorManager).registerListener(listenerCaptor.capture(), eq(mLightSensor),
+ eq(INITIAL_LIGHT_SENSOR_RATE * 1000), any(Handler.class));
+ SensorEventListener listener = listenerCaptor.getValue();
+
+ // Sensor reads 123 lux,
+ listener.onSensorChanged(TestUtils.createSensorEvent(mLightSensor, 123));
+ // User sets brightness to 100
+ mController.configure(AUTO_BRIGHTNESS_ENABLED, /* configuration= */ null,
+ /* brightness= */ 0.5f, /* userChangedBrightness= */ true, /* adjustment= */ 0,
+ /* userChanged= */ false, DisplayPowerRequest.POLICY_BRIGHT,
+ /* shouldResetShortTermModel= */ true);
+
+ when(mBrightnessMappingStrategy.getShortTermModelTimeout()).thenReturn(2000L);
+
+ when(mBrightnessMappingStrategy.getUserBrightness()).thenReturn(0.5f);
+ when(mBrightnessMappingStrategy.getUserLux()).thenReturn(123f);
+
+ mController.switchToIdleMode();
+ when(mIdleBrightnessMappingStrategy.isForIdleMode()).thenReturn(true);
+ when(mIdleBrightnessMappingStrategy.getUserBrightness()).thenReturn(-1f);
+ when(mIdleBrightnessMappingStrategy.getUserLux()).thenReturn(-1f);
+
+ when(mBrightnessMappingStrategy.shouldResetShortTermModel(
+ 123f, 0.5f)).thenReturn(true);
+
+ // Sensor reads 1000 lux,
+ listener.onSensorChanged(TestUtils.createSensorEvent(mLightSensor, 1000));
+ // Do not fast-forward time.
+ mTestLooper.dispatchAll();
+
+ mController.switchToInteractiveScreenBrightnessMode();
+ // Do not fast-forward time
+ mTestLooper.dispatchAll();
+
+ // Verify this happens on the first configure and again when switching back
+ // Intentionally using any() to ensure it's not called any other times whatsoever.
+ verify(mBrightnessMappingStrategy, times(2))
+ .addUserDataPoint(123.0f, 0.5f);
+ verify(mBrightnessMappingStrategy, times(2))
+ .addUserDataPoint(anyFloat(), anyFloat());
+ }
+
+ @Test
public void testSwitchToIdleMappingStrategy() throws Exception {
ArgumentCaptor<SensorEventListener> listenerCaptor =
ArgumentCaptor.forClass(SensorEventListener.class);
@@ -326,6 +499,11 @@ public class AutomaticBrightnessControllerTest {
// Called once for init, and once when switching,
// setAmbientLux() is called twice and once in updateAutoBrightness()
verify(mBrightnessMappingStrategy, times(5)).isForIdleMode();
+ // Called when switching.
+ verify(mBrightnessMappingStrategy, times(1)).getShortTermModelTimeout();
+ verify(mBrightnessMappingStrategy, times(1)).getUserBrightness();
+ verify(mBrightnessMappingStrategy, times(1)).getUserLux();
+
// Ensure, after switching, original BMS is not used anymore
verifyNoMoreInteractions(mBrightnessMappingStrategy);
diff --git a/services/tests/servicestests/src/com/android/server/display/BrightnessThrottlerTest.java b/services/tests/servicestests/src/com/android/server/display/BrightnessThrottlerTest.java
index ffe2fec380a8..ce4b438470df 100644
--- a/services/tests/servicestests/src/com/android/server/display/BrightnessThrottlerTest.java
+++ b/services/tests/servicestests/src/com/android/server/display/BrightnessThrottlerTest.java
@@ -54,6 +54,7 @@ import org.mockito.Mock;
import org.mockito.MockitoAnnotations;
import java.util.ArrayList;
+import java.util.HashMap;
import java.util.List;
@SmallTest
@@ -122,8 +123,6 @@ public class BrightnessThrottlerTest {
BrightnessThrottlingData data;
data = BrightnessThrottlingData.create((List<ThrottlingLevel>)null);
assertEquals(data, null);
- data = BrightnessThrottlingData.create((BrightnessThrottlingData)null);
- assertEquals(data, null);
data = BrightnessThrottlingData.create(new ArrayList<ThrottlingLevel>());
assertEquals(data, null);
data = BrightnessThrottlingData.create(unsortedThermalLevels);
@@ -146,7 +145,7 @@ public class BrightnessThrottlerTest {
}
@Test
- public void testThrottlingUnsupported() throws Exception {
+ public void testThrottlingUnsupported() {
final BrightnessThrottler throttler = createThrottlerUnsupported();
assertFalse(throttler.deviceSupportsThrottling());
@@ -307,37 +306,18 @@ public class BrightnessThrottlerTest {
verify(mThermalServiceMock).registerThermalEventListenerWithType(
mThermalEventListenerCaptor.capture(), eq(Temperature.TYPE_SKIN));
final IThermalEventListener listener = mThermalEventListenerCaptor.getValue();
+ testThrottling(throttler, listener, PowerManager.BRIGHTNESS_MAX, 0.4f);
- // Set status too low to trigger throttling
- listener.notifyThrottling(getSkinTemp(level.thermalStatus - 1));
- mTestLooper.dispatchAll();
- assertEquals(PowerManager.BRIGHTNESS_MAX, throttler.getBrightnessCap(), 0f);
- assertFalse(throttler.isThrottled());
-
- // Set status high enough to trigger throttling
- listener.notifyThrottling(getSkinTemp(level.thermalStatus));
- mTestLooper.dispatchAll();
- assertEquals(0.4f, throttler.getBrightnessCap(), 0f);
- assertTrue(throttler.isThrottled());
-
- // Update thresholds
- // This data is equivalent to the string "123,1,critical,0.8", passed below
- final ThrottlingLevel newLevel = new ThrottlingLevel(PowerManager.THERMAL_STATUS_CRITICAL,
- 0.8f);
// Set new (valid) data from device config
mDeviceConfigFake.setBrightnessThrottlingData("123,1,critical,0.8");
+ testThrottling(throttler, listener, PowerManager.BRIGHTNESS_MAX, 0.8f);
- // Set status too low to trigger throttling
- listener.notifyThrottling(getSkinTemp(newLevel.thermalStatus - 1));
- mTestLooper.dispatchAll();
- assertEquals(PowerManager.BRIGHTNESS_MAX, throttler.getBrightnessCap(), 0f);
- assertFalse(throttler.isThrottled());
-
- // Set status high enough to trigger throttling
- listener.notifyThrottling(getSkinTemp(newLevel.thermalStatus));
- mTestLooper.dispatchAll();
- assertEquals(newLevel.brightness, throttler.getBrightnessCap(), 0f);
- assertTrue(throttler.isThrottled());
+ mDeviceConfigFake.setBrightnessThrottlingData(
+ "123,1,critical,0.75;123,1,critical,0.99,id_2");
+ testThrottling(throttler, listener, PowerManager.BRIGHTNESS_MAX, 0.75f);
+ mDeviceConfigFake.setBrightnessThrottlingData(
+ "123,1,critical,0.8,default;123,1,critical,0.99,id_2");
+ testThrottling(throttler, listener, PowerManager.BRIGHTNESS_MAX, 0.8f);
}
@Test public void testInvalidThrottlingStrings() throws Exception {
@@ -370,6 +350,18 @@ public class BrightnessThrottlerTest {
testThrottling(throttler, listener, PowerManager.BRIGHTNESS_MAX, 0.25f);
mDeviceConfigFake.setBrightnessThrottlingData(""); // Invalid format
testThrottling(throttler, listener, PowerManager.BRIGHTNESS_MAX, 0.25f);
+ // Invalid string format
+ mDeviceConfigFake.setBrightnessThrottlingData(
+ "123,default,1,critical,0.75,1,critical,0.99");
+ testThrottling(throttler, listener, PowerManager.BRIGHTNESS_MAX, 0.25f);
+ // Invalid level string and number string
+ mDeviceConfigFake.setBrightnessThrottlingData(
+ "123,1,1,critical,0.75,id_2,1,critical,0.99");
+ testThrottling(throttler, listener, PowerManager.BRIGHTNESS_MAX, 0.25f);
+ // Invalid format - (two default ids for same display)
+ mDeviceConfigFake.setBrightnessThrottlingData(
+ "123,1,critical,0.75,default;123,1,critical,0.99");
+ testThrottling(throttler, listener, PowerManager.BRIGHTNESS_MAX, 0.25f);
}
private void testThrottling(BrightnessThrottler throttler, IThermalEventListener listener,
@@ -472,13 +464,17 @@ public class BrightnessThrottlerTest {
}
private BrightnessThrottler createThrottlerUnsupported() {
- return new BrightnessThrottler(mInjectorMock, mHandler, mHandler, null, () -> {}, null);
+ return new BrightnessThrottler(mInjectorMock, mHandler, mHandler,
+ /* throttlingChangeCallback= */ () -> {}, /* uniqueDisplayId= */ null,
+ /* throttlingDataId= */ null, /* throttlingDataMap= */ new HashMap<>(1));
}
private BrightnessThrottler createThrottlerSupported(BrightnessThrottlingData data) {
assertNotNull(data);
+ HashMap<String, BrightnessThrottlingData> throttlingDataMap = new HashMap<>(1);
+ throttlingDataMap.put("default", data);
return new BrightnessThrottler(mInjectorMock, mHandler, BackgroundThread.getHandler(),
- data, () -> {}, "123");
+ () -> {}, "123", "default", throttlingDataMap);
}
private Temperature getSkinTemp(@ThrottlingStatus int status) {
diff --git a/services/tests/servicestests/src/com/android/server/display/DisplayDeviceConfigTest.java b/services/tests/servicestests/src/com/android/server/display/DisplayDeviceConfigTest.java
index 9fd647bb0b90..ed0755949869 100644
--- a/services/tests/servicestests/src/com/android/server/display/DisplayDeviceConfigTest.java
+++ b/services/tests/servicestests/src/com/android/server/display/DisplayDeviceConfigTest.java
@@ -50,6 +50,7 @@ import java.nio.charset.StandardCharsets;
import java.nio.file.Files;
import java.nio.file.Path;
import java.util.ArrayList;
+import java.util.HashMap;
import java.util.List;
@SmallTest
@@ -186,50 +187,72 @@ public final class DisplayDeviceConfigTest {
assertArrayEquals(new int[]{-1, 10, 20, 30, 40},
mDisplayDeviceConfig.getScreenOffBrightnessSensorValueToLux());
- List<DisplayDeviceConfig.BrightnessThrottlingData.ThrottlingLevel> throttlingLevels =
- new ArrayList();
- throttlingLevels.add(new DisplayDeviceConfig.BrightnessThrottlingData.ThrottlingLevel(
+ List<DisplayDeviceConfig.BrightnessThrottlingData.ThrottlingLevel>
+ defaultThrottlingLevels = new ArrayList<>();
+ defaultThrottlingLevels.add(
+ new DisplayDeviceConfig.BrightnessThrottlingData.ThrottlingLevel(
DisplayDeviceConfig.convertThermalStatus(ThermalStatus.light), 0.4f
));
- throttlingLevels.add(new DisplayDeviceConfig.BrightnessThrottlingData.ThrottlingLevel(
+ defaultThrottlingLevels.add(
+ new DisplayDeviceConfig.BrightnessThrottlingData.ThrottlingLevel(
DisplayDeviceConfig.convertThermalStatus(ThermalStatus.moderate), 0.3f
));
- throttlingLevels.add(new DisplayDeviceConfig.BrightnessThrottlingData.ThrottlingLevel(
+ defaultThrottlingLevels.add(
+ new DisplayDeviceConfig.BrightnessThrottlingData.ThrottlingLevel(
DisplayDeviceConfig.convertThermalStatus(ThermalStatus.severe), 0.2f
));
- throttlingLevels.add(new DisplayDeviceConfig.BrightnessThrottlingData.ThrottlingLevel(
+ defaultThrottlingLevels.add(
+ new DisplayDeviceConfig.BrightnessThrottlingData.ThrottlingLevel(
DisplayDeviceConfig.convertThermalStatus(ThermalStatus.critical), 0.1f
));
- throttlingLevels.add(new DisplayDeviceConfig.BrightnessThrottlingData.ThrottlingLevel(
+ defaultThrottlingLevels.add(
+ new DisplayDeviceConfig.BrightnessThrottlingData.ThrottlingLevel(
DisplayDeviceConfig.convertThermalStatus(ThermalStatus.emergency), 0.05f
));
- throttlingLevels.add(new DisplayDeviceConfig.BrightnessThrottlingData.ThrottlingLevel(
+ defaultThrottlingLevels.add(
+ new DisplayDeviceConfig.BrightnessThrottlingData.ThrottlingLevel(
DisplayDeviceConfig.convertThermalStatus(ThermalStatus.shutdown), 0.025f
));
- assertEquals(new DisplayDeviceConfig.BrightnessThrottlingData(throttlingLevels),
- mDisplayDeviceConfig.getBrightnessThrottlingData("default"));
- throttlingLevels.clear();
- throttlingLevels.add(new DisplayDeviceConfig.BrightnessThrottlingData.ThrottlingLevel(
+ DisplayDeviceConfig.BrightnessThrottlingData defaultThrottlingData =
+ new DisplayDeviceConfig.BrightnessThrottlingData(defaultThrottlingLevels);
+
+ List<DisplayDeviceConfig.BrightnessThrottlingData.ThrottlingLevel>
+ concurrentThrottlingLevels = new ArrayList<>();
+ concurrentThrottlingLevels.add(
+ new DisplayDeviceConfig.BrightnessThrottlingData.ThrottlingLevel(
DisplayDeviceConfig.convertThermalStatus(ThermalStatus.light), 0.2f
));
- throttlingLevels.add(new DisplayDeviceConfig.BrightnessThrottlingData.ThrottlingLevel(
+ concurrentThrottlingLevels.add(
+ new DisplayDeviceConfig.BrightnessThrottlingData.ThrottlingLevel(
DisplayDeviceConfig.convertThermalStatus(ThermalStatus.moderate), 0.15f
));
- throttlingLevels.add(new DisplayDeviceConfig.BrightnessThrottlingData.ThrottlingLevel(
+ concurrentThrottlingLevels.add(
+ new DisplayDeviceConfig.BrightnessThrottlingData.ThrottlingLevel(
DisplayDeviceConfig.convertThermalStatus(ThermalStatus.severe), 0.1f
));
- throttlingLevels.add(new DisplayDeviceConfig.BrightnessThrottlingData.ThrottlingLevel(
+ concurrentThrottlingLevels.add(
+ new DisplayDeviceConfig.BrightnessThrottlingData.ThrottlingLevel(
DisplayDeviceConfig.convertThermalStatus(ThermalStatus.critical), 0.05f
));
- throttlingLevels.add(new DisplayDeviceConfig.BrightnessThrottlingData.ThrottlingLevel(
+ concurrentThrottlingLevels.add(
+ new DisplayDeviceConfig.BrightnessThrottlingData.ThrottlingLevel(
DisplayDeviceConfig.convertThermalStatus(ThermalStatus.emergency), 0.025f
));
- throttlingLevels.add(new DisplayDeviceConfig.BrightnessThrottlingData.ThrottlingLevel(
+ concurrentThrottlingLevels.add(
+ new DisplayDeviceConfig.BrightnessThrottlingData.ThrottlingLevel(
DisplayDeviceConfig.convertThermalStatus(ThermalStatus.shutdown), 0.0125f
));
- assertEquals(new DisplayDeviceConfig.BrightnessThrottlingData(throttlingLevels),
- mDisplayDeviceConfig.getBrightnessThrottlingData("concurrent"));
+ DisplayDeviceConfig.BrightnessThrottlingData concurrentThrottlingData =
+ new DisplayDeviceConfig.BrightnessThrottlingData(concurrentThrottlingLevels);
+
+ HashMap<String, DisplayDeviceConfig.BrightnessThrottlingData> throttlingDataMap =
+ new HashMap<>(2);
+ throttlingDataMap.put("default", defaultThrottlingData);
+ throttlingDataMap.put("concurrent", concurrentThrottlingData);
+
+ assertEquals(throttlingDataMap,
+ mDisplayDeviceConfig.getBrightnessThrottlingDataMapByThrottlingId());
assertNotNull(mDisplayDeviceConfig.getHostUsiVersion());
assertEquals(mDisplayDeviceConfig.getHostUsiVersion().getMajorVersion(), 2);
@@ -246,8 +269,7 @@ public final class DisplayDeviceConfigTest {
mDisplayDeviceConfig.getHdrBrightnessFromSdr(0.62f, 1.25f),
SMALL_DELTA);
-
- // Todo: Add asserts for BrightnessThrottlingData, DensityMapping,
+ // Todo: Add asserts for DensityMapping,
// HighBrightnessModeData AmbientLightSensor, RefreshRateLimitations and ProximitySensor.
}
diff --git a/services/tests/uiservicestests/src/com/android/server/notification/NotificationManagerServiceTest.java b/services/tests/uiservicestests/src/com/android/server/notification/NotificationManagerServiceTest.java
index dc954a2433c5..1ba6ad7c9f34 100755
--- a/services/tests/uiservicestests/src/com/android/server/notification/NotificationManagerServiceTest.java
+++ b/services/tests/uiservicestests/src/com/android/server/notification/NotificationManagerServiceTest.java
@@ -4734,7 +4734,7 @@ public class NotificationManagerServiceTest extends UiServiceTestCase {
}
@Test
- public void testBumpFGImportance_noChannelChangePreOApp() throws Exception {
+ public void testBumpFGImportance_channelChangePreOApp() throws Exception {
String preOPkg = PKG_N_MR1;
final ApplicationInfo legacy = new ApplicationInfo();
legacy.targetSdkVersion = Build.VERSION_CODES.N_MR1;
@@ -4752,7 +4752,7 @@ public class NotificationManagerServiceTest extends UiServiceTestCase {
.setPriority(Notification.PRIORITY_MIN);
StatusBarNotification sbn = new StatusBarNotification(preOPkg, preOPkg, 9,
- "testBumpFGImportance_noChannelChangePreOApp",
+ "testBumpFGImportance_channelChangePreOApp",
Binder.getCallingUid(), 0, nb.build(),
UserHandle.getUserHandleForUid(Binder.getCallingUid()), null, 0);
@@ -4772,11 +4772,11 @@ public class NotificationManagerServiceTest extends UiServiceTestCase {
.setPriority(Notification.PRIORITY_MIN);
sbn = new StatusBarNotification(preOPkg, preOPkg, 9,
- "testBumpFGImportance_noChannelChangePreOApp", Binder.getCallingUid(),
+ "testBumpFGImportance_channelChangePreOApp", Binder.getCallingUid(),
0, nb.build(), UserHandle.getUserHandleForUid(Binder.getCallingUid()), null, 0);
mBinderService.enqueueNotificationWithTag(preOPkg, preOPkg,
- "testBumpFGImportance_noChannelChangePreOApp",
+ "testBumpFGImportance_channelChangePreOApp",
sbn.getId(), sbn.getNotification(), sbn.getUserId());
waitForIdle();
assertEquals(IMPORTANCE_LOW,
@@ -4784,7 +4784,7 @@ public class NotificationManagerServiceTest extends UiServiceTestCase {
NotificationChannel defaultChannel = mBinderService.getNotificationChannel(
preOPkg, mContext.getUserId(), preOPkg, NotificationChannel.DEFAULT_CHANNEL_ID);
- assertEquals(IMPORTANCE_UNSPECIFIED, defaultChannel.getImportance());
+ assertEquals(IMPORTANCE_LOW, defaultChannel.getImportance());
}
@Test
diff --git a/services/tests/uiservicestests/src/com/android/server/notification/ZenModeConfigTest.java b/services/tests/uiservicestests/src/com/android/server/notification/ZenModeConfigTest.java
index 893f53825bbb..3ba94000d4a5 100644
--- a/services/tests/uiservicestests/src/com/android/server/notification/ZenModeConfigTest.java
+++ b/services/tests/uiservicestests/src/com/android/server/notification/ZenModeConfigTest.java
@@ -120,12 +120,20 @@ public class ZenModeConfigTest extends UiServiceTestCase {
.showLights(false)
.showBadges(false)
.showInAmbientDisplay(false)
+ .allowCalls(ZenPolicy.PEOPLE_TYPE_CONTACTS)
+ .allowMessages(ZenPolicy.PEOPLE_TYPE_STARRED)
+ .allowConversations(ZenPolicy.CONVERSATION_SENDERS_NONE)
.build();
ZenModeConfig config = getMutedAllConfig();
config.allowAlarms = true;
config.allowReminders = true;
config.allowEvents = true;
+ config.allowCalls = true;
+ config.allowCallsFrom = Policy.PRIORITY_SENDERS_CONTACTS;
+ config.allowMessages = true;
+ config.allowMessagesFrom = Policy.PRIORITY_SENDERS_STARRED;
+ config.allowConversations = false;
config.suppressedVisualEffects |= Policy.SUPPRESSED_EFFECT_BADGE;
config.suppressedVisualEffects |= Policy.SUPPRESSED_EFFECT_LIGHTS;
config.suppressedVisualEffects |= Policy.SUPPRESSED_EFFECT_AMBIENT;
@@ -138,6 +146,10 @@ public class ZenModeConfigTest extends UiServiceTestCase {
assertEquals(expected.getPriorityCategoryEvents(), actual.getPriorityCategoryEvents());
assertEquals(expected.getVisualEffectLights(), actual.getVisualEffectLights());
assertEquals(expected.getVisualEffectAmbient(), actual.getVisualEffectAmbient());
+ assertEquals(expected.getPriorityConversationSenders(),
+ actual.getPriorityConversationSenders());
+ assertEquals(expected.getPriorityCallSenders(), actual.getPriorityCallSenders());
+ assertEquals(expected.getPriorityMessageSenders(), actual.getPriorityMessageSenders());
}
@Test
diff --git a/services/tests/wmtests/src/com/android/server/wm/LetterboxUiControllerTest.java b/services/tests/wmtests/src/com/android/server/wm/LetterboxUiControllerTest.java
index 12e4825e5f85..a15ee694d6a4 100644
--- a/services/tests/wmtests/src/com/android/server/wm/LetterboxUiControllerTest.java
+++ b/services/tests/wmtests/src/com/android/server/wm/LetterboxUiControllerTest.java
@@ -41,6 +41,7 @@ import static android.view.WindowManager.PROPERTY_CAMERA_COMPAT_ENABLE_REFRESH_V
import static android.view.WindowManager.PROPERTY_COMPAT_ALLOW_DISPLAY_ORIENTATION_OVERRIDE;
import static android.view.WindowManager.PROPERTY_COMPAT_ALLOW_ORIENTATION_OVERRIDE;
import static android.view.WindowManager.PROPERTY_COMPAT_ENABLE_FAKE_FOCUS;
+import static android.view.WindowManager.PROPERTY_COMPAT_IGNORE_ORIENTATION_REQUEST_WHEN_LOOP_DETECTED;
import static android.view.WindowManager.PROPERTY_COMPAT_IGNORE_REQUESTED_ORIENTATION;
import static com.android.dx.mockito.inline.extended.ExtendedMockito.doReturn;
@@ -146,7 +147,7 @@ public class LetterboxUiControllerTest extends WindowTestsBase {
mActivity = setUpActivityWithComponent();
mController = new LetterboxUiController(mWm, mActivity);
prepareActivityThatShouldIgnoreRequestedOrientationDuringRelaunch();
- mController.setRelauchingAfterRequestedOrientationChanged(false);
+ mController.setRelaunchingAfterRequestedOrientationChanged(false);
spyOn(mDisplayContent.mDisplayRotationCompatPolicy);
doReturn(true).when(mDisplayContent.mDisplayRotationCompatPolicy)
@@ -190,7 +191,28 @@ public class LetterboxUiControllerTest extends WindowTestsBase {
@Test
public void testShouldIgnoreOrientationRequestLoop_overrideDisabled_returnsFalse() {
+ doReturn(true).when(mLetterboxConfiguration)
+ .isPolicyForIgnoringRequestedOrientationEnabled();
+ doReturn(false).when(mActivity).isLetterboxedForFixedOrientationAndAspectRatio();
+ // Request 3 times to simulate orientation request loop
+ for (int i = 0; i <= MIN_COUNT_TO_IGNORE_REQUEST_IN_LOOP; i++) {
+ assertShouldIgnoreOrientationRequestLoop(/* shouldIgnore */ false,
+ /* expectedCount */ 0);
+ }
+ }
+
+ @Test
+ @EnableCompatChanges({OVERRIDE_ENABLE_COMPAT_IGNORE_ORIENTATION_REQUEST_WHEN_LOOP_DETECTED})
+ public void testShouldIgnoreOrientationRequestLoop_propertyIsFalseAndOverride_returnsFalse()
+ throws Exception {
+ doReturn(true).when(mLetterboxConfiguration)
+ .isPolicyForIgnoringRequestedOrientationEnabled();
+ mockThatProperty(PROPERTY_COMPAT_IGNORE_ORIENTATION_REQUEST_WHEN_LOOP_DETECTED,
+ /* value */ false);
doReturn(false).when(mActivity).isLetterboxedForFixedOrientationAndAspectRatio();
+
+ mController = new LetterboxUiController(mWm, mActivity);
+
// Request 3 times to simulate orientation request loop
for (int i = 0; i <= MIN_COUNT_TO_IGNORE_REQUEST_IN_LOOP; i++) {
assertShouldIgnoreOrientationRequestLoop(/* shouldIgnore */ false,
@@ -201,7 +223,10 @@ public class LetterboxUiControllerTest extends WindowTestsBase {
@Test
@EnableCompatChanges({OVERRIDE_ENABLE_COMPAT_IGNORE_ORIENTATION_REQUEST_WHEN_LOOP_DETECTED})
public void testShouldIgnoreOrientationRequestLoop_isLetterboxed_returnsFalse() {
+ doReturn(true).when(mLetterboxConfiguration)
+ .isPolicyForIgnoringRequestedOrientationEnabled();
doReturn(true).when(mActivity).isLetterboxedForFixedOrientationAndAspectRatio();
+
// Request 3 times to simulate orientation request loop
for (int i = 0; i <= MIN_COUNT_TO_IGNORE_REQUEST_IN_LOOP; i++) {
assertShouldIgnoreOrientationRequestLoop(/* shouldIgnore */ false,
@@ -212,7 +237,10 @@ public class LetterboxUiControllerTest extends WindowTestsBase {
@Test
@EnableCompatChanges({OVERRIDE_ENABLE_COMPAT_IGNORE_ORIENTATION_REQUEST_WHEN_LOOP_DETECTED})
public void testShouldIgnoreOrientationRequestLoop_noLoop_returnsFalse() {
+ doReturn(true).when(mLetterboxConfiguration)
+ .isPolicyForIgnoringRequestedOrientationEnabled();
doReturn(false).when(mActivity).isLetterboxedForFixedOrientationAndAspectRatio();
+
// No orientation request loop
assertShouldIgnoreOrientationRequestLoop(/* shouldIgnore */ false,
/* expectedCount */ 0);
@@ -222,7 +250,10 @@ public class LetterboxUiControllerTest extends WindowTestsBase {
@EnableCompatChanges({OVERRIDE_ENABLE_COMPAT_IGNORE_ORIENTATION_REQUEST_WHEN_LOOP_DETECTED})
public void testShouldIgnoreOrientationRequestLoop_timeout_returnsFalse()
throws InterruptedException {
+ doReturn(true).when(mLetterboxConfiguration)
+ .isPolicyForIgnoringRequestedOrientationEnabled();
doReturn(false).when(mActivity).isLetterboxedForFixedOrientationAndAspectRatio();
+
for (int i = MIN_COUNT_TO_IGNORE_REQUEST_IN_LOOP; i > 0; i--) {
assertShouldIgnoreOrientationRequestLoop(/* shouldIgnore */ false,
/* expectedCount */ 0);
@@ -233,7 +264,10 @@ public class LetterboxUiControllerTest extends WindowTestsBase {
@Test
@EnableCompatChanges({OVERRIDE_ENABLE_COMPAT_IGNORE_ORIENTATION_REQUEST_WHEN_LOOP_DETECTED})
public void testShouldIgnoreOrientationRequestLoop_returnsTrue() {
+ doReturn(true).when(mLetterboxConfiguration)
+ .isPolicyForIgnoringRequestedOrientationEnabled();
doReturn(false).when(mActivity).isLetterboxedForFixedOrientationAndAspectRatio();
+
for (int i = 0; i < MIN_COUNT_TO_IGNORE_REQUEST_IN_LOOP; i++) {
assertShouldIgnoreOrientationRequestLoop(/* shouldIgnore */ false,
/* expectedCount */ i);
@@ -870,7 +904,7 @@ public class LetterboxUiControllerTest extends WindowTestsBase {
private void prepareActivityThatShouldIgnoreRequestedOrientationDuringRelaunch() {
doReturn(true).when(mLetterboxConfiguration)
.isPolicyForIgnoringRequestedOrientationEnabled();
- mController.setRelauchingAfterRequestedOrientationChanged(true);
+ mController.setRelaunchingAfterRequestedOrientationChanged(true);
}
private ActivityRecord setUpActivityWithComponent() {
diff --git a/services/tests/wmtests/src/com/android/server/wm/SizeCompatTests.java b/services/tests/wmtests/src/com/android/server/wm/SizeCompatTests.java
index a646d01378aa..e96d1abf9ced 100644
--- a/services/tests/wmtests/src/com/android/server/wm/SizeCompatTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/SizeCompatTests.java
@@ -813,6 +813,8 @@ public class SizeCompatTests extends WindowTestsBase {
spyOn(mActivity.mLetterboxUiController);
doReturn(true).when(mActivity.mLetterboxUiController)
+ .isSurfaceReadyToShow(any());
+ doReturn(true).when(mActivity.mLetterboxUiController)
.isSurfaceVisible(any());
assertTrue(mActivity.mLetterboxUiController.shouldShowLetterboxUi(