summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--apex/jobscheduler/service/java/com/android/server/job/controllers/QuotaController.java152
-rw-r--r--core/api/current.txt4
-rw-r--r--core/api/system-current.txt24
-rw-r--r--core/api/test-current.txt5
-rw-r--r--core/java/android/app/ForegroundServiceTypePolicy.java47
-rw-r--r--core/java/android/app/WallpaperManager.java16
-rw-r--r--core/java/android/app/wallpaper.aconfig10
-rw-r--r--core/java/android/content/pm/UserInfo.java8
-rw-r--r--core/java/android/content/pm/multiuser.aconfig7
-rw-r--r--core/java/android/hardware/biometrics/BiometricConstants.java20
-rw-r--r--core/java/android/os/Binder.java16
-rw-r--r--core/java/android/view/SurfaceView.java2
-rw-r--r--core/java/com/android/internal/os/BatteryStatsHistory.java15
-rw-r--r--core/jni/android_util_Binder.cpp34
-rw-r--r--core/tests/coretests/src/android/content/pm/UserInfoTest.java90
-rw-r--r--libs/WindowManager/Shell/aconfig/multitasking.aconfig7
-rw-r--r--libs/WindowManager/Shell/shared/src/com/android/wm/shell/shared/GroupedTaskInfo.java41
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/recents/RecentTasksController.java15
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/CaptionWindowDecoration.java17
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/DesktopModeWindowDecoration.java44
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/MultiDisplayVeiledResizeTaskPositioner.kt13
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/WindowDecoration.java56
-rw-r--r--libs/WindowManager/Shell/tests/unittest/res/values/dimen.xml2
-rw-r--r--libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/recents/GroupedTaskInfoTest.kt5
-rw-r--r--libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/windowdecor/DesktopModeWindowDecorationTests.java123
-rw-r--r--libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/windowdecor/MultiDisplayVeiledResizeTaskPositionerTest.kt6
-rw-r--r--libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/windowdecor/WindowDecorationTests.java50
-rw-r--r--libs/hwui/Android.bp1
-rw-r--r--libs/hwui/WebViewFunctorManager.cpp47
-rw-r--r--libs/hwui/WebViewFunctorManager.h13
-rw-r--r--libs/hwui/jni/android_graphics_HardwareRenderer.cpp14
-rw-r--r--libs/hwui/platform/host/WebViewFunctorManager.cpp2
-rw-r--r--libs/hwui/platform/host/renderthread/RenderThread.cpp2
-rw-r--r--libs/hwui/renderthread/CanvasContext.cpp64
-rw-r--r--libs/hwui/renderthread/CanvasContext.h17
-rw-r--r--libs/hwui/renderthread/RenderProxy.cpp20
-rw-r--r--libs/hwui/renderthread/RenderProxy.h4
-rw-r--r--libs/hwui/renderthread/RenderThread.cpp60
-rw-r--r--libs/hwui/renderthread/RenderThread.h48
-rw-r--r--media/java/android/media/AudioDeviceVolumeManager.java238
-rw-r--r--media/java/android/media/AudioManager.java90
-rw-r--r--media/java/android/media/MediaRecorder.java2
-rw-r--r--packages/SettingsLib/ButtonPreference/src/com/android/settingslib/widget/ButtonPreference.java48
-rw-r--r--packages/SystemUI/multivalentTests/src/com/android/systemui/qs/panels/ui/viewmodel/DetailsViewModelTest.kt41
-rw-r--r--packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/row/NotificationMenuRowTest.java3
-rw-r--r--packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/stack/MagneticNotificationRowManagerImplTest.kt47
-rw-r--r--packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/stack/NotificationSwipeHelperTest.java16
-rw-r--r--packages/SystemUI/src/com/android/systemui/SwipeHelper.java21
-rw-r--r--packages/SystemUI/src/com/android/systemui/accessibility/hearingaid/HearingDevicesDialogDelegate.java8
-rw-r--r--packages/SystemUI/src/com/android/systemui/qs/panels/ui/viewmodel/DetailsViewModel.kt10
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/notification/OWNERS1
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/BundleEntry.java5
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/ShadeListBuilder.java2
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/GroupCountCoordinator.kt15
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/PreparationCoordinator.java12
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ExpandableView.java25
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationMenuRow.java5
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/MagneticNotificationRowManager.kt20
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/MagneticNotificationRowManagerImpl.kt61
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/MagneticRowListener.kt13
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayoutController.java13
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationSwipeHelper.java6
-rw-r--r--packages/SystemUI/tests/utils/src/com/android/systemui/qs/panels/ui/viewmodel/DetailsViewModelKosmos.kt8
-rw-r--r--services/accessibility/java/com/android/server/accessibility/HearingDevicePhoneCallNotificationController.java32
-rw-r--r--services/core/java/com/android/server/adb/AdbDebuggingManager.java4
-rw-r--r--services/core/java/com/android/server/audio/AudioService.java28
-rw-r--r--services/core/java/com/android/server/hdmi/AudioDeviceVolumeManagerWrapper.java17
-rw-r--r--services/core/java/com/android/server/hdmi/AudioManagerWrapper.java12
-rw-r--r--services/core/java/com/android/server/hdmi/DefaultAudioDeviceVolumeManagerWrapper.java25
-rw-r--r--services/core/java/com/android/server/hdmi/DefaultAudioManagerWrapper.java12
-rw-r--r--services/core/java/com/android/server/hdmi/HdmiControlService.java26
-rw-r--r--services/core/java/com/android/server/pm/UserManagerService.java4
-rw-r--r--services/core/java/com/android/server/wallpaper/WallpaperManagerInternal.java3
-rw-r--r--services/core/java/com/android/server/wallpaper/WallpaperManagerService.java69
-rw-r--r--services/core/java/com/android/server/wm/AbsAppSnapshotController.java18
-rw-r--r--services/core/java/com/android/server/wm/ActivityStartInterceptor.java6
-rw-r--r--services/core/java/com/android/server/wm/ActivityTaskManagerInternal.java5
-rw-r--r--services/core/java/com/android/server/wm/ActivityTaskManagerService.java19
-rw-r--r--services/core/java/com/android/server/wm/SnapshotPersistQueue.java81
-rw-r--r--services/core/java/com/android/server/wm/Transition.java1
-rw-r--r--services/tests/mockingservicestests/src/com/android/server/job/JobSchedulerServiceTest.java29
-rw-r--r--services/tests/mockingservicestests/src/com/android/server/job/controllers/QuotaControllerTest.java18
-rw-r--r--services/tests/powerstatstests/src/com/android/server/power/stats/BatteryStatsHistoryTest.java28
-rw-r--r--services/tests/servicestests/src/com/android/server/accessibility/HearingDevicePhoneCallNotificationControllerTest.java18
-rw-r--r--services/tests/servicestests/src/com/android/server/hdmi/BaseAbsoluteVolumeBehaviorTest.java70
-rw-r--r--services/tests/servicestests/src/com/android/server/hdmi/BasePlaybackDeviceAvbTest.java6
-rw-r--r--services/tests/servicestests/src/com/android/server/hdmi/BaseTvToAudioSystemAvbTest.java35
-rw-r--r--services/tests/servicestests/src/com/android/server/hdmi/FakeAudioFramework.java32
-rw-r--r--services/tests/servicestests/src/com/android/server/hdmi/PlaybackDeviceToAudioSystemAvbTest.java12
-rw-r--r--services/tests/servicestests/src/com/android/server/hdmi/PlaybackDeviceToTvAvbTest.java12
-rw-r--r--services/tests/servicestests/src/com/android/server/pm/UserManagerServiceUserInfoTest.java2
91 files changed, 1764 insertions, 691 deletions
diff --git a/apex/jobscheduler/service/java/com/android/server/job/controllers/QuotaController.java b/apex/jobscheduler/service/java/com/android/server/job/controllers/QuotaController.java
index a9c4a1501dd8..6dd7521e4d43 100644
--- a/apex/jobscheduler/service/java/com/android/server/job/controllers/QuotaController.java
+++ b/apex/jobscheduler/service/java/com/android/server/job/controllers/QuotaController.java
@@ -36,7 +36,6 @@ import android.annotation.UserIdInt;
import android.app.ActivityManager;
import android.app.AlarmManager;
import android.app.UidObserver;
-import android.app.compat.CompatChanges;
import android.app.job.JobInfo;
import android.app.usage.UsageEvents;
import android.app.usage.UsageStatsManagerInternal;
@@ -54,6 +53,7 @@ import android.os.Handler;
import android.os.Looper;
import android.os.Message;
import android.os.RemoteException;
+import android.os.ServiceManager;
import android.os.Trace;
import android.os.UserHandle;
import android.provider.DeviceConfig;
@@ -74,6 +74,7 @@ import com.android.internal.util.ArrayUtils;
import com.android.server.AppSchedulingModuleThread;
import com.android.server.LocalServices;
import com.android.server.PowerAllowlistInternal;
+import com.android.server.compat.PlatformCompat;
import com.android.server.job.ConstantsProto;
import com.android.server.job.Flags;
import com.android.server.job.JobSchedulerService;
@@ -157,6 +158,15 @@ public final class QuotaController extends StateController {
@Overridable // The change can be overridden in user build.
static final long OVERRIDE_QUOTA_ENFORCEMENT_TO_TOP_STARTED_JOBS = 374323858L;
+ /**
+ * When enabled this change id overrides the default quota parameters adjustment.
+ */
+ @VisibleForTesting
+ @ChangeId
+ @Disabled // Disabled by default
+ @Overridable // The change can be overridden in user build.
+ static final long OVERRIDE_QUOTA_ADJUST_DEFAULT_CONSTANTS = 378129159L;
+
@VisibleForTesting
static class ExecutionStats {
/**
@@ -536,6 +546,8 @@ public final class QuotaController extends StateController {
*/
private final SparseSetArray<String> mSystemInstallers = new SparseSetArray<>();
+ private final PlatformCompat mPlatformCompat;
+
/** An app has reached its quota. The message should contain a {@link UserPackage} object. */
@VisibleForTesting
static final int MSG_REACHED_TIME_QUOTA = 0;
@@ -587,6 +599,13 @@ public final class QuotaController extends StateController {
PowerAllowlistInternal pai = LocalServices.getService(PowerAllowlistInternal.class);
pai.registerTempAllowlistChangeListener(new TempAllowlistTracker());
+ mPlatformCompat = (PlatformCompat)
+ ServiceManager.getService(Context.PLATFORM_COMPAT_SERVICE);
+ if (Flags.adjustQuotaDefaultConstants()) {
+ mPlatformCompat.registerListener(OVERRIDE_QUOTA_ADJUST_DEFAULT_CONSTANTS,
+ (packageName) -> handleQuotaDefaultConstantsCompatChange());
+ }
+
try {
ActivityManager.getService().registerUidObserver(new QcUidObserver(),
ActivityManager.UID_OBSERVER_PROCSTATE,
@@ -651,8 +670,9 @@ public final class QuotaController extends StateController {
final int uid = jobStatus.getSourceUid();
if ((!Flags.enforceQuotaPolicyToTopStartedJobs()
- || CompatChanges.isChangeEnabled(OVERRIDE_QUOTA_ENFORCEMENT_TO_TOP_STARTED_JOBS,
- uid)) && mTopAppCache.get(uid)) {
+ || mPlatformCompat.isChangeEnabledByUid(
+ OVERRIDE_QUOTA_ENFORCEMENT_TO_TOP_STARTED_JOBS, uid))
+ && mTopAppCache.get(uid)) {
if (DEBUG) {
Slog.d(TAG, jobStatus.toShortString() + " is top started job");
}
@@ -690,8 +710,8 @@ public final class QuotaController extends StateController {
}
}
if (!Flags.enforceQuotaPolicyToTopStartedJobs()
- || CompatChanges.isChangeEnabled(OVERRIDE_QUOTA_ENFORCEMENT_TO_TOP_STARTED_JOBS,
- jobStatus.getSourceUid())) {
+ || mPlatformCompat.isChangeEnabledByUid(
+ OVERRIDE_QUOTA_ENFORCEMENT_TO_TOP_STARTED_JOBS, jobStatus.getSourceUid())) {
mTopStartedJobs.remove(jobStatus);
}
}
@@ -805,8 +825,8 @@ public final class QuotaController extends StateController {
/** @return true if the job was started while the app was in the TOP state. */
private boolean isTopStartedJobLocked(@NonNull final JobStatus jobStatus) {
if (!Flags.enforceQuotaPolicyToTopStartedJobs()
- || CompatChanges.isChangeEnabled(OVERRIDE_QUOTA_ENFORCEMENT_TO_TOP_STARTED_JOBS,
- jobStatus.getSourceUid())) {
+ || mPlatformCompat.isChangeEnabledByUid(
+ OVERRIDE_QUOTA_ENFORCEMENT_TO_TOP_STARTED_JOBS, jobStatus.getSourceUid())) {
return mTopStartedJobs.contains(jobStatus);
}
@@ -1102,6 +1122,7 @@ public final class QuotaController extends StateController {
final int standbyBucket) {
final long baseLimitMs = mAllowedTimePerPeriodMs[standbyBucket];
if (Flags.adjustQuotaDefaultConstants()
+ && !isCompatOverridedForQuotaConstantAdjustment()
&& Flags.additionalQuotaForSystemInstaller()
&& standbyBucket == EXEMPTED_INDEX
&& mSystemInstallers.contains(userId, pkgName)) {
@@ -1473,10 +1494,21 @@ public final class QuotaController extends StateController {
}
}
+ void handleQuotaDefaultConstantsCompatChange() {
+ synchronized (mLock) {
+ final boolean isCompatEnabled = isCompatOverridedForQuotaConstantAdjustment();
+ mQcConstants.adjustDefaultBucketWindowSizes(isCompatEnabled);
+ mQcConstants.adjustDefaultEjLimits(isCompatEnabled);
+ mQcConstants.mShouldReevaluateConstraints = true;
+ onConstantsUpdatedLocked();
+ }
+ }
+
void processQuotaConstantsAdjustment() {
- if (Flags.adjustQuotaDefaultConstants()) {
- mQcConstants.adjustDefaultBucketWindowSizes();
- mQcConstants.adjustDefaultEjLimits();
+ if (Flags.adjustQuotaDefaultConstants()
+ && !isCompatOverridedForQuotaConstantAdjustment()) {
+ mQcConstants.adjustDefaultBucketWindowSizes(false);
+ mQcConstants.adjustDefaultEjLimits(false);
}
}
@@ -1505,6 +1537,11 @@ public final class QuotaController extends StateController {
}
}
+ private boolean isCompatOverridedForQuotaConstantAdjustment() {
+ return mPlatformCompat.isChangeEnabledByPackageName(
+ OVERRIDE_QUOTA_ADJUST_DEFAULT_CONSTANTS, "android", UserHandle.USER_SYSTEM);
+ }
+
private void incrementTimingSessionCountLocked(final int userId,
@NonNull final String packageName) {
final long now = sElapsedRealtimeClock.millis();
@@ -2689,7 +2726,8 @@ public final class QuotaController extends StateController {
@VisibleForTesting
int getProcessStateQuotaFreeThreshold(int uid) {
if (Flags.enforceQuotaPolicyToFgsJobs()
- && !CompatChanges.isChangeEnabled(OVERRIDE_QUOTA_ENFORCEMENT_TO_FGS_JOBS, uid)) {
+ && !mPlatformCompat.isChangeEnabledByUid(
+ OVERRIDE_QUOTA_ENFORCEMENT_TO_FGS_JOBS, uid)) {
return ActivityManager.PROCESS_STATE_BOUND_TOP;
}
@@ -3596,25 +3634,40 @@ public final class QuotaController extends StateController {
*/
public long EJ_GRACE_PERIOD_TOP_APP_MS = DEFAULT_EJ_GRACE_PERIOD_TOP_APP_MS;
- void adjustDefaultBucketWindowSizes() {
- ALLOWED_TIME_PER_PERIOD_EXEMPTED_MS = Flags.tuneQuotaWindowDefaultParameters()
- ? DEFAULT_CURRENT_ALLOWED_TIME_PER_PERIOD_EXEMPTED_MS :
- DEFAULT_LEGACY_ALLOWED_TIME_PER_PERIOD_EXEMPTED_MS;
- ALLOWED_TIME_PER_PERIOD_ACTIVE_MS = Flags.tuneQuotaWindowDefaultParameters()
- ? DEFAULT_CURRENT_ALLOWED_TIME_PER_PERIOD_ACTIVE_MS :
- DEFAULT_LEGACY_ALLOWED_TIME_PER_PERIOD_ACTIVE_MS;
- ALLOWED_TIME_PER_PERIOD_ADDITION_INSTALLER_MS = Flags.tuneQuotaWindowDefaultParameters()
- ? DEFAULT_CURRENT_ALLOWED_TIME_PER_PERIOD_ADDITION_INSTALLER_MS :
- DEFAULT_ALLOWED_TIME_PER_PERIOD_ADDITION_INSTALLER_MS;
-
- WINDOW_SIZE_EXEMPTED_MS = Flags.tuneQuotaWindowDefaultParameters()
- ? DEFAULT_LATEST_WINDOW_SIZE_EXEMPTED_MS :
- DEFAULT_CURRENT_WINDOW_SIZE_EXEMPTED_MS;
- WINDOW_SIZE_ACTIVE_MS = Flags.tuneQuotaWindowDefaultParameters()
- ? DEFAULT_LATEST_WINDOW_SIZE_ACTIVE_MS :
- DEFAULT_CURRENT_WINDOW_SIZE_ACTIVE_MS;
- WINDOW_SIZE_WORKING_MS = DEFAULT_CURRENT_WINDOW_SIZE_WORKING_MS;
- WINDOW_SIZE_FREQUENT_MS = DEFAULT_CURRENT_WINDOW_SIZE_FREQUENT_MS;
+ void adjustDefaultBucketWindowSizes(boolean useLegacyQuotaConstants) {
+ if (useLegacyQuotaConstants) {
+ ALLOWED_TIME_PER_PERIOD_EXEMPTED_MS =
+ DEFAULT_LEGACY_ALLOWED_TIME_PER_PERIOD_EXEMPTED_MS;
+ ALLOWED_TIME_PER_PERIOD_ACTIVE_MS =
+ DEFAULT_LEGACY_ALLOWED_TIME_PER_PERIOD_ACTIVE_MS;
+ ALLOWED_TIME_PER_PERIOD_ADDITION_INSTALLER_MS =
+ DEFAULT_ALLOWED_TIME_PER_PERIOD_ADDITION_INSTALLER_MS;
+
+ WINDOW_SIZE_EXEMPTED_MS = DEFAULT_LEGACY_WINDOW_SIZE_EXEMPTED_MS;
+ WINDOW_SIZE_ACTIVE_MS = DEFAULT_LEGACY_WINDOW_SIZE_ACTIVE_MS;
+ WINDOW_SIZE_WORKING_MS = DEFAULT_LEGACY_WINDOW_SIZE_WORKING_MS;
+ WINDOW_SIZE_FREQUENT_MS = DEFAULT_LEGACY_WINDOW_SIZE_FREQUENT_MS;
+ } else {
+ ALLOWED_TIME_PER_PERIOD_EXEMPTED_MS = Flags.tuneQuotaWindowDefaultParameters()
+ ? DEFAULT_CURRENT_ALLOWED_TIME_PER_PERIOD_EXEMPTED_MS :
+ DEFAULT_LEGACY_ALLOWED_TIME_PER_PERIOD_EXEMPTED_MS;
+ ALLOWED_TIME_PER_PERIOD_ACTIVE_MS = Flags.tuneQuotaWindowDefaultParameters()
+ ? DEFAULT_CURRENT_ALLOWED_TIME_PER_PERIOD_ACTIVE_MS :
+ DEFAULT_LEGACY_ALLOWED_TIME_PER_PERIOD_ACTIVE_MS;
+ ALLOWED_TIME_PER_PERIOD_ADDITION_INSTALLER_MS =
+ Flags.tuneQuotaWindowDefaultParameters()
+ ? DEFAULT_CURRENT_ALLOWED_TIME_PER_PERIOD_ADDITION_INSTALLER_MS :
+ DEFAULT_ALLOWED_TIME_PER_PERIOD_ADDITION_INSTALLER_MS;
+
+ WINDOW_SIZE_EXEMPTED_MS = Flags.tuneQuotaWindowDefaultParameters()
+ ? DEFAULT_LATEST_WINDOW_SIZE_EXEMPTED_MS :
+ DEFAULT_CURRENT_WINDOW_SIZE_EXEMPTED_MS;
+ WINDOW_SIZE_ACTIVE_MS = Flags.tuneQuotaWindowDefaultParameters()
+ ? DEFAULT_LATEST_WINDOW_SIZE_ACTIVE_MS :
+ DEFAULT_CURRENT_WINDOW_SIZE_ACTIVE_MS;
+ WINDOW_SIZE_WORKING_MS = DEFAULT_CURRENT_WINDOW_SIZE_WORKING_MS;
+ WINDOW_SIZE_FREQUENT_MS = DEFAULT_CURRENT_WINDOW_SIZE_FREQUENT_MS;
+ }
mAllowedTimePerPeriodMs[EXEMPTED_INDEX] = Math.min(MAX_PERIOD_MS,
Math.max(MINUTE_IN_MILLIS, ALLOWED_TIME_PER_PERIOD_EXEMPTED_MS));
@@ -3640,10 +3693,15 @@ public final class QuotaController extends StateController {
ALLOWED_TIME_PER_PERIOD_ADDITION_INSTALLER_MS);
}
- void adjustDefaultEjLimits() {
- EJ_LIMIT_WORKING_MS = DEFAULT_CURRENT_EJ_LIMIT_WORKING_MS;
- EJ_TOP_APP_TIME_CHUNK_SIZE_MS = DEFAULT_CURRENT_EJ_TOP_APP_TIME_CHUNK_SIZE_MS;
- EJ_REWARD_INTERACTION_MS = DEFAULT_CURRENT_EJ_REWARD_INTERACTION_MS;
+ void adjustDefaultEjLimits(boolean useLegacyQuotaConstants) {
+ EJ_LIMIT_WORKING_MS = useLegacyQuotaConstants ? DEFAULT_LEGACY_EJ_LIMIT_WORKING_MS
+ : DEFAULT_CURRENT_EJ_LIMIT_WORKING_MS;
+ EJ_TOP_APP_TIME_CHUNK_SIZE_MS = useLegacyQuotaConstants
+ ? DEFAULT_LEGACY_EJ_TOP_APP_TIME_CHUNK_SIZE_MS :
+ DEFAULT_CURRENT_EJ_TOP_APP_TIME_CHUNK_SIZE_MS;
+ EJ_REWARD_INTERACTION_MS = useLegacyQuotaConstants
+ ? DEFAULT_LEGACY_EJ_REWARD_INTERACTION_MS
+ : DEFAULT_CURRENT_EJ_REWARD_INTERACTION_MS;
// The limit must be in the range [15 minutes, active limit].
mEJLimitsMs[WORKING_INDEX] = Math.max(15 * MINUTE_IN_MILLIS,
@@ -3668,6 +3726,8 @@ public final class QuotaController extends StateController {
public void processConstantLocked(@NonNull DeviceConfig.Properties properties,
@NonNull String key) {
+ final boolean isCompatEnabled = isCompatOverridedForQuotaConstantAdjustment();
+
switch (key) {
case KEY_ALLOWED_TIME_PER_PERIOD_EXEMPTED_MS:
case KEY_ALLOWED_TIME_PER_PERIOD_ACTIVE_MS:
@@ -3835,7 +3895,8 @@ public final class QuotaController extends StateController {
case KEY_EJ_TOP_APP_TIME_CHUNK_SIZE_MS:
// We don't need to re-evaluate execution stats or constraint status for this.
EJ_TOP_APP_TIME_CHUNK_SIZE_MS =
- properties.getLong(key, Flags.adjustQuotaDefaultConstants()
+ properties.getLong(key,
+ Flags.adjustQuotaDefaultConstants() && !isCompatEnabled
? DEFAULT_CURRENT_EJ_TOP_APP_TIME_CHUNK_SIZE_MS :
DEFAULT_LEGACY_EJ_TOP_APP_TIME_CHUNK_SIZE_MS);
// Limit chunking to be in the range [1 millisecond, 15 minutes] per event.
@@ -3873,7 +3934,8 @@ public final class QuotaController extends StateController {
case KEY_EJ_REWARD_INTERACTION_MS:
// We don't need to re-evaluate execution stats or constraint status for this.
EJ_REWARD_INTERACTION_MS =
- properties.getLong(key, Flags.adjustQuotaDefaultConstants()
+ properties.getLong(key,
+ Flags.adjustQuotaDefaultConstants() && !isCompatEnabled
? DEFAULT_CURRENT_EJ_REWARD_INTERACTION_MS :
DEFAULT_LEGACY_EJ_REWARD_INTERACTION_MS);
// Limit interaction reward to be in the range [5 seconds, 15 minutes] per
@@ -3914,6 +3976,8 @@ public final class QuotaController extends StateController {
}
mExecutionPeriodConstantsUpdated = true;
+ final boolean isCompatEnabled = isCompatOverridedForQuotaConstantAdjustment();
+
// Query the values as an atomic set.
final DeviceConfig.Properties properties = DeviceConfig.getProperties(
DeviceConfig.NAMESPACE_JOB_SCHEDULER,
@@ -3958,27 +4022,27 @@ public final class QuotaController extends StateController {
MAX_EXECUTION_TIME_MS = properties.getLong(KEY_MAX_EXECUTION_TIME_MS,
DEFAULT_MAX_EXECUTION_TIME_MS);
WINDOW_SIZE_EXEMPTED_MS = properties.getLong(KEY_WINDOW_SIZE_EXEMPTED_MS,
- (Flags.adjustQuotaDefaultConstants()
+ (Flags.adjustQuotaDefaultConstants() && !isCompatEnabled
&& Flags.tuneQuotaWindowDefaultParameters())
? DEFAULT_LATEST_WINDOW_SIZE_EXEMPTED_MS :
- (Flags.adjustQuotaDefaultConstants()
+ (Flags.adjustQuotaDefaultConstants() && !isCompatEnabled
? DEFAULT_CURRENT_WINDOW_SIZE_EXEMPTED_MS :
DEFAULT_LEGACY_WINDOW_SIZE_EXEMPTED_MS));
WINDOW_SIZE_ACTIVE_MS = properties.getLong(KEY_WINDOW_SIZE_ACTIVE_MS,
- (Flags.adjustQuotaDefaultConstants()
+ (Flags.adjustQuotaDefaultConstants() && !isCompatEnabled
&& Flags.tuneQuotaWindowDefaultParameters())
? DEFAULT_LATEST_WINDOW_SIZE_ACTIVE_MS :
- (Flags.adjustQuotaDefaultConstants()
+ (Flags.adjustQuotaDefaultConstants() && !isCompatEnabled
? DEFAULT_CURRENT_WINDOW_SIZE_ACTIVE_MS :
DEFAULT_LEGACY_WINDOW_SIZE_ACTIVE_MS));
WINDOW_SIZE_WORKING_MS =
properties.getLong(KEY_WINDOW_SIZE_WORKING_MS,
- Flags.adjustQuotaDefaultConstants()
+ Flags.adjustQuotaDefaultConstants() && !isCompatEnabled
? DEFAULT_CURRENT_WINDOW_SIZE_WORKING_MS :
DEFAULT_LEGACY_WINDOW_SIZE_WORKING_MS);
WINDOW_SIZE_FREQUENT_MS =
properties.getLong(KEY_WINDOW_SIZE_FREQUENT_MS,
- Flags.adjustQuotaDefaultConstants()
+ Flags.adjustQuotaDefaultConstants() && !isCompatEnabled
? DEFAULT_CURRENT_WINDOW_SIZE_FREQUENT_MS :
DEFAULT_LEGACY_WINDOW_SIZE_FREQUENT_MS);
WINDOW_SIZE_RARE_MS = properties.getLong(KEY_WINDOW_SIZE_RARE_MS,
@@ -4149,6 +4213,8 @@ public final class QuotaController extends StateController {
}
mEJLimitConstantsUpdated = true;
+ final boolean isCompatEnabled = isCompatOverridedForQuotaConstantAdjustment();
+
// Query the values as an atomic set.
final DeviceConfig.Properties properties = DeviceConfig.getProperties(
DeviceConfig.NAMESPACE_JOB_SCHEDULER,
@@ -4163,7 +4229,7 @@ public final class QuotaController extends StateController {
EJ_LIMIT_ACTIVE_MS = properties.getLong(
KEY_EJ_LIMIT_ACTIVE_MS, DEFAULT_EJ_LIMIT_ACTIVE_MS);
EJ_LIMIT_WORKING_MS = properties.getLong(
- KEY_EJ_LIMIT_WORKING_MS, Flags.adjustQuotaDefaultConstants()
+ KEY_EJ_LIMIT_WORKING_MS, Flags.adjustQuotaDefaultConstants() && !isCompatEnabled
? DEFAULT_CURRENT_EJ_LIMIT_WORKING_MS :
DEFAULT_LEGACY_EJ_LIMIT_WORKING_MS);
EJ_LIMIT_FREQUENT_MS = properties.getLong(
diff --git a/core/api/current.txt b/core/api/current.txt
index 216bbab882a9..bba21f418e41 100644
--- a/core/api/current.txt
+++ b/core/api/current.txt
@@ -24820,7 +24820,7 @@ package android.media {
method public android.view.Surface getSurface();
method public boolean isPrivacySensitive();
method public void pause() throws java.lang.IllegalStateException;
- method public void prepare() throws java.io.IOException, java.lang.IllegalStateException;
+ method @RequiresPermission(value=android.Manifest.permission.RECORD_AUDIO, conditional=true) public void prepare() throws java.io.IOException, java.lang.IllegalStateException;
method public void registerAudioRecordingCallback(@NonNull java.util.concurrent.Executor, @NonNull android.media.AudioManager.AudioRecordingCallback);
method public void release();
method public void removeOnRoutingChangedListener(android.media.AudioRouting.OnRoutingChangedListener);
@@ -24861,7 +24861,7 @@ package android.media {
method public void setVideoProfile(@NonNull android.media.EncoderProfiles.VideoProfile);
method public void setVideoSize(int, int) throws java.lang.IllegalStateException;
method public void setVideoSource(int) throws java.lang.IllegalStateException;
- method public void start() throws java.lang.IllegalStateException;
+ method @RequiresPermission(value=android.Manifest.permission.RECORD_AUDIO, conditional=true) public void start() throws java.lang.IllegalStateException;
method public void stop() throws java.lang.IllegalStateException;
method public void unregisterAudioRecordingCallback(@NonNull android.media.AudioManager.AudioRecordingCallback);
field public static final int MEDIA_ERROR_SERVER_DIED = 100; // 0x64
diff --git a/core/api/system-current.txt b/core/api/system-current.txt
index 35720fd17769..12f302a01a73 100644
--- a/core/api/system-current.txt
+++ b/core/api/system-current.txt
@@ -7354,7 +7354,15 @@ package android.media {
public class AudioDeviceVolumeManager {
method @NonNull @RequiresPermission(anyOf={android.Manifest.permission.MODIFY_AUDIO_ROUTING, android.Manifest.permission.MODIFY_AUDIO_SETTINGS_PRIVILEGED}) public android.media.VolumeInfo getDeviceVolume(@NonNull android.media.VolumeInfo, @NonNull android.media.AudioDeviceAttributes);
+ method @FlaggedApi("android.media.audio.unify_absolute_volume_management") @RequiresPermission(anyOf={android.Manifest.permission.MODIFY_AUDIO_ROUTING, "android.permission.QUERY_AUDIO_STATE", android.Manifest.permission.MODIFY_AUDIO_SETTINGS_PRIVILEGED}) public int getDeviceVolumeBehavior(@NonNull android.media.AudioDeviceAttributes);
method @RequiresPermission(anyOf={android.Manifest.permission.MODIFY_AUDIO_ROUTING, android.Manifest.permission.MODIFY_AUDIO_SETTINGS_PRIVILEGED}) public void setDeviceVolume(@NonNull android.media.VolumeInfo, @NonNull android.media.AudioDeviceAttributes);
+ method @FlaggedApi("android.media.audio.unify_absolute_volume_management") @RequiresPermission(anyOf={android.Manifest.permission.MODIFY_AUDIO_ROUTING, android.Manifest.permission.MODIFY_AUDIO_SETTINGS_PRIVILEGED}) public void setDeviceVolumeBehavior(@NonNull android.media.AudioDeviceAttributes, int);
+ field @FlaggedApi("android.media.audio.unify_absolute_volume_management") public static final int DEVICE_VOLUME_BEHAVIOR_ABSOLUTE = 3; // 0x3
+ field @FlaggedApi("android.media.audio.unify_absolute_volume_management") public static final int DEVICE_VOLUME_BEHAVIOR_ABSOLUTE_ADJUST_ONLY = 5; // 0x5
+ field @FlaggedApi("android.media.audio.unify_absolute_volume_management") public static final int DEVICE_VOLUME_BEHAVIOR_ABSOLUTE_MULTI_MODE = 4; // 0x4
+ field @FlaggedApi("android.media.audio.unify_absolute_volume_management") public static final int DEVICE_VOLUME_BEHAVIOR_FIXED = 2; // 0x2
+ field @FlaggedApi("android.media.audio.unify_absolute_volume_management") public static final int DEVICE_VOLUME_BEHAVIOR_FULL = 1; // 0x1
+ field @FlaggedApi("android.media.audio.unify_absolute_volume_management") public static final int DEVICE_VOLUME_BEHAVIOR_VARIABLE = 0; // 0x0
}
public final class AudioFocusInfo implements android.os.Parcelable {
@@ -7399,7 +7407,7 @@ package android.media {
method @NonNull @RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING) public static java.util.List<android.media.audiopolicy.AudioVolumeGroup> getAudioVolumeGroups();
method @NonNull @RequiresPermission(android.Manifest.permission.CALL_AUDIO_INTERCEPTION) public android.media.AudioRecord getCallDownlinkExtractionAudioRecord(@NonNull android.media.AudioFormat);
method @NonNull @RequiresPermission(android.Manifest.permission.CALL_AUDIO_INTERCEPTION) public android.media.AudioTrack getCallUplinkInjectionAudioTrack(@NonNull android.media.AudioFormat);
- method @RequiresPermission(anyOf={android.Manifest.permission.MODIFY_AUDIO_ROUTING, "android.permission.QUERY_AUDIO_STATE", android.Manifest.permission.MODIFY_AUDIO_SETTINGS_PRIVILEGED}) public int getDeviceVolumeBehavior(@NonNull android.media.AudioDeviceAttributes);
+ method @Deprecated @FlaggedApi("android.media.audio.unify_absolute_volume_management") @RequiresPermission(anyOf={android.Manifest.permission.MODIFY_AUDIO_ROUTING, "android.permission.QUERY_AUDIO_STATE", android.Manifest.permission.MODIFY_AUDIO_SETTINGS_PRIVILEGED}) public int getDeviceVolumeBehavior(@NonNull android.media.AudioDeviceAttributes);
method @NonNull @RequiresPermission(anyOf={android.Manifest.permission.MODIFY_AUDIO_ROUTING, "android.permission.QUERY_AUDIO_STATE"}) public java.util.List<android.media.AudioDeviceAttributes> getDevicesForAttributes(@NonNull android.media.AudioAttributes);
method @NonNull @RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_SETTINGS_PRIVILEGED) public java.util.List<java.lang.Integer> getIndependentStreamTypes();
method @RequiresPermission("android.permission.QUERY_AUDIO_STATE") public int getLastAudibleStreamVolume(int);
@@ -7445,7 +7453,7 @@ package android.media {
method public void setAudioServerStateCallback(@NonNull java.util.concurrent.Executor, @NonNull android.media.AudioManager.AudioServerStateCallback);
method @RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING) public void setBluetoothVariableLatencyEnabled(boolean);
method @RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING) public boolean setDeviceAsNonDefaultForStrategy(@NonNull android.media.audiopolicy.AudioProductStrategy, @NonNull android.media.AudioDeviceAttributes);
- method @RequiresPermission(anyOf={android.Manifest.permission.MODIFY_AUDIO_ROUTING, android.Manifest.permission.MODIFY_AUDIO_SETTINGS_PRIVILEGED}) public void setDeviceVolumeBehavior(@NonNull android.media.AudioDeviceAttributes, int);
+ method @Deprecated @FlaggedApi("android.media.audio.unify_absolute_volume_management") @RequiresPermission(anyOf={android.Manifest.permission.MODIFY_AUDIO_ROUTING, android.Manifest.permission.MODIFY_AUDIO_SETTINGS_PRIVILEGED}) public void setDeviceVolumeBehavior(@NonNull android.media.AudioDeviceAttributes, int);
method @RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING) public void setFocusRequestResult(@NonNull android.media.AudioFocusInfo, int, @NonNull android.media.audiopolicy.AudioPolicy);
method @RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING) public boolean setPreferredDeviceForCapturePreset(int, @NonNull android.media.AudioDeviceAttributes);
method @RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING) public boolean setPreferredDeviceForStrategy(@NonNull android.media.audiopolicy.AudioProductStrategy, @NonNull android.media.AudioDeviceAttributes);
@@ -7465,12 +7473,12 @@ package android.media {
field public static final int AUDIOFOCUS_FLAG_PAUSES_ON_DUCKABLE_LOSS = 2; // 0x2
field @RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING) public static final int DEVICE_CONNECTION_STATE_CONNECTED = 1; // 0x1
field @RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING) public static final int DEVICE_CONNECTION_STATE_DISCONNECTED = 0; // 0x0
- field public static final int DEVICE_VOLUME_BEHAVIOR_ABSOLUTE = 3; // 0x3
- field public static final int DEVICE_VOLUME_BEHAVIOR_ABSOLUTE_ADJUST_ONLY = 5; // 0x5
- field public static final int DEVICE_VOLUME_BEHAVIOR_ABSOLUTE_MULTI_MODE = 4; // 0x4
- field public static final int DEVICE_VOLUME_BEHAVIOR_FIXED = 2; // 0x2
- field public static final int DEVICE_VOLUME_BEHAVIOR_FULL = 1; // 0x1
- field public static final int DEVICE_VOLUME_BEHAVIOR_VARIABLE = 0; // 0x0
+ field @Deprecated @FlaggedApi("android.media.audio.unify_absolute_volume_management") public static final int DEVICE_VOLUME_BEHAVIOR_ABSOLUTE = 3; // 0x3
+ field @Deprecated @FlaggedApi("android.media.audio.unify_absolute_volume_management") public static final int DEVICE_VOLUME_BEHAVIOR_ABSOLUTE_ADJUST_ONLY = 5; // 0x5
+ field @Deprecated @FlaggedApi("android.media.audio.unify_absolute_volume_management") public static final int DEVICE_VOLUME_BEHAVIOR_ABSOLUTE_MULTI_MODE = 4; // 0x4
+ field @Deprecated @FlaggedApi("android.media.audio.unify_absolute_volume_management") public static final int DEVICE_VOLUME_BEHAVIOR_FIXED = 2; // 0x2
+ field @Deprecated @FlaggedApi("android.media.audio.unify_absolute_volume_management") public static final int DEVICE_VOLUME_BEHAVIOR_FULL = 1; // 0x1
+ field @Deprecated @FlaggedApi("android.media.audio.unify_absolute_volume_management") public static final int DEVICE_VOLUME_BEHAVIOR_VARIABLE = 0; // 0x0
field public static final String EXTRA_VOLUME_STREAM_TYPE = "android.media.EXTRA_VOLUME_STREAM_TYPE";
field public static final String EXTRA_VOLUME_STREAM_VALUE = "android.media.EXTRA_VOLUME_STREAM_VALUE";
field public static final int FLAG_BLUETOOTH_ABS_VOLUME = 64; // 0x40
diff --git a/core/api/test-current.txt b/core/api/test-current.txt
index 4c8283907712..daa1902edf02 100644
--- a/core/api/test-current.txt
+++ b/core/api/test-current.txt
@@ -1955,6 +1955,10 @@ package android.media {
method public static void enforceValidAudioDeviceTypeOut(int);
}
+ public class AudioDeviceVolumeManager {
+ method @RequiresPermission(anyOf={android.Manifest.permission.MODIFY_AUDIO_ROUTING, android.Manifest.permission.QUERY_AUDIO_STATE, android.Manifest.permission.MODIFY_AUDIO_SETTINGS_PRIVILEGED}) public boolean isFullVolumeDevice();
+ }
+
public final class AudioFocusRequest {
method @Nullable public android.media.AudioManager.OnAudioFocusChangeListener getOnAudioFocusChangeListener();
}
@@ -2010,7 +2014,6 @@ package android.media {
method @NonNull public android.media.VolumePolicy getVolumePolicy();
method public boolean hasRegisteredDynamicPolicy();
method @RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_SETTINGS_PRIVILEGED) public boolean isCsdEnabled();
- method @RequiresPermission(anyOf={android.Manifest.permission.MODIFY_AUDIO_ROUTING, android.Manifest.permission.QUERY_AUDIO_STATE, android.Manifest.permission.MODIFY_AUDIO_SETTINGS_PRIVILEGED}) public boolean isFullVolumeDevice();
method @RequiresPermission(android.Manifest.permission.CALL_AUDIO_INTERCEPTION) public boolean isPstnCallAudioInterceptable();
method @RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_SETTINGS_PRIVILEGED) public boolean isVolumeControlUsingVolumeGroups();
method public void permissionUpdateBarrier();
diff --git a/core/java/android/app/ForegroundServiceTypePolicy.java b/core/java/android/app/ForegroundServiceTypePolicy.java
index 6efc4ef55180..3003b79435e2 100644
--- a/core/java/android/app/ForegroundServiceTypePolicy.java
+++ b/core/java/android/app/ForegroundServiceTypePolicy.java
@@ -49,11 +49,14 @@ import android.annotation.Nullable;
import android.annotation.SuppressLint;
import android.app.compat.CompatChanges;
import android.app.role.RoleManager;
+import android.companion.virtual.VirtualDevice;
+import android.companion.virtual.VirtualDeviceManager;
import android.compat.Compatibility;
import android.compat.annotation.ChangeId;
import android.compat.annotation.Disabled;
import android.compat.annotation.EnabledAfter;
import android.compat.annotation.Overridable;
+import android.content.AttributionSource;
import android.content.Context;
import android.content.PermissionChecker;
import android.content.pm.PackageManager;
@@ -67,6 +70,7 @@ import android.os.RemoteException;
import android.os.ServiceManager;
import android.os.UserHandle;
import android.permission.PermissionCheckerManager;
+import android.permission.PermissionManager;
import android.provider.DeviceConfig;
import android.text.TextUtils;
import android.util.ArrayMap;
@@ -1174,17 +1178,48 @@ public abstract class ForegroundServiceTypePolicy {
@PackageManager.PermissionResult
public int checkPermission(@NonNull Context context, int callerUid, int callerPid,
String packageName, boolean allowWhileInUse) {
- return checkPermission(context, mName, callerUid, callerPid, packageName,
- allowWhileInUse);
+ int permissionResult = checkPermission(context, mName, callerUid, callerPid,
+ packageName, allowWhileInUse, Context.DEVICE_ID_DEFAULT);
+
+ if (permissionResult == PERMISSION_GRANTED
+ || !PermissionManager.DEVICE_AWARE_PERMISSIONS.contains(mName)) {
+ return permissionResult;
+ }
+
+ // For device aware permissions, check if the permission is granted on any other
+ // active virtual device
+ VirtualDeviceManager vdm = context.getSystemService(VirtualDeviceManager.class);
+ if (vdm == null) {
+ return permissionResult;
+ }
+
+ final List<VirtualDevice> virtualDevices = vdm.getVirtualDevices();
+ for (int i = 0, size = virtualDevices.size(); i < size; i++) {
+ final VirtualDevice virtualDevice = virtualDevices.get(i);
+ int resolvedDeviceId = PermissionManager.resolveDeviceIdForPermissionCheck(
+ context, virtualDevice.getDeviceId(), mName);
+ // we already checked on the default device context
+ if (resolvedDeviceId == Context.DEVICE_ID_DEFAULT) {
+ continue;
+ }
+ permissionResult = checkPermission(context, mName, callerUid, callerPid,
+ packageName, allowWhileInUse, resolvedDeviceId);
+ if (permissionResult == PERMISSION_GRANTED) {
+ break;
+ }
+ }
+
+ return permissionResult;
}
@SuppressLint("AndroidFrameworkRequiresPermission")
@PackageManager.PermissionResult
int checkPermission(@NonNull Context context, @NonNull String name, int callerUid,
- int callerPid, String packageName, boolean allowWhileInUse) {
+ int callerPid, String packageName, boolean allowWhileInUse, int deviceId) {
+ final AttributionSource attributionSource = new AttributionSource(callerUid,
+ packageName, null /*attributionTag*/, deviceId);
@PermissionCheckerManager.PermissionResult final int result =
- PermissionChecker.checkPermissionForPreflight(context, name,
- callerPid, callerUid, packageName);
+ PermissionChecker.checkPermissionForPreflight(context, name, attributionSource);
if (result == PERMISSION_HARD_DENIED) {
// If the user didn't grant this permission at all.
return PERMISSION_DENIED;
@@ -1196,7 +1231,7 @@ public abstract class ForegroundServiceTypePolicy {
? PERMISSION_GRANTED : PERMISSION_DENIED;
}
final AppOpsManager appOpsManager = context.getSystemService(AppOpsManager.class);
- final int mode = appOpsManager.unsafeCheckOpRawNoThrow(opCode, callerUid, packageName);
+ final int mode = appOpsManager.unsafeCheckOpRawNoThrow(opCode, attributionSource);
switch (mode) {
case MODE_ALLOWED:
// The appop is just allowed, plain and simple.
diff --git a/core/java/android/app/WallpaperManager.java b/core/java/android/app/WallpaperManager.java
index 957482450893..7f1870bd2d87 100644
--- a/core/java/android/app/WallpaperManager.java
+++ b/core/java/android/app/WallpaperManager.java
@@ -248,7 +248,9 @@ public class WallpaperManager {
/**
* Command for {@link #sendWallpaperCommand}: reported by System UI when the device keyguard
* starts going away.
- * This command is triggered by {@link android.app.IActivityTaskManager#keyguardGoingAway(int)}.
+ * <p>
+ * This command is triggered by {@link android.app.IActivityTaskManager#keyguardGoingAway(int)}
+ * or by {@link android.app.IActivityTaskManager#setLockScreenShown(boolean, boolean)}.
*
* @hide
*/
@@ -256,6 +258,18 @@ public class WallpaperManager {
"android.wallpaper.keyguardgoingaway";
/**
+ * Command for {@link #sendWallpaperCommand}: reported by System UI when the device keyguard
+ * starts going away.
+ *
+ * <p>This command is triggered by
+ * {@link android.app.IActivityTaskManager#setLockScreenShown(boolean, boolean)}.
+ *
+ * @hide
+ */
+ public static final String COMMAND_KEYGUARD_APPEARING =
+ "android.wallpaper.keyguardappearing";
+
+ /**
* Command for {@link #sendWallpaperCommand}: reported by System UI when the device is going to
* sleep. The x and y arguments are a location (possibly very roughly) corresponding to the
* action that caused the device to go to sleep. For example, if the power button was pressed,
diff --git a/core/java/android/app/wallpaper.aconfig b/core/java/android/app/wallpaper.aconfig
index 7aba172fad79..4a15a723da1a 100644
--- a/core/java/android/app/wallpaper.aconfig
+++ b/core/java/android/app/wallpaper.aconfig
@@ -24,6 +24,16 @@ flag {
}
flag {
+ name: "notify_keyguard_events"
+ namespace: "systemui"
+ description: "Send keyguard showing/hiding/going-away events to wallpaper as wallpaper commands (guarded by permission)"
+ bug: "395897130"
+ metadata {
+ purpose: PURPOSE_BUGFIX
+ }
+}
+
+flag {
name: "accurate_wallpaper_downsampling"
namespace: "systemui"
description: "Accurate downsampling of wallpaper bitmap for high resolution images"
diff --git a/core/java/android/content/pm/UserInfo.java b/core/java/android/content/pm/UserInfo.java
index 53203eba4020..c5412a982110 100644
--- a/core/java/android/content/pm/UserInfo.java
+++ b/core/java/android/content/pm/UserInfo.java
@@ -494,10 +494,14 @@ public class UserInfo implements Parcelable {
// TODO(b/142482943): Make this logic more specific and customizable. (canHaveProfile(userType))
/* @hide */
public boolean canHaveProfile() {
- if (isProfile() || isGuest() || isRestricted()) {
+ if (!isFull() || isProfile() || isGuest() || isRestricted() || isDemo()) {
return false;
}
- return isMain();
+ // NOTE: profiles used to be restricted just to the system user (and later to the main
+ // user), but from the framework point of view there is no need for such restriction, hence
+ // it's lifted
+ // TODO(b/374832167): check value of config_supportProfilesOnNonMainUser
+ return isMain() || android.multiuser.Flags.profilesForAll();
}
// TODO(b/142482943): Get rid of this (after removing it from all tests) if feasible.
diff --git a/core/java/android/content/pm/multiuser.aconfig b/core/java/android/content/pm/multiuser.aconfig
index 3411a4897e83..3dbd5b239ae5 100644
--- a/core/java/android/content/pm/multiuser.aconfig
+++ b/core/java/android/content/pm/multiuser.aconfig
@@ -646,3 +646,10 @@ flag {
purpose: PURPOSE_BUGFIX
}
}
+
+flag {
+ name: "profiles_for_all"
+ namespace: "multiuser"
+ description: "Allows any regular user to have profiles"
+ bug: "374832167"
+}
diff --git a/core/java/android/hardware/biometrics/BiometricConstants.java b/core/java/android/hardware/biometrics/BiometricConstants.java
index a7fbce51e9df..7dc6afba3f1c 100644
--- a/core/java/android/hardware/biometrics/BiometricConstants.java
+++ b/core/java/android/hardware/biometrics/BiometricConstants.java
@@ -188,24 +188,6 @@ public interface BiometricConstants {
int BIOMETRIC_ERROR_CONTENT_VIEW_MORE_OPTIONS_BUTTON = 22;
/**
- * The error code returned after lock out error happens, the error dialog shows, and the users
- * dismisses the dialog. This is a placeholder that is currently only used by the support
- * library.
- *
- * @hide
- */
- int BIOMETRIC_ERROR_LOCKOUT_ERROR_DIALOG_DISMISSED = 23;
-
- /**
- * The error code returned after biometric hardware error happens, the error dialog shows, and
- * the users dismisses the dialog.This is a placeholder that is currently only used by the
- * support library.
- *
- * @hide
- */
- int BIOMETRIC_ERROR_BIOMETRIC_HARDWARE_ERROR_DIALOG_DISMISSED = 24;
-
- /**
* This constant is only used by SystemUI. It notifies SystemUI that authentication was paused
* because the authentication attempt was unsuccessful.
* @hide
@@ -237,8 +219,6 @@ public interface BiometricConstants {
BIOMETRIC_ERROR_IDENTITY_CHECK_NOT_ACTIVE,
BIOMETRIC_ERROR_NOT_ENABLED_FOR_APPS,
BIOMETRIC_ERROR_CONTENT_VIEW_MORE_OPTIONS_BUTTON,
- BIOMETRIC_ERROR_LOCKOUT_ERROR_DIALOG_DISMISSED,
- BIOMETRIC_ERROR_BIOMETRIC_HARDWARE_ERROR_DIALOG_DISMISSED,
BIOMETRIC_PAUSED_REJECTED})
@Retention(RetentionPolicy.SOURCE)
@interface Errors {}
diff --git a/core/java/android/os/Binder.java b/core/java/android/os/Binder.java
index ee62dea7f9e5..6b1e918a3c47 100644
--- a/core/java/android/os/Binder.java
+++ b/core/java/android/os/Binder.java
@@ -149,6 +149,11 @@ public class Binder implements IBinder {
private static volatile boolean sStackTrackingEnabled = false;
/**
+ * The extension binder object
+ */
+ private IBinder mExtension = null;
+
+ /**
* Enable Binder IPC stack tracking. If enabled, every binder transaction will be logged to
* {@link TransactionTracker}.
*
@@ -1237,7 +1242,9 @@ public class Binder implements IBinder {
/** @hide */
@Override
- public final native @Nullable IBinder getExtension();
+ public final @Nullable IBinder getExtension() {
+ return mExtension;
+ }
/**
* Set the binder extension.
@@ -1245,7 +1252,12 @@ public class Binder implements IBinder {
*
* @hide
*/
- public final native void setExtension(@Nullable IBinder extension);
+ public final void setExtension(@Nullable IBinder extension) {
+ mExtension = extension;
+ setExtensionNative(extension);
+ }
+
+ private final native void setExtensionNative(@Nullable IBinder extension);
/**
* Default implementation rewinds the parcels and calls onTransact. On
diff --git a/core/java/android/view/SurfaceView.java b/core/java/android/view/SurfaceView.java
index 1b57b0045537..94e9aa709369 100644
--- a/core/java/android/view/SurfaceView.java
+++ b/core/java/android/view/SurfaceView.java
@@ -1070,9 +1070,9 @@ public class SurfaceView extends View implements ViewRootImpl.SurfaceChangedCall
}
if (mSurfacePackage != null) {
- mSurfaceControlViewHostParent.detach();
mEmbeddedWindowParams.clear();
if (releaseSurfacePackage) {
+ mSurfaceControlViewHostParent.detach();
mSurfacePackage.release();
mSurfacePackage = null;
}
diff --git a/core/java/com/android/internal/os/BatteryStatsHistory.java b/core/java/com/android/internal/os/BatteryStatsHistory.java
index 8151429f9139..f1c47a7a023b 100644
--- a/core/java/com/android/internal/os/BatteryStatsHistory.java
+++ b/core/java/com/android/internal/os/BatteryStatsHistory.java
@@ -760,9 +760,20 @@ public class BatteryStatsHistory {
break;
}
- if (fragment.monotonicTimeMs >= startTimeMs && fragment != mActiveFragment) {
- containers.add(new BatteryHistoryParcelContainer(fragment));
+ if (fragment.monotonicTimeMs >= mHistoryBufferStartTime) {
+ // Do not include the backup of the current buffer, which is explicitly
+ // included later
+ continue;
}
+
+ if (i < fragments.size() - 1
+ && fragments.get(i + 1).monotonicTimeMs < startTimeMs) {
+ // Since fragments are ordered, an early start of next fragment implies an
+ // early end for this one.
+ continue;
+ }
+
+ containers.add(new BatteryHistoryParcelContainer(fragment));
}
}
diff --git a/core/jni/android_util_Binder.cpp b/core/jni/android_util_Binder.cpp
index a0c8f30c9356..36bda61c94a6 100644
--- a/core/jni/android_util_Binder.cpp
+++ b/core/jni/android_util_Binder.cpp
@@ -73,6 +73,7 @@ static struct bindernative_offsets_t
jmethodID mExecTransact;
jmethodID mGetInterfaceDescriptor;
jmethodID mTransactionCallback;
+ jmethodID mGetExtension;
// Object state.
jfieldID mObject;
@@ -488,8 +489,12 @@ public:
if (mVintf) {
::android::internal::Stability::markVintf(b.get());
}
- if (mExtension != nullptr) {
- b.get()->setExtension(mExtension);
+ if (mSetExtensionCalled) {
+ jobject javaIBinderObject = env->CallObjectMethod(obj, gBinderOffsets.mGetExtension);
+ sp<IBinder> extensionFromJava = ibinderForJavaObject(env, javaIBinderObject);
+ if (extensionFromJava != nullptr) {
+ b.get()->setExtension(extensionFromJava);
+ }
}
mBinder = b;
ALOGV("Creating JavaBinder %p (refs %p) for Object %p, weakCount=%" PRId32 "\n",
@@ -515,21 +520,12 @@ public:
mVintf = false;
}
- sp<IBinder> getExtension() {
- AutoMutex _l(mLock);
- sp<JavaBBinder> b = mBinder.promote();
- if (b != nullptr) {
- return b.get()->getExtension();
- }
- return mExtension;
- }
-
void setExtension(const sp<IBinder>& extension) {
AutoMutex _l(mLock);
- mExtension = extension;
+ mSetExtensionCalled = true;
sp<JavaBBinder> b = mBinder.promote();
if (b != nullptr) {
- b.get()->setExtension(mExtension);
+ b.get()->setExtension(extension);
}
}
@@ -541,8 +537,7 @@ private:
// is too much binder state here, we can think about making JavaBBinder an
// sp here (avoid recreating it)
bool mVintf = false;
-
- sp<IBinder> mExtension;
+ bool mSetExtensionCalled = false;
};
// ----------------------------------------------------------------------------
@@ -1254,10 +1249,6 @@ static void android_os_Binder_blockUntilThreadAvailable(JNIEnv* env, jobject cla
return IPCThreadState::self()->blockUntilThreadAvailable();
}
-static jobject android_os_Binder_getExtension(JNIEnv* env, jobject obj) {
- JavaBBinderHolder* jbh = (JavaBBinderHolder*) env->GetLongField(obj, gBinderOffsets.mObject);
- return javaObjectForIBinder(env, jbh->getExtension());
-}
static void android_os_Binder_setExtension(JNIEnv* env, jobject obj, jobject extensionObject) {
JavaBBinderHolder* jbh = (JavaBBinderHolder*) env->GetLongField(obj, gBinderOffsets.mObject);
@@ -1300,8 +1291,7 @@ static const JNINativeMethod gBinderMethods[] = {
{ "getNativeBBinderHolder", "()J", (void*)android_os_Binder_getNativeBBinderHolder },
{ "getNativeFinalizer", "()J", (void*)android_os_Binder_getNativeFinalizer },
{ "blockUntilThreadAvailable", "()V", (void*)android_os_Binder_blockUntilThreadAvailable },
- { "getExtension", "()Landroid/os/IBinder;", (void*)android_os_Binder_getExtension },
- { "setExtension", "(Landroid/os/IBinder;)V", (void*)android_os_Binder_setExtension },
+ { "setExtensionNative", "(Landroid/os/IBinder;)V", (void*)android_os_Binder_setExtension },
};
// clang-format on
@@ -1318,6 +1308,8 @@ static int int_register_android_os_Binder(JNIEnv* env)
gBinderOffsets.mTransactionCallback =
GetStaticMethodIDOrDie(env, clazz, "transactionCallback", "(IIII)V");
gBinderOffsets.mObject = GetFieldIDOrDie(env, clazz, "mObject", "J");
+ gBinderOffsets.mGetExtension = GetMethodIDOrDie(env, clazz, "getExtension",
+ "()Landroid/os/IBinder;");
return RegisterMethodsOrDie(
env, kBinderPathName,
diff --git a/core/tests/coretests/src/android/content/pm/UserInfoTest.java b/core/tests/coretests/src/android/content/pm/UserInfoTest.java
index edeea6d85ca6..c84c21557ea4 100644
--- a/core/tests/coretests/src/android/content/pm/UserInfoTest.java
+++ b/core/tests/coretests/src/android/content/pm/UserInfoTest.java
@@ -16,19 +16,44 @@
package android.content.pm;
+import static android.content.pm.UserInfo.FLAG_DEMO;
+import static android.content.pm.UserInfo.FLAG_FULL;
+import static android.content.pm.UserInfo.FLAG_GUEST;
+import static android.content.pm.UserInfo.FLAG_MAIN;
+import static android.content.pm.UserInfo.FLAG_PROFILE;
+import static android.content.pm.UserInfo.FLAG_SYSTEM;
+import static android.os.UserManager.USER_TYPE_FULL_RESTRICTED;
+import static android.os.UserManager.USER_TYPE_FULL_SYSTEM;
+import static android.os.UserManager.USER_TYPE_SYSTEM_HEADLESS;
+
import static com.google.common.truth.Truth.assertThat;
+import android.content.pm.UserInfo.UserInfoFlag;
import android.os.UserHandle;
+import android.platform.test.annotations.DisableFlags;
+import android.platform.test.annotations.EnableFlags;
+import android.platform.test.flag.junit.SetFlagsRule;
import androidx.test.ext.junit.runners.AndroidJUnit4;
import androidx.test.filters.SmallTest;
+import com.google.common.truth.Expect;
+
+import org.junit.Rule;
import org.junit.Test;
import org.junit.runner.RunWith;
+
@RunWith(AndroidJUnit4.class)
@SmallTest
-public class UserInfoTest {
+public final class UserInfoTest {
+
+ @Rule
+ public final SetFlagsRule flags =
+ new SetFlagsRule(SetFlagsRule.DefaultInitValueType.DEVICE_DEFAULT);
+
+ @Rule public final Expect expect = Expect.create();
+
@Test
public void testSimple() throws Exception {
final UserInfo ui = new UserInfo(10, "Test", UserInfo.FLAG_GUEST);
@@ -56,9 +81,6 @@ public class UserInfoTest {
assertThat(ui.isInitialized()).isEqualTo(false);
assertThat(ui.isFull()).isEqualTo(false);
assertThat(ui.isMain()).isEqualTo(false);
-
- // Derived dynamically
- assertThat(ui.canHaveProfile()).isEqualTo(false);
}
@Test
@@ -68,4 +90,64 @@ public class UserInfoTest {
assertThat(ui.toString()).isNotEmpty();
assertThat(ui.toFullString()).isNotEmpty();
}
+
+ @Test
+ @DisableFlags(android.multiuser.Flags.FLAG_PROFILES_FOR_ALL)
+ public void testCanHaveProfile_flagProfilesForAllDisabled() {
+ expectCannotHaveProfile("non-full user", createTestUserInfo(/* flags= */ 0));
+ expectCannotHaveProfile("guest user", createTestUserInfo(FLAG_FULL | FLAG_GUEST));
+ expectCanHaveProfile("main user", createTestUserInfo(FLAG_FULL | FLAG_MAIN));
+ expectCannotHaveProfile("non-main user", createTestUserInfo(FLAG_FULL));
+ expectCannotHaveProfile("demo user", createTestUserInfo(FLAG_FULL | FLAG_DEMO));
+ expectCannotHaveProfile("restricted user",
+ createTestUserInfo(USER_TYPE_FULL_RESTRICTED, FLAG_FULL));
+ expectCannotHaveProfile("profile user", createTestUserInfo(FLAG_PROFILE));
+ expectCanHaveProfile("(full) system user that's also main user",
+ createTestUserInfo(USER_TYPE_FULL_SYSTEM, FLAG_FULL | FLAG_SYSTEM | FLAG_MAIN));
+ expectCannotHaveProfile("headless system user that's not main user",
+ createTestUserInfo(USER_TYPE_SYSTEM_HEADLESS, FLAG_SYSTEM));
+ }
+
+ @Test
+ @EnableFlags(android.multiuser.Flags.FLAG_PROFILES_FOR_ALL)
+ public void testCanHaveProfile_flagProfilesForAllEnabled() {
+ expectCannotHaveProfile("non-full user", createTestUserInfo(/* flags= */ 0));
+ expectCannotHaveProfile("guest user", createTestUserInfo(FLAG_FULL | FLAG_GUEST));
+ expectCanHaveProfile("main user", createTestUserInfo(FLAG_FULL | FLAG_MAIN));
+ expectCanHaveProfile("non-main user", createTestUserInfo(FLAG_FULL));
+ expectCannotHaveProfile("demo user", createTestUserInfo(FLAG_FULL | FLAG_DEMO));
+ expectCannotHaveProfile("restricted user",
+ createTestUserInfo(USER_TYPE_FULL_RESTRICTED, FLAG_FULL));
+ expectCannotHaveProfile("profile user", createTestUserInfo(FLAG_PROFILE));
+ expectCanHaveProfile("(full) system user that's also main user",
+ createTestUserInfo(USER_TYPE_FULL_SYSTEM, FLAG_FULL | FLAG_SYSTEM | FLAG_MAIN));
+ expectCannotHaveProfile("headless system user that's not main user",
+ createTestUserInfo(USER_TYPE_SYSTEM_HEADLESS, FLAG_SYSTEM));
+ }
+
+ /**
+ * Creates a new {@link UserInfo} with id {@code 10}, name {@code Test}, and the given
+ * {@code flags}.
+ */
+ private UserInfo createTestUserInfo(@UserInfoFlag int flags) {
+ return new UserInfo(10, "Test", flags);
+ }
+
+ /**
+ * Creates a new {@link UserInfo} with id {@code 10}, name {@code Test}, and the given
+ * {@code userType} and {@code flags}.
+ */
+ private UserInfo createTestUserInfo(String userType, @UserInfoFlag int flags) {
+ return new UserInfo(10, "Test", /* iconPath= */ null, flags, userType);
+ }
+
+ private void expectCanHaveProfile(String description, UserInfo user) {
+ expect.withMessage("canHaveProfile() on %s (%s)", description, user)
+ .that(user.canHaveProfile()).isTrue();
+ }
+
+ private void expectCannotHaveProfile(String description, UserInfo user) {
+ expect.withMessage("canHaveProfile() on %s (%s)", description, user)
+ .that(user.canHaveProfile()).isFalse();
+ }
}
diff --git a/libs/WindowManager/Shell/aconfig/multitasking.aconfig b/libs/WindowManager/Shell/aconfig/multitasking.aconfig
index b6a1501831c0..19455a313a9d 100644
--- a/libs/WindowManager/Shell/aconfig/multitasking.aconfig
+++ b/libs/WindowManager/Shell/aconfig/multitasking.aconfig
@@ -211,3 +211,10 @@ flag {
description: "Makes the split divider snap 'magnetically' to available snap points during drag"
bug: "383631946"
}
+
+flag {
+ name: "enable_dynamic_insets_for_app_launch"
+ namespace: "multitasking"
+ description: "Enables dynamic insets for app launch so the window is properly cropped"
+ bug: "336511494"
+}
diff --git a/libs/WindowManager/Shell/shared/src/com/android/wm/shell/shared/GroupedTaskInfo.java b/libs/WindowManager/Shell/shared/src/com/android/wm/shell/shared/GroupedTaskInfo.java
index 25b9f8ccc6ae..f68afea92850 100644
--- a/libs/WindowManager/Shell/shared/src/com/android/wm/shell/shared/GroupedTaskInfo.java
+++ b/libs/WindowManager/Shell/shared/src/com/android/wm/shell/shared/GroupedTaskInfo.java
@@ -18,6 +18,7 @@ package com.android.wm.shell.shared;
import static android.app.WindowConfiguration.windowingModeToString;
import static android.content.Intent.FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS;
+import static android.view.Display.INVALID_DISPLAY;
import android.annotation.IntDef;
import android.app.ActivityManager.RecentTaskInfo;
@@ -65,6 +66,11 @@ public class GroupedTaskInfo implements Parcelable {
private final int mDeskId;
/**
+ * The ID of the display that desk with [mDeskId] is in.
+ */
+ private final int mDeskDisplayId;
+
+ /**
* The type of this particular task info, can be one of TYPE_FULLSCREEN, TYPE_SPLIT or
* TYPE_DESK.
*/
@@ -109,17 +115,19 @@ public class GroupedTaskInfo implements Parcelable {
* Create new for a stack of fullscreen tasks
*/
public static GroupedTaskInfo forFullscreenTasks(@NonNull TaskInfo task) {
- return new GroupedTaskInfo(/* deskId = */ -1, List.of(task), null, TYPE_FULLSCREEN,
- /* minimizedFreeformTaskIds = */ null);
+ return new GroupedTaskInfo(/* deskId = */ -1, /* displayId = */ INVALID_DISPLAY,
+ List.of(task), null,
+ TYPE_FULLSCREEN, /* minimizedFreeformTaskIds = */ null);
}
/**
* Create new for a pair of tasks in split screen
*/
public static GroupedTaskInfo forSplitTasks(@NonNull TaskInfo task1,
- @NonNull TaskInfo task2, @NonNull SplitBounds splitBounds) {
- return new GroupedTaskInfo(/* deskId = */ -1, List.of(task1, task2), splitBounds,
- TYPE_SPLIT, /* minimizedFreeformTaskIds = */ null);
+ @NonNull TaskInfo task2, @NonNull SplitBounds splitBounds) {
+ return new GroupedTaskInfo(/* deskId = */ -1, /* displayId = */ INVALID_DISPLAY,
+ List.of(task1, task2),
+ splitBounds, TYPE_SPLIT, /* minimizedFreeformTaskIds = */ null);
}
/**
@@ -127,9 +135,11 @@ public class GroupedTaskInfo implements Parcelable {
*/
public static GroupedTaskInfo forDeskTasks(
int deskId,
+ int deskDisplayId,
@NonNull List<TaskInfo> tasks,
@NonNull Set<Integer> minimizedFreeformTaskIds) {
- return new GroupedTaskInfo(deskId, tasks, /* splitBounds = */ null, TYPE_DESK,
+ return new GroupedTaskInfo(deskId, deskDisplayId, tasks, /* splitBounds = */ null,
+ TYPE_DESK,
minimizedFreeformTaskIds.stream().mapToInt(i -> i).toArray());
}
@@ -149,11 +159,13 @@ public class GroupedTaskInfo implements Parcelable {
private GroupedTaskInfo(
int deskId,
+ int deskDisplayId,
@NonNull List<TaskInfo> tasks,
@Nullable SplitBounds splitBounds,
@GroupType int type,
@Nullable int[] minimizedFreeformTaskIds) {
mDeskId = deskId;
+ mDeskDisplayId = deskDisplayId;
mTasks = tasks;
mGroupedTasks = null;
mSplitBounds = splitBounds;
@@ -164,6 +176,7 @@ public class GroupedTaskInfo implements Parcelable {
private GroupedTaskInfo(@NonNull List<GroupedTaskInfo> groupedTasks) {
mDeskId = -1;
+ mDeskDisplayId = INVALID_DISPLAY;
mTasks = null;
mGroupedTasks = groupedTasks;
mSplitBounds = null;
@@ -185,6 +198,7 @@ public class GroupedTaskInfo implements Parcelable {
protected GroupedTaskInfo(@NonNull Parcel parcel) {
mDeskId = parcel.readInt();
+ mDeskDisplayId = parcel.readInt();
mTasks = new ArrayList();
final int numTasks = parcel.readInt();
for (int i = 0; i < numTasks; i++) {
@@ -295,6 +309,16 @@ public class GroupedTaskInfo implements Parcelable {
}
/**
+ * Returns the ID of the display that hosts the desk represented by [mDeskId].
+ */
+ public int getDeskDisplayId() {
+ if (mType != TYPE_DESK) {
+ throw new IllegalStateException("No display ID for non desktop task");
+ }
+ return mDeskDisplayId;
+ }
+
+ /**
* Get type of this recents entry. One of {@link GroupType}.
* Note: This is deprecated, callers should use `isBaseType()` and not make assumptions about
* specific group types
@@ -323,6 +347,7 @@ public class GroupedTaskInfo implements Parcelable {
}
GroupedTaskInfo other = (GroupedTaskInfo) obj;
return mDeskId == other.mDeskId
+ && mDeskDisplayId == other.mDeskDisplayId
&& mType == other.mType
&& Objects.equals(mTasks, other.mTasks)
&& Objects.equals(mGroupedTasks, other.mGroupedTasks)
@@ -332,7 +357,7 @@ public class GroupedTaskInfo implements Parcelable {
@Override
public int hashCode() {
- return Objects.hash(mDeskId, mType, mTasks, mGroupedTasks, mSplitBounds,
+ return Objects.hash(mDeskId, mDeskDisplayId, mType, mTasks, mGroupedTasks, mSplitBounds,
Arrays.hashCode(mMinimizedTaskIds));
}
@@ -345,6 +370,7 @@ public class GroupedTaskInfo implements Parcelable {
.collect(Collectors.joining(",\n\t", "[\n\t", "\n]")));
} else {
taskString.append("Desk ID= ").append(mDeskId).append(", ");
+ taskString.append("Desk Display ID=").append(mDeskDisplayId).append(", ");
taskString.append("Tasks=" + mTasks.stream()
.map(taskInfo -> getTaskInfoDumpString(taskInfo))
.collect(Collectors.joining(", ", "[", "]")));
@@ -377,6 +403,7 @@ public class GroupedTaskInfo implements Parcelable {
@Override
public void writeToParcel(Parcel parcel, int flags) {
parcel.writeInt(mDeskId);
+ parcel.writeInt(mDeskDisplayId);
// We don't use the parcel list methods because we want to only write the TaskInfo state
// and not the subclasses (Recents/RunningTaskInfo) whose fields are all deprecated
final int tasksSize = mTasks != null ? mTasks.size() : 0;
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/recents/RecentTasksController.java b/libs/WindowManager/Shell/src/com/android/wm/shell/recents/RecentTasksController.java
index bb5b5cec1b4a..382fa9640ff9 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/recents/RecentTasksController.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/recents/RecentTasksController.java
@@ -536,17 +536,20 @@ public class RecentTasksController implements TaskStackListenerCallback,
}
/**
- * Represents a desk whose ID is `mDeskId` and contains the tasks in `mDeskTasks`. Some of these
- * tasks are minimized and their IDs are contained in the `mMinimizedDeskTasks` set.
+ * Represents a desk whose ID is `mDeskId` inside the display with `mDisplayId` and contains
+ * the tasks in `mDeskTasks`. Some of these tasks are minimized and their IDs are contained
+ * in the `mMinimizedDeskTasks` set.
*/
private static class Desk {
final int mDeskId;
+ final int mDisplayId;
boolean mHasVisibleTasks = false;
final ArrayList<TaskInfo> mDeskTasks = new ArrayList<>();
final Set<Integer> mMinimizedDeskTasks = new HashSet<>();
- Desk(int deskId) {
+ Desk(int deskId, int displayId) {
mDeskId = deskId;
+ mDisplayId = displayId;
}
void addTask(TaskInfo taskInfo, boolean isMinimized, boolean isVisible) {
@@ -562,7 +565,8 @@ public class RecentTasksController implements TaskStackListenerCallback,
}
GroupedTaskInfo createDeskTaskInfo() {
- return GroupedTaskInfo.forDeskTasks(mDeskId, mDeskTasks, mMinimizedDeskTasks);
+ return GroupedTaskInfo.forDeskTasks(mDeskId, mDisplayId, mDeskTasks,
+ mMinimizedDeskTasks);
}
}
@@ -601,7 +605,8 @@ public class RecentTasksController implements TaskStackListenerCallback,
private Desk getOrCreateDesk(int deskId) {
var desk = mTmpDesks.get(deskId);
if (desk == null) {
- desk = new Desk(deskId);
+ desk = new Desk(deskId,
+ mDesktopUserRepositories.get().getCurrent().getDisplayForDesk(deskId));
mTmpDesks.put(deskId, desk);
}
return desk;
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/CaptionWindowDecoration.java b/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/CaptionWindowDecoration.java
index 5e8c1fe2aa8d..e08ef5883390 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/CaptionWindowDecoration.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/CaptionWindowDecoration.java
@@ -49,6 +49,7 @@ import android.view.ViewConfiguration;
import android.view.WindowInsets;
import android.view.WindowManager;
import android.view.WindowManagerGlobal;
+import android.window.DesktopExperienceFlags;
import android.window.DesktopModeFlags;
import android.window.WindowContainerTransaction;
@@ -218,11 +219,17 @@ public class CaptionWindowDecoration extends WindowDecoration<WindowDecorLinearL
relayoutParams.mRunningTaskInfo = taskInfo;
relayoutParams.mLayoutResId = R.layout.caption_window_decor;
relayoutParams.mCaptionHeightId = getCaptionHeightIdStatic(taskInfo.getWindowingMode());
- relayoutParams.mShadowRadius = hasGlobalFocus
- ? context.getResources().getDimensionPixelSize(
- R.dimen.freeform_decor_shadow_focused_thickness)
- : context.getResources().getDimensionPixelSize(
- R.dimen.freeform_decor_shadow_unfocused_thickness);
+ if (DesktopExperienceFlags.ENABLE_DYNAMIC_RADIUS_COMPUTATION_BUGFIX.isTrue()) {
+ relayoutParams.mShadowRadiusId = hasGlobalFocus
+ ? R.dimen.freeform_decor_shadow_focused_thickness
+ : R.dimen.freeform_decor_shadow_unfocused_thickness;
+ } else {
+ relayoutParams.mShadowRadius = hasGlobalFocus
+ ? context.getResources().getDimensionPixelSize(
+ R.dimen.freeform_decor_shadow_focused_thickness)
+ : context.getResources().getDimensionPixelSize(
+ R.dimen.freeform_decor_shadow_unfocused_thickness);
+ }
relayoutParams.mApplyStartTransactionOnDraw = applyStartTransactionOnDraw;
relayoutParams.mSetTaskVisibilityPositionAndCrop = shouldSetTaskVisibilityPositionAndCrop;
relayoutParams.mIsCaptionVisible = taskInfo.isFreeform()
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/DesktopModeWindowDecoration.java b/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/DesktopModeWindowDecoration.java
index 989550c60c0d..e8019e47e374 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/DesktopModeWindowDecoration.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/DesktopModeWindowDecoration.java
@@ -72,6 +72,7 @@ import android.view.WindowInsets;
import android.view.WindowManager;
import android.view.WindowManagerGlobal;
import android.widget.ImageButton;
+import android.window.DesktopExperienceFlags;
import android.window.DesktopModeFlags;
import android.window.TaskSnapshot;
import android.window.WindowContainerTransaction;
@@ -719,7 +720,8 @@ public class DesktopModeWindowDecoration extends WindowDecoration<WindowDecorLin
.getScaledTouchSlop();
final Resources res = mResult.mRootView.getResources();
final DragResizeWindowGeometry newGeometry = new DragResizeWindowGeometry(
- mRelayoutParams.mCornerRadius,
+ DesktopExperienceFlags.ENABLE_DYNAMIC_RADIUS_COMPUTATION_BUGFIX.isTrue()
+ ? mResult.mCornerRadius : mRelayoutParams.mCornerRadius,
new Size(mResult.mWidth, mResult.mHeight),
getResizeEdgeHandleSize(res), getResizeHandleEdgeInset(res),
getFineResizeCornerSize(res), getLargeResizeCornerSize(res),
@@ -1072,13 +1074,23 @@ public class DesktopModeWindowDecoration extends WindowDecoration<WindowDecorLin
}
if (isAppHeader
&& DesktopModeStatus.useWindowShadow(/* isFocusedWindow= */ hasGlobalFocus)) {
- relayoutParams.mShadowRadius = hasGlobalFocus
- ? context.getResources().getDimensionPixelSize(
- R.dimen.freeform_decor_shadow_focused_thickness)
- : context.getResources().getDimensionPixelSize(
- R.dimen.freeform_decor_shadow_unfocused_thickness);
+ if (DesktopExperienceFlags.ENABLE_DYNAMIC_RADIUS_COMPUTATION_BUGFIX.isTrue()) {
+ relayoutParams.mShadowRadiusId = hasGlobalFocus
+ ? R.dimen.freeform_decor_shadow_focused_thickness
+ : R.dimen.freeform_decor_shadow_unfocused_thickness;
+ } else {
+ relayoutParams.mShadowRadius = hasGlobalFocus
+ ? context.getResources().getDimensionPixelSize(
+ R.dimen.freeform_decor_shadow_focused_thickness)
+ : context.getResources().getDimensionPixelSize(
+ R.dimen.freeform_decor_shadow_unfocused_thickness);
+ }
} else {
- relayoutParams.mShadowRadius = INVALID_SHADOW_RADIUS;
+ if (DesktopExperienceFlags.ENABLE_DYNAMIC_RADIUS_COMPUTATION_BUGFIX.isTrue()) {
+ relayoutParams.mShadowRadiusId = Resources.ID_NULL;
+ } else {
+ relayoutParams.mShadowRadius = INVALID_SHADOW_RADIUS;
+ }
}
relayoutParams.mApplyStartTransactionOnDraw = applyStartTransactionOnDraw;
relayoutParams.mSetTaskVisibilityPositionAndCrop = shouldSetTaskVisibilityPositionAndCrop;
@@ -1104,8 +1116,13 @@ public class DesktopModeWindowDecoration extends WindowDecoration<WindowDecorLin
relayoutParams.mWindowDecorConfig = windowDecorConfig;
if (DesktopModeStatus.useRoundedCorners()) {
- relayoutParams.mCornerRadius = shouldIgnoreCornerRadius ? INVALID_CORNER_RADIUS :
- getCornerRadius(context, relayoutParams.mLayoutResId);
+ if (DesktopExperienceFlags.ENABLE_DYNAMIC_RADIUS_COMPUTATION_BUGFIX.isTrue()) {
+ relayoutParams.mCornerRadiusId = shouldIgnoreCornerRadius ? Resources.ID_NULL :
+ getCornerRadiusId(relayoutParams.mLayoutResId);
+ } else {
+ relayoutParams.mCornerRadius = shouldIgnoreCornerRadius ? INVALID_CORNER_RADIUS :
+ getCornerRadius(context, relayoutParams.mLayoutResId);
+ }
}
// Set opaque background for all freeform tasks to prevent freeform tasks below
// from being visible if freeform task window above is translucent.
@@ -1113,6 +1130,7 @@ public class DesktopModeWindowDecoration extends WindowDecoration<WindowDecorLin
relayoutParams.mShouldSetBackground = DesktopModeStatus.shouldSetBackground(taskInfo);
}
+ @Deprecated
private static int getCornerRadius(@NonNull Context context, int layoutResId) {
if (layoutResId == R.layout.desktop_mode_app_header) {
return loadDimensionPixelSize(context.getResources(),
@@ -1122,6 +1140,14 @@ public class DesktopModeWindowDecoration extends WindowDecoration<WindowDecorLin
return INVALID_CORNER_RADIUS;
}
+ private static int getCornerRadiusId(int layoutResId) {
+ if (layoutResId == R.layout.desktop_mode_app_header) {
+ return com.android.wm.shell.shared.R.dimen
+ .desktop_windowing_freeform_rounded_corner_radius;
+ }
+ return Resources.ID_NULL;
+ }
+
/**
* If task has focused window decor, return the caption id of the fullscreen caption size
* resource. Otherwise, return ID_NULL and caption width be set to task width.
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/MultiDisplayVeiledResizeTaskPositioner.kt b/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/MultiDisplayVeiledResizeTaskPositioner.kt
index eb324f74ca82..238242792782 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/MultiDisplayVeiledResizeTaskPositioner.kt
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/MultiDisplayVeiledResizeTaskPositioner.kt
@@ -278,13 +278,16 @@ class MultiDisplayVeiledResizeTaskPositioner(
currentDisplayLayout,
)
)
-
- multiDisplayDragMoveIndicatorController.onDragEnd(
- desktopWindowDecoration.mTaskInfo.taskId,
- transactionSupplier,
- )
}
+ // Call the MultiDisplayDragMoveIndicatorController to clear any active indicator
+ // surfaces. This is necessary even if the drag ended on the same display, as surfaces
+ // may have been created for other displays during the drag.
+ multiDisplayDragMoveIndicatorController.onDragEnd(
+ desktopWindowDecoration.mTaskInfo.taskId,
+ transactionSupplier,
+ )
+
interactionJankMonitor.end(Cuj.CUJ_DESKTOP_MODE_DRAG_WINDOW)
}
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/WindowDecoration.java b/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/WindowDecoration.java
index 91a899c09407..6fd963f4203d 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/WindowDecoration.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/WindowDecoration.java
@@ -47,6 +47,7 @@ import android.view.SurfaceControlViewHost;
import android.view.View;
import android.view.WindowManager;
import android.view.WindowlessWindowManager;
+import android.window.DesktopExperienceFlags;
import android.window.SurfaceSyncGroup;
import android.window.TaskConstants;
import android.window.WindowContainerToken;
@@ -286,6 +287,14 @@ public abstract class WindowDecoration<T extends View & TaskFocusStateConsumer>
outResult.mCaptionX = (outResult.mWidth - outResult.mCaptionWidth) / 2;
outResult.mCaptionY = 0;
outResult.mCaptionTopPadding = params.mCaptionTopPadding;
+ if (DesktopExperienceFlags.ENABLE_DYNAMIC_RADIUS_COMPUTATION_BUGFIX.isTrue()) {
+ outResult.mCornerRadius = params.mCornerRadiusId == Resources.ID_NULL
+ ? INVALID_CORNER_RADIUS : loadDimensionPixelSize(resources,
+ params.mCornerRadiusId);
+ outResult.mShadowRadius = params.mShadowRadiusId == Resources.ID_NULL
+ ? INVALID_SHADOW_RADIUS : loadDimensionPixelSize(resources,
+ params.mShadowRadiusId);
+ }
Trace.beginSection("relayout-createViewHostIfNeeded");
createViewHostIfNeeded(mDecorWindowContext, mDisplay);
@@ -497,9 +506,16 @@ public abstract class WindowDecoration<T extends View & TaskFocusStateConsumer>
.setPosition(mTaskSurface, taskPosition.x, taskPosition.y);
}
- if (params.mShadowRadius != INVALID_SHADOW_RADIUS) {
- startT.setShadowRadius(mTaskSurface, params.mShadowRadius);
- finishT.setShadowRadius(mTaskSurface, params.mShadowRadius);
+ if (DesktopExperienceFlags.ENABLE_DYNAMIC_RADIUS_COMPUTATION_BUGFIX.isTrue()) {
+ if (outResult.mShadowRadius != INVALID_SHADOW_RADIUS) {
+ startT.setShadowRadius(mTaskSurface, outResult.mShadowRadius);
+ finishT.setShadowRadius(mTaskSurface, outResult.mShadowRadius);
+ }
+ } else {
+ if (params.mShadowRadius != INVALID_SHADOW_RADIUS) {
+ startT.setShadowRadius(mTaskSurface, params.mShadowRadius);
+ finishT.setShadowRadius(mTaskSurface, params.mShadowRadius);
+ }
}
if (params.mSetTaskVisibilityPositionAndCrop) {
@@ -517,9 +533,16 @@ public abstract class WindowDecoration<T extends View & TaskFocusStateConsumer>
startT.unsetColor(mTaskSurface);
}
- if (params.mCornerRadius != INVALID_CORNER_RADIUS) {
- startT.setCornerRadius(mTaskSurface, params.mCornerRadius);
- finishT.setCornerRadius(mTaskSurface, params.mCornerRadius);
+ if (DesktopExperienceFlags.ENABLE_DYNAMIC_RADIUS_COMPUTATION_BUGFIX.isTrue()) {
+ if (outResult.mCornerRadius != INVALID_CORNER_RADIUS) {
+ startT.setCornerRadius(mTaskSurface, outResult.mCornerRadius);
+ finishT.setCornerRadius(mTaskSurface, outResult.mCornerRadius);
+ }
+ } else {
+ if (params.mCornerRadius != INVALID_CORNER_RADIUS) {
+ startT.setCornerRadius(mTaskSurface, params.mCornerRadius);
+ finishT.setCornerRadius(mTaskSurface, params.mCornerRadius);
+ }
}
}
@@ -824,9 +847,14 @@ public abstract class WindowDecoration<T extends View & TaskFocusStateConsumer>
@InsetsSource.Flags int mInsetSourceFlags;
final Region mDisplayExclusionRegion = Region.obtain();
+ @Deprecated
int mShadowRadius = INVALID_SHADOW_RADIUS;
+ @Deprecated
int mCornerRadius = INVALID_CORNER_RADIUS;
+ int mShadowRadiusId = Resources.ID_NULL;
+ int mCornerRadiusId = Resources.ID_NULL;
+
int mCaptionTopPadding;
boolean mIsCaptionVisible;
@@ -849,9 +877,13 @@ public abstract class WindowDecoration<T extends View & TaskFocusStateConsumer>
mIsInsetSource = true;
mInsetSourceFlags = 0;
mDisplayExclusionRegion.setEmpty();
-
- mShadowRadius = INVALID_SHADOW_RADIUS;
- mCornerRadius = INVALID_SHADOW_RADIUS;
+ if (DesktopExperienceFlags.ENABLE_DYNAMIC_RADIUS_COMPUTATION_BUGFIX.isTrue()) {
+ mShadowRadiusId = Resources.ID_NULL;
+ mCornerRadiusId = Resources.ID_NULL;
+ } else {
+ mShadowRadius = INVALID_SHADOW_RADIUS;
+ mCornerRadius = INVALID_SHADOW_RADIUS;
+ }
mCaptionTopPadding = 0;
mIsCaptionVisible = false;
@@ -893,6 +925,8 @@ public abstract class WindowDecoration<T extends View & TaskFocusStateConsumer>
int mWidth;
int mHeight;
T mRootView;
+ int mCornerRadius;
+ int mShadowRadius;
void reset() {
mWidth = 0;
@@ -904,6 +938,10 @@ public abstract class WindowDecoration<T extends View & TaskFocusStateConsumer>
mCaptionTopPadding = 0;
mCustomizableCaptionRegion.setEmpty();
mRootView = null;
+ if (DesktopExperienceFlags.ENABLE_DYNAMIC_RADIUS_COMPUTATION_BUGFIX.isTrue()) {
+ mCornerRadius = INVALID_CORNER_RADIUS;
+ mShadowRadius = INVALID_SHADOW_RADIUS;
+ }
}
}
diff --git a/libs/WindowManager/Shell/tests/unittest/res/values/dimen.xml b/libs/WindowManager/Shell/tests/unittest/res/values/dimen.xml
index aa1b24189274..33ea0baa4f6d 100644
--- a/libs/WindowManager/Shell/tests/unittest/res/values/dimen.xml
+++ b/libs/WindowManager/Shell/tests/unittest/res/values/dimen.xml
@@ -18,6 +18,8 @@
<!-- Resources used in WindowDecorationTests -->
<dimen name="test_freeform_decor_caption_height">32dp</dimen>
<dimen name="test_freeform_decor_caption_menu_width">216dp</dimen>
+ <dimen name="test_freeform_shadow_radius">20dp</dimen>
+ <dimen name="test_freeform_corner_radius">16dp</dimen>
<dimen name="test_window_decor_left_outset">10dp</dimen>
<dimen name="test_window_decor_top_outset">20dp</dimen>
<dimen name="test_window_decor_right_outset">30dp</dimen>
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/recents/GroupedTaskInfoTest.kt b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/recents/GroupedTaskInfoTest.kt
index 75f6bda4d750..4e8812d34ef4 100644
--- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/recents/GroupedTaskInfoTest.kt
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/recents/GroupedTaskInfoTest.kt
@@ -21,6 +21,7 @@ import android.app.TaskInfo
import android.graphics.Rect
import android.os.Parcel
import android.testing.AndroidTestingRunner
+import android.view.Display.DEFAULT_DISPLAY
import android.window.IWindowContainerToken
import android.window.WindowContainerToken
import androidx.test.filters.SmallTest
@@ -281,7 +282,8 @@ class GroupedTaskInfoTest : ShellTestCase() {
val task2 = createTaskInfo(id = 2)
val taskInfo = GroupedTaskInfo.forDeskTasks(
- /* deskId = */ 500, listOf(task1, task2), setOf())
+ /* deskId = */ 500, DEFAULT_DISPLAY, listOf(task1, task2), setOf()
+ )
assertThat(taskInfo.deskId).isEqualTo(500)
assertThat(taskInfo.getTaskById(1)).isEqualTo(task1)
@@ -335,6 +337,7 @@ class GroupedTaskInfoTest : ShellTestCase() {
): GroupedTaskInfo {
return GroupedTaskInfo.forDeskTasks(
deskId,
+ DEFAULT_DISPLAY,
freeformTaskIds.map { createTaskInfo(it) }.toList(),
minimizedTaskIds.toSet())
}
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/windowdecor/DesktopModeWindowDecorationTests.java b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/windowdecor/DesktopModeWindowDecorationTests.java
index f37f2fb14bea..f7b9c3352dea 100644
--- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/windowdecor/DesktopModeWindowDecorationTests.java
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/windowdecor/DesktopModeWindowDecorationTests.java
@@ -59,6 +59,7 @@ import android.content.pm.ActivityInfo;
import android.content.pm.ApplicationInfo;
import android.content.pm.PackageManager;
import android.content.pm.ResolveInfo;
+import android.content.res.Resources;
import android.content.res.TypedArray;
import android.graphics.Point;
import android.graphics.Rect;
@@ -341,7 +342,8 @@ public class DesktopModeWindowDecorationTests extends ShellTestCase {
}
@Test
- public void updateRelayoutParams_noSysPropFlagsSet_windowShadowsAreSetForFreeform() {
+ @DisableFlags(Flags.FLAG_ENABLE_DYNAMIC_RADIUS_COMPUTATION_BUGFIX)
+ public void updateRelayoutParams_noSysPropFlagsSet_windowShadowsAreSetForFreeform_dynamicDisabled() {
final ActivityManager.RunningTaskInfo taskInfo = createTaskInfo(/* visible= */ true);
taskInfo.configuration.windowConfiguration.setWindowingMode(WINDOWING_MODE_FREEFORM);
RelayoutParams relayoutParams = new RelayoutParams();
@@ -353,7 +355,8 @@ public class DesktopModeWindowDecorationTests extends ShellTestCase {
}
@Test
- public void updateRelayoutParams_noSysPropFlagsSet_windowShadowsAreNotSetForFullscreen() {
+ @DisableFlags(Flags.FLAG_ENABLE_DYNAMIC_RADIUS_COMPUTATION_BUGFIX)
+ public void updateRelayoutParams_noSysPropFlagsSet_windowShadowsAreNotSetForFullscreen_dynamicDisabled() {
final ActivityManager.RunningTaskInfo taskInfo = createTaskInfo(/* visible= */ true);
taskInfo.configuration.windowConfiguration.setWindowingMode(WINDOWING_MODE_FULLSCREEN);
RelayoutParams relayoutParams = new RelayoutParams();
@@ -364,7 +367,8 @@ public class DesktopModeWindowDecorationTests extends ShellTestCase {
}
@Test
- public void updateRelayoutParams_noSysPropFlagsSet_windowShadowsAreNotSetForSplit() {
+ @DisableFlags(Flags.FLAG_ENABLE_DYNAMIC_RADIUS_COMPUTATION_BUGFIX)
+ public void updateRelayoutParams_noSysPropFlagsSet_windowShadowsAreNotSetForSplit_dynamicDisabled() {
final ActivityManager.RunningTaskInfo taskInfo = createTaskInfo(/* visible= */ true);
taskInfo.configuration.windowConfiguration.setWindowingMode(WINDOWING_MODE_MULTI_WINDOW);
RelayoutParams relayoutParams = new RelayoutParams();
@@ -375,7 +379,8 @@ public class DesktopModeWindowDecorationTests extends ShellTestCase {
}
@Test
- public void updateRelayoutParams_noSysPropFlagsSet_roundedCornersSetForFreeform() {
+ @DisableFlags(Flags.FLAG_ENABLE_DYNAMIC_RADIUS_COMPUTATION_BUGFIX)
+ public void updateRelayoutParams_noSysPropFlagsSet_roundedCornersSetForFreeform_dynamicDisabled() {
final ActivityManager.RunningTaskInfo taskInfo = createTaskInfo(/* visible= */ true);
taskInfo.configuration.windowConfiguration.setWindowingMode(WINDOWING_MODE_FREEFORM);
fillRoundedCornersResources(/* fillValue= */ 30);
@@ -387,7 +392,8 @@ public class DesktopModeWindowDecorationTests extends ShellTestCase {
}
@Test
- public void updateRelayoutParams_noSysPropFlagsSet_roundedCornersNotSetForFullscreen() {
+ @DisableFlags(Flags.FLAG_ENABLE_DYNAMIC_RADIUS_COMPUTATION_BUGFIX)
+ public void updateRelayoutParams_noSysPropFlagsSet_roundedCornersNotSetForFullscreen_dynamicDisabled() {
final ActivityManager.RunningTaskInfo taskInfo = createTaskInfo(/* visible= */ true);
taskInfo.configuration.windowConfiguration.setWindowingMode(WINDOWING_MODE_FULLSCREEN);
fillRoundedCornersResources(/* fillValue= */ 30);
@@ -399,7 +405,8 @@ public class DesktopModeWindowDecorationTests extends ShellTestCase {
}
@Test
- public void updateRelayoutParams_noSysPropFlagsSet_roundedCornersNotSetForSplit() {
+ @DisableFlags(Flags.FLAG_ENABLE_DYNAMIC_RADIUS_COMPUTATION_BUGFIX)
+ public void updateRelayoutParams_noSysPropFlagsSet_roundedCornersNotSetForSplit_dynamicDisabled() {
final ActivityManager.RunningTaskInfo taskInfo = createTaskInfo(/* visible= */ true);
taskInfo.configuration.windowConfiguration.setWindowingMode(WINDOWING_MODE_MULTI_WINDOW);
fillRoundedCornersResources(/* fillValue= */ 30);
@@ -411,7 +418,8 @@ public class DesktopModeWindowDecorationTests extends ShellTestCase {
}
@Test
- public void updateRelayoutParams_shouldIgnoreCornerRadius_roundedCornersNotSet() {
+ @DisableFlags(Flags.FLAG_ENABLE_DYNAMIC_RADIUS_COMPUTATION_BUGFIX)
+ public void updateRelayoutParams_shouldIgnoreCornerRadius_roundedCornersNotSet_dynamicDisabled() {
final ActivityManager.RunningTaskInfo taskInfo = createTaskInfo(/* visible= */ true);
taskInfo.configuration.windowConfiguration.setWindowingMode(WINDOWING_MODE_FREEFORM);
fillRoundedCornersResources(/* fillValue= */ 30);
@@ -440,6 +448,107 @@ public class DesktopModeWindowDecorationTests extends ShellTestCase {
}
@Test
+ @EnableFlags(Flags.FLAG_ENABLE_DYNAMIC_RADIUS_COMPUTATION_BUGFIX)
+ public void updateRelayoutParams_noSysPropFlagsSet_windowShadowsAreSetForFreeform() {
+ final ActivityManager.RunningTaskInfo taskInfo = createTaskInfo(/* visible= */ true);
+ taskInfo.configuration.windowConfiguration.setWindowingMode(WINDOWING_MODE_FREEFORM);
+ RelayoutParams relayoutParams = new RelayoutParams();
+
+ updateRelayoutParams(relayoutParams, taskInfo);
+
+ assertThat(relayoutParams.mShadowRadiusId).isNotEqualTo(Resources.ID_NULL);
+ }
+
+ @Test
+ @EnableFlags(Flags.FLAG_ENABLE_DYNAMIC_RADIUS_COMPUTATION_BUGFIX)
+ public void updateRelayoutParams_noSysPropFlagsSet_windowShadowsAreNotSetForFullscreen() {
+ final ActivityManager.RunningTaskInfo taskInfo = createTaskInfo(/* visible= */ true);
+ taskInfo.configuration.windowConfiguration.setWindowingMode(WINDOWING_MODE_FULLSCREEN);
+ RelayoutParams relayoutParams = new RelayoutParams();
+
+ updateRelayoutParams(relayoutParams, taskInfo);
+
+ assertThat(relayoutParams.mShadowRadiusId).isEqualTo(Resources.ID_NULL);
+ }
+
+ @Test
+ @EnableFlags(Flags.FLAG_ENABLE_DYNAMIC_RADIUS_COMPUTATION_BUGFIX)
+ public void updateRelayoutParams_noSysPropFlagsSet_windowShadowsAreNotSetForSplit() {
+ final ActivityManager.RunningTaskInfo taskInfo = createTaskInfo(/* visible= */ true);
+ taskInfo.configuration.windowConfiguration.setWindowingMode(WINDOWING_MODE_MULTI_WINDOW);
+ RelayoutParams relayoutParams = new RelayoutParams();
+
+ updateRelayoutParams(relayoutParams, taskInfo);
+
+ assertThat(relayoutParams.mShadowRadiusId).isEqualTo(Resources.ID_NULL);
+ }
+
+ @Test
+ @EnableFlags(Flags.FLAG_ENABLE_DYNAMIC_RADIUS_COMPUTATION_BUGFIX)
+ public void updateRelayoutParams_noSysPropFlagsSet_roundedCornersSetForFreeform() {
+ final ActivityManager.RunningTaskInfo taskInfo = createTaskInfo(/* visible= */ true);
+ taskInfo.configuration.windowConfiguration.setWindowingMode(WINDOWING_MODE_FREEFORM);
+ RelayoutParams relayoutParams = new RelayoutParams();
+
+ updateRelayoutParams(relayoutParams, taskInfo);
+
+ assertThat(relayoutParams.mShadowRadiusId).isNotEqualTo(Resources.ID_NULL);
+ }
+
+ @Test
+ @EnableFlags(Flags.FLAG_ENABLE_DYNAMIC_RADIUS_COMPUTATION_BUGFIX)
+ public void updateRelayoutParams_noSysPropFlagsSet_roundedCornersNotSetForFullscreen() {
+ final ActivityManager.RunningTaskInfo taskInfo = createTaskInfo(/* visible= */ true);
+ taskInfo.configuration.windowConfiguration.setWindowingMode(WINDOWING_MODE_FULLSCREEN);
+ RelayoutParams relayoutParams = new RelayoutParams();
+
+ updateRelayoutParams(relayoutParams, taskInfo);
+
+ assertThat(relayoutParams.mCornerRadiusId).isEqualTo(Resources.ID_NULL);
+ }
+
+ @Test
+ @EnableFlags(Flags.FLAG_ENABLE_DYNAMIC_RADIUS_COMPUTATION_BUGFIX)
+ public void updateRelayoutParams_noSysPropFlagsSet_roundedCornersNotSetForSplit() {
+ final ActivityManager.RunningTaskInfo taskInfo = createTaskInfo(/* visible= */ true);
+ taskInfo.configuration.windowConfiguration.setWindowingMode(WINDOWING_MODE_MULTI_WINDOW);
+ RelayoutParams relayoutParams = new RelayoutParams();
+
+ updateRelayoutParams(relayoutParams, taskInfo);
+
+ assertThat(relayoutParams.mCornerRadiusId).isEqualTo(Resources.ID_NULL);
+ }
+
+ @Test
+ @EnableFlags(Flags.FLAG_ENABLE_DYNAMIC_RADIUS_COMPUTATION_BUGFIX)
+ public void updateRelayoutParams_shouldIgnoreCornerRadius_roundedCornersNotSet() {
+ final ActivityManager.RunningTaskInfo taskInfo = createTaskInfo(/* visible= */ true);
+ taskInfo.configuration.windowConfiguration.setWindowingMode(WINDOWING_MODE_FREEFORM);
+ RelayoutParams relayoutParams = new RelayoutParams();
+
+ DesktopModeWindowDecoration.updateRelayoutParams(
+ relayoutParams,
+ mTestableContext,
+ taskInfo,
+ mMockSplitScreenController,
+ DEFAULT_APPLY_START_TRANSACTION_ON_DRAW,
+ DEFAULT_SHOULD_SET_TASK_POSITIONING_AND_CROP,
+ DEFAULT_IS_STATUSBAR_VISIBLE,
+ DEFAULT_IS_KEYGUARD_VISIBLE_AND_OCCLUDED,
+ DEFAULT_IS_IN_FULL_IMMERSIVE_MODE,
+ DEFAULT_IS_DRAGGING,
+ new InsetsState(),
+ DEFAULT_HAS_GLOBAL_FOCUS,
+ mExclusionRegion,
+ /* shouldIgnoreCornerRadius= */ true,
+ DEFAULT_SHOULD_EXCLUDE_CAPTION_FROM_APP_BOUNDS,
+ DEFAULT_IS_RECENTS_TRANSITION_RUNNING,
+ DEFAULT_IS_MOVING_TO_BACK);
+
+ assertThat(relayoutParams.mCornerRadiusId).isEqualTo(Resources.ID_NULL);
+ }
+
+ @Test
@EnableFlags(Flags.FLAG_ENABLE_APP_HEADER_WITH_TASK_DENSITY)
public void updateRelayoutParams_appHeader_usesTaskDensity() {
final int systemDensity = mTestableContext.getOrCreateTestableResources().getResources()
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/windowdecor/MultiDisplayVeiledResizeTaskPositionerTest.kt b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/windowdecor/MultiDisplayVeiledResizeTaskPositionerTest.kt
index 0798613ed632..24a46aacde15 100644
--- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/windowdecor/MultiDisplayVeiledResizeTaskPositionerTest.kt
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/windowdecor/MultiDisplayVeiledResizeTaskPositionerTest.kt
@@ -63,6 +63,7 @@ import org.mockito.Mockito.mock
import org.mockito.Mockito.never
import org.mockito.Mockito.times
import org.mockito.Mockito.verify
+import org.mockito.Mockito.verifyNoInteractions
import org.mockito.Mockito.`when`
import org.mockito.Mockito.`when` as whenever
import org.mockito.MockitoAnnotations
@@ -210,6 +211,7 @@ class MultiDisplayVeiledResizeTaskPositionerTest : ShellTestCase() {
eq(taskPositioner),
)
verify(mockDesktopWindowDecoration, never()).hideResizeVeil()
+ verifyNoInteractions(mockMultiDisplayDragMoveIndicatorController)
}
@Test
@@ -248,6 +250,7 @@ class MultiDisplayVeiledResizeTaskPositionerTest : ShellTestCase() {
verify(mockDesktopWindowDecoration, never()).showResizeVeil(any())
verify(mockDesktopWindowDecoration, never()).hideResizeVeil()
+ verify(mockMultiDisplayDragMoveIndicatorController).onDragEnd(eq(TASK_ID), any())
Assert.assertEquals(rectAfterEnd, endBounds)
}
@@ -268,6 +271,7 @@ class MultiDisplayVeiledResizeTaskPositionerTest : ShellTestCase() {
verify(spyDisplayLayout0, never()).localPxToGlobalDp(any(), any())
verify(spyDisplayLayout0, never()).globalDpToLocalPx(any(), any())
+ verify(mockMultiDisplayDragMoveIndicatorController).onDragEnd(eq(TASK_ID), any())
}
@Test
@@ -290,6 +294,7 @@ class MultiDisplayVeiledResizeTaskPositionerTest : ShellTestCase() {
verify(mockDesktopWindowDecoration, never()).showResizeVeil(any())
verify(mockDesktopWindowDecoration, never()).hideResizeVeil()
+ verify(mockMultiDisplayDragMoveIndicatorController).onDragEnd(eq(TASK_ID), any())
Assert.assertEquals(rectAfterEnd, endBounds)
}
@@ -346,6 +351,7 @@ class MultiDisplayVeiledResizeTaskPositionerTest : ShellTestCase() {
},
eq(taskPositioner),
)
+ verifyNoInteractions(mockMultiDisplayDragMoveIndicatorController)
}
@Test
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/windowdecor/WindowDecorationTests.java b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/windowdecor/WindowDecorationTests.java
index 2e95a979220c..c691dc72b1ea 100644
--- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/windowdecor/WindowDecorationTests.java
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/windowdecor/WindowDecorationTests.java
@@ -61,7 +61,8 @@ import android.graphics.Rect;
import android.graphics.Region;
import android.os.Handler;
import android.os.LocaleList;
-import android.testing.AndroidTestingRunner;
+import android.platform.test.annotations.UsesFlags;
+import android.platform.test.flag.junit.FlagsParameterization;
import android.util.DisplayMetrics;
import android.view.AttachedSurfaceControl;
import android.view.Display;
@@ -78,6 +79,7 @@ import android.window.WindowContainerTransaction;
import androidx.test.filters.SmallTest;
+import com.android.window.flags.Flags;
import com.android.wm.shell.ShellTaskOrganizer;
import com.android.wm.shell.ShellTestCase;
import com.android.wm.shell.TestRunningTaskInfoBuilder;
@@ -96,6 +98,9 @@ import org.mockito.InOrder;
import org.mockito.Mock;
import org.mockito.Mockito;
+import platform.test.runner.parameterized.ParameterizedAndroidJunit4;
+import platform.test.runner.parameterized.Parameters;
+
import java.util.ArrayList;
import java.util.List;
import java.util.Locale;
@@ -108,7 +113,8 @@ import java.util.function.Supplier;
* atest WMShellUnitTests:WindowDecorationTests
*/
@SmallTest
-@RunWith(AndroidTestingRunner.class)
+@RunWith(ParameterizedAndroidJunit4.class)
+@UsesFlags(com.android.window.flags.Flags.class)
public class WindowDecorationTests extends ShellTestCase {
private static final Rect TASK_BOUNDS = new Rect(100, 300, 400, 400);
private static final Point TASK_POSITION_IN_PARENT = new Point(40, 60);
@@ -116,6 +122,12 @@ public class WindowDecorationTests extends ShellTestCase {
private static final int SHADOW_RADIUS = 10;
private static final int STATUS_BAR_INSET_SOURCE_ID = 0;
+ @Parameters(name = "{0}")
+ public static List<FlagsParameterization> getParams() {
+ return FlagsParameterization.allCombinationsOf(
+ Flags.FLAG_ENABLE_DYNAMIC_RADIUS_COMPUTATION_BUGFIX);
+ }
+
private final WindowDecoration.RelayoutResult<TestView> mRelayoutResult =
new WindowDecoration.RelayoutResult<>();
@@ -156,6 +168,10 @@ public class WindowDecorationTests extends ShellTestCase {
private WindowDecoration.RelayoutParams mRelayoutParams = new WindowDecoration.RelayoutParams();
private int mCaptionMenuWidthId;
+ public WindowDecorationTests(FlagsParameterization flags) {
+ mSetFlagsRule.setFlagsParameterization(flags);
+ }
+
@Before
public void setUp() {
mMockSurfaceControlStartT = createMockSurfaceControlTransaction();
@@ -165,8 +181,13 @@ public class WindowDecorationTests extends ShellTestCase {
mRelayoutParams.mLayoutResId = 0;
mRelayoutParams.mCaptionHeightId = R.dimen.test_freeform_decor_caption_height;
mCaptionMenuWidthId = R.dimen.test_freeform_decor_caption_menu_width;
- mRelayoutParams.mShadowRadius = SHADOW_RADIUS;
- mRelayoutParams.mCornerRadius = CORNER_RADIUS;
+ if (Flags.enableDynamicRadiusComputationBugfix()) {
+ mRelayoutParams.mShadowRadiusId = R.dimen.test_freeform_shadow_radius;
+ mRelayoutParams.mCornerRadiusId = R.dimen.test_freeform_corner_radius;
+ } else {
+ mRelayoutParams.mShadowRadius = SHADOW_RADIUS;
+ mRelayoutParams.mCornerRadius = CORNER_RADIUS;
+ }
when(mMockDisplayController.getDisplay(Display.DEFAULT_DISPLAY))
.thenReturn(mock(Display.class));
@@ -282,9 +303,21 @@ public class WindowDecorationTests extends ShellTestCase {
any(),
anyInt());
- verify(mMockSurfaceControlStartT).setCornerRadius(mMockTaskSurface, CORNER_RADIUS);
- verify(mMockSurfaceControlFinishT).setCornerRadius(mMockTaskSurface, CORNER_RADIUS);
- verify(mMockSurfaceControlStartT).setShadowRadius(mMockTaskSurface, SHADOW_RADIUS);
+ if (Flags.enableDynamicRadiusComputationBugfix()) {
+ final int cornerRadius = WindowDecoration.loadDimensionPixelSize(
+ windowDecor.mDecorWindowContext.getResources(),
+ mRelayoutParams.mCornerRadiusId);
+ verify(mMockSurfaceControlStartT).setCornerRadius(mMockTaskSurface, cornerRadius);
+ verify(mMockSurfaceControlFinishT).setCornerRadius(mMockTaskSurface, cornerRadius);
+ final int shadowRadius = WindowDecoration.loadDimensionPixelSize(
+ windowDecor.mDecorWindowContext.getResources(),
+ mRelayoutParams.mShadowRadiusId);
+ verify(mMockSurfaceControlStartT).setShadowRadius(mMockTaskSurface, shadowRadius);
+ } else {
+ verify(mMockSurfaceControlStartT).setCornerRadius(mMockTaskSurface, CORNER_RADIUS);
+ verify(mMockSurfaceControlFinishT).setCornerRadius(mMockTaskSurface, CORNER_RADIUS);
+ verify(mMockSurfaceControlStartT).setShadowRadius(mMockTaskSurface, SHADOW_RADIUS);
+ }
assertEquals(300, mRelayoutResult.mWidth);
assertEquals(100, mRelayoutResult.mHeight);
@@ -1198,7 +1231,8 @@ public class WindowDecorationTests extends ShellTestCase {
}
@Override
- public void setTaskFocusState(boolean focused) {}
+ public void setTaskFocusState(boolean focused) {
+ }
}
private class TestWindowDecoration extends WindowDecoration<TestView> {
diff --git a/libs/hwui/Android.bp b/libs/hwui/Android.bp
index a892e887bd43..ab1be7e6128d 100644
--- a/libs/hwui/Android.bp
+++ b/libs/hwui/Android.bp
@@ -139,6 +139,7 @@ cc_defaults {
"libandroidfw",
"libcrypto",
"libsync",
+ "libgui",
"libui",
"aconfig_text_flags_c_lib",
"aconfig_view_accessibility_flags_c_lib",
diff --git a/libs/hwui/WebViewFunctorManager.cpp b/libs/hwui/WebViewFunctorManager.cpp
index 9d16ee86739e..7e1eb70ca02b 100644
--- a/libs/hwui/WebViewFunctorManager.cpp
+++ b/libs/hwui/WebViewFunctorManager.cpp
@@ -16,6 +16,7 @@
#include "WebViewFunctorManager.h"
+#include <gui/SurfaceComposerClient.h>
#include <log/log.h>
#include <private/hwui/WebViewFunctor.h>
#include <utils/Trace.h>
@@ -43,7 +44,7 @@ public:
static ASurfaceControl* getSurfaceControl() {
ALOG_ASSERT(sCurrentFunctor);
- return sCurrentFunctor->getSurfaceControl();
+ return reinterpret_cast<ASurfaceControl*>(sCurrentFunctor->getSurfaceControl());
}
static void mergeTransaction(ASurfaceTransaction* transaction) {
ALOG_ASSERT(sCurrentFunctor);
@@ -129,12 +130,12 @@ bool WebViewFunctor::prepareRootSurfaceControl() {
renderthread::CanvasContext* activeContext = renderthread::CanvasContext::getActiveContext();
if (!activeContext) return false;
- ASurfaceControl* rootSurfaceControl = activeContext->getSurfaceControl();
+ sp<SurfaceControl> rootSurfaceControl = activeContext->getSurfaceControl();
if (!rootSurfaceControl) return false;
int32_t rgid = activeContext->getSurfaceControlGenerationId();
if (mParentSurfaceControlGenerationId != rgid) {
- reparentSurfaceControl(rootSurfaceControl);
+ reparentSurfaceControl(reinterpret_cast<ASurfaceControl*>(rootSurfaceControl.get()));
mParentSurfaceControlGenerationId = rgid;
}
@@ -210,33 +211,35 @@ void WebViewFunctor::removeOverlays() {
mCallbacks.removeOverlays(mFunctor, mData, currentFunctor.mergeTransaction);
if (mSurfaceControl) {
reparentSurfaceControl(nullptr);
- auto funcs = renderthread::RenderThread::getInstance().getASurfaceControlFunctions();
- funcs.releaseFunc(mSurfaceControl);
mSurfaceControl = nullptr;
}
}
ASurfaceControl* WebViewFunctor::getSurfaceControl() {
ATRACE_NAME("WebViewFunctor::getSurfaceControl");
- if (mSurfaceControl != nullptr) return mSurfaceControl;
+ if (mSurfaceControl != nullptr) {
+ return reinterpret_cast<ASurfaceControl*>(mSurfaceControl.get());
+ }
renderthread::CanvasContext* activeContext = renderthread::CanvasContext::getActiveContext();
LOG_ALWAYS_FATAL_IF(activeContext == nullptr, "Null active canvas context!");
- ASurfaceControl* rootSurfaceControl = activeContext->getSurfaceControl();
+ sp<SurfaceControl> rootSurfaceControl = activeContext->getSurfaceControl();
LOG_ALWAYS_FATAL_IF(rootSurfaceControl == nullptr, "Null root surface control!");
- auto funcs = renderthread::RenderThread::getInstance().getASurfaceControlFunctions();
mParentSurfaceControlGenerationId = activeContext->getSurfaceControlGenerationId();
- mSurfaceControl = funcs.createFunc(rootSurfaceControl, "Webview Overlay SurfaceControl");
- ASurfaceTransaction* transaction = funcs.transactionCreateFunc();
+
+ SurfaceComposerClient* client = rootSurfaceControl->getClient().get();
+ mSurfaceControl = client->createSurface(
+ String8("Webview Overlay SurfaceControl"), 0 /* width */, 0 /* height */,
+ // Format is only relevant for buffer queue layers.
+ PIXEL_FORMAT_UNKNOWN /* format */, ISurfaceComposerClient::eFXSurfaceBufferState,
+ rootSurfaceControl->getHandle());
+
activeContext->prepareSurfaceControlForWebview();
- funcs.transactionSetZOrderFunc(transaction, mSurfaceControl, -1);
- funcs.transactionSetVisibilityFunc(transaction, mSurfaceControl,
- ASURFACE_TRANSACTION_VISIBILITY_SHOW);
- funcs.transactionApplyFunc(transaction);
- funcs.transactionDeleteFunc(transaction);
- return mSurfaceControl;
+ SurfaceComposerClient::Transaction transaction;
+ transaction.setLayer(mSurfaceControl, -1).show(mSurfaceControl).apply();
+ return reinterpret_cast<ASurfaceControl*>(mSurfaceControl.get());
}
void WebViewFunctor::mergeTransaction(ASurfaceTransaction* transaction) {
@@ -249,8 +252,7 @@ void WebViewFunctor::mergeTransaction(ASurfaceTransaction* transaction) {
done = activeContext->mergeTransaction(transaction, mSurfaceControl);
}
if (!done) {
- auto funcs = renderthread::RenderThread::getInstance().getASurfaceControlFunctions();
- funcs.transactionApplyFunc(transaction);
+ reinterpret_cast<SurfaceComposerClient::Transaction*>(transaction)->apply();
}
}
@@ -258,11 +260,10 @@ void WebViewFunctor::reparentSurfaceControl(ASurfaceControl* parent) {
ATRACE_NAME("WebViewFunctor::reparentSurfaceControl");
if (mSurfaceControl == nullptr) return;
- auto funcs = renderthread::RenderThread::getInstance().getASurfaceControlFunctions();
- ASurfaceTransaction* transaction = funcs.transactionCreateFunc();
- funcs.transactionReparentFunc(transaction, mSurfaceControl, parent);
- mergeTransaction(transaction);
- funcs.transactionDeleteFunc(transaction);
+ SurfaceComposerClient::Transaction transaction;
+ transaction.reparent(mSurfaceControl, sp<SurfaceControl>::fromExisting(
+ reinterpret_cast<SurfaceControl*>(parent)));
+ mergeTransaction(reinterpret_cast<ASurfaceTransaction*>(&transaction));
}
void WebViewFunctor::reportRenderingThreads(const pid_t* thread_ids, size_t size) {
diff --git a/libs/hwui/WebViewFunctorManager.h b/libs/hwui/WebViewFunctorManager.h
index ec17640f9b5e..ac16f9138384 100644
--- a/libs/hwui/WebViewFunctorManager.h
+++ b/libs/hwui/WebViewFunctorManager.h
@@ -25,7 +25,11 @@
#include <mutex>
#include <vector>
-namespace android::uirenderer {
+namespace android {
+
+class SurfaceControl;
+
+namespace uirenderer {
class WebViewFunctorManager;
@@ -100,7 +104,9 @@ private:
bool mHasContext = false;
bool mCreatedHandle = false;
int32_t mParentSurfaceControlGenerationId = 0;
- ASurfaceControl* mSurfaceControl = nullptr;
+#ifdef __ANDROID__
+ sp<SurfaceControl> mSurfaceControl = nullptr;
+#endif
std::vector<pid_t> mRenderingThreads;
};
@@ -126,4 +132,5 @@ private:
std::vector<sp<WebViewFunctor::Handle>> mActiveFunctors;
};
-} // namespace android::uirenderer
+} // namespace uirenderer
+} // namespace android
diff --git a/libs/hwui/jni/android_graphics_HardwareRenderer.cpp b/libs/hwui/jni/android_graphics_HardwareRenderer.cpp
index cfec24b17cd4..009974b3c8de 100644
--- a/libs/hwui/jni/android_graphics_HardwareRenderer.cpp
+++ b/libs/hwui/jni/android_graphics_HardwareRenderer.cpp
@@ -53,6 +53,7 @@
#include <src/image/SkImage_Base.h>
#include <thread/CommonPool.h>
#ifdef __ANDROID__
+#include <gui/SurfaceControl.h>
#include <ui/GraphicBufferAllocator.h>
#endif
#include <utils/Color.h>
@@ -217,9 +218,11 @@ static void android_view_ThreadedRenderer_setSurface(JNIEnv* env, jobject clazz,
static void android_view_ThreadedRenderer_setSurfaceControl(JNIEnv* env, jobject clazz,
jlong proxyPtr, jlong surfaceControlPtr) {
+#ifdef __ANDROID__
RenderProxy* proxy = reinterpret_cast<RenderProxy*>(proxyPtr);
- ASurfaceControl* surfaceControl = reinterpret_cast<ASurfaceControl*>(surfaceControlPtr);
- proxy->setSurfaceControl(surfaceControl);
+ SurfaceControl* surfaceControl = reinterpret_cast<SurfaceControl*>(surfaceControlPtr);
+ proxy->setSurfaceControl(sp<SurfaceControl>::fromExisting(surfaceControl));
+#endif
}
static jboolean android_view_ThreadedRenderer_pause(JNIEnv* env, jobject clazz,
@@ -684,7 +687,7 @@ static void android_view_ThreadedRenderer_setFrameCompleteCallback(JNIEnv* env,
class CopyRequestAdapter : public CopyRequest {
public:
- CopyRequestAdapter(JavaVM* vm, jobject jCopyRequest, Rect srcRect)
+ CopyRequestAdapter(JavaVM* vm, jobject jCopyRequest, ::android::uirenderer::Rect srcRect)
: CopyRequest(srcRect), mRefHolder(vm, jCopyRequest) {}
virtual SkBitmap getDestinationBitmap(int srcWidth, int srcHeight) override {
@@ -710,8 +713,9 @@ static void android_view_ThreadedRenderer_copySurfaceInto(JNIEnv* env, jobject c
jobject jCopyRequest) {
JavaVM* vm = nullptr;
LOG_ALWAYS_FATAL_IF(env->GetJavaVM(&vm) != JNI_OK, "Unable to get Java VM");
- auto copyRequest = std::make_shared<CopyRequestAdapter>(vm, env->NewGlobalRef(jCopyRequest),
- Rect(left, top, right, bottom));
+ auto copyRequest = std::make_shared<CopyRequestAdapter>(
+ vm, env->NewGlobalRef(jCopyRequest),
+ ::android::uirenderer::Rect(left, top, right, bottom));
ANativeWindow* window = fromSurface(env, jsurface);
RenderProxy::copySurfaceInto(window, std::move(copyRequest));
ANativeWindow_release(window);
diff --git a/libs/hwui/platform/host/WebViewFunctorManager.cpp b/libs/hwui/platform/host/WebViewFunctorManager.cpp
index 4ba206b41b39..66646b2da2ef 100644
--- a/libs/hwui/platform/host/WebViewFunctorManager.cpp
+++ b/libs/hwui/platform/host/WebViewFunctorManager.cpp
@@ -45,7 +45,7 @@ void WebViewFunctor::destroyContext() {}
void WebViewFunctor::removeOverlays() {}
ASurfaceControl* WebViewFunctor::getSurfaceControl() {
- return mSurfaceControl;
+ return nullptr;
}
void WebViewFunctor::mergeTransaction(ASurfaceTransaction* transaction) {}
diff --git a/libs/hwui/platform/host/renderthread/RenderThread.cpp b/libs/hwui/platform/host/renderthread/RenderThread.cpp
index f9d0f4704e08..ece45304e6d5 100644
--- a/libs/hwui/platform/host/renderthread/RenderThread.cpp
+++ b/libs/hwui/platform/host/renderthread/RenderThread.cpp
@@ -27,8 +27,6 @@ namespace renderthread {
static bool gHasRenderThreadInstance = false;
static JVMAttachHook gOnStartHook = nullptr;
-ASurfaceControlFunctions::ASurfaceControlFunctions() {}
-
bool RenderThread::hasInstance() {
return gHasRenderThreadInstance;
}
diff --git a/libs/hwui/renderthread/CanvasContext.cpp b/libs/hwui/renderthread/CanvasContext.cpp
index b248c4bc9ade..d5ac99389d87 100644
--- a/libs/hwui/renderthread/CanvasContext.cpp
+++ b/libs/hwui/renderthread/CanvasContext.cpp
@@ -18,6 +18,12 @@
#include <apex/window.h>
#include <fcntl.h>
+
+#ifdef __ANDROID__
+#include <gui/ITransactionCompletedListener.h>
+#include <gui/SurfaceComposerClient.h>
+#endif
+
#include <gui/TraceUtils.h>
#include <strings.h>
#include <sys/stat.h>
@@ -165,7 +171,9 @@ void CanvasContext::destroy() {
stopDrawing();
setHardwareBuffer(nullptr);
setSurface(nullptr);
+#ifdef __ANDROID__
setSurfaceControl(nullptr);
+#endif
freePrefetchedLayers();
destroyHardwareResources();
mAnimationContext->destroy();
@@ -220,10 +228,15 @@ void CanvasContext::setSurface(ANativeWindow* window, bool enableTimeout) {
setupPipelineSurface();
}
-void CanvasContext::setSurfaceControl(ASurfaceControl* surfaceControl) {
- if (surfaceControl == mSurfaceControl) return;
+#ifdef __ANDROID__
+sp<SurfaceControl> CanvasContext::getSurfaceControl() const {
+ return mSurfaceControl;
+}
+#endif
- auto funcs = mRenderThread.getASurfaceControlFunctions();
+void CanvasContext::setSurfaceControl(sp<SurfaceControl> surfaceControl) {
+#ifdef __ANDROID__
+ if (surfaceControl == mSurfaceControl) return;
if (surfaceControl == nullptr) {
setASurfaceTransactionCallback(nullptr);
@@ -231,17 +244,23 @@ void CanvasContext::setSurfaceControl(ASurfaceControl* surfaceControl) {
}
if (mSurfaceControl != nullptr) {
- funcs.unregisterListenerFunc(this, &onSurfaceStatsAvailable);
- funcs.releaseFunc(mSurfaceControl);
+ TransactionCompletedListener::getInstance()->removeSurfaceStatsListener(
+ this, reinterpret_cast<void*>(onSurfaceStatsAvailable));
}
- mSurfaceControl = surfaceControl;
+
+ mSurfaceControl = std::move(surfaceControl);
mSurfaceControlGenerationId++;
- mExpectSurfaceStats = surfaceControl != nullptr;
+ mExpectSurfaceStats = mSurfaceControl != nullptr;
if (mExpectSurfaceStats) {
- funcs.acquireFunc(mSurfaceControl);
- funcs.registerListenerFunc(surfaceControl, mSurfaceControlGenerationId, this,
- &onSurfaceStatsAvailable);
+ SurfaceStatsCallback callback = [generationId = mSurfaceControlGenerationId](
+ void* callback_context, nsecs_t, const sp<Fence>&,
+ const SurfaceStats& surfaceStats) {
+ onSurfaceStatsAvailable(callback_context, generationId, surfaceStats);
+ };
+ TransactionCompletedListener::getInstance()->addSurfaceStatsListener(
+ this, reinterpret_cast<void*>(onSurfaceStatsAvailable), mSurfaceControl, callback);
}
+#endif
}
void CanvasContext::setupPipelineSurface() {
@@ -896,17 +915,26 @@ FrameInfo* CanvasContext::getFrameInfoFromLastFew(uint64_t frameNumber, uint32_t
}
void CanvasContext::onSurfaceStatsAvailable(void* context, int32_t surfaceControlId,
- ASurfaceControlStats* stats) {
+ const SurfaceStats& stats) {
+#ifdef __ANDROID__
auto* instance = static_cast<CanvasContext*>(context);
- const ASurfaceControlFunctions& functions =
- instance->mRenderThread.getASurfaceControlFunctions();
+ nsecs_t gpuCompleteTime = -1L;
+ if (const auto* fence = std::get_if<sp<Fence>>(&stats.acquireTimeOrFence)) {
+ // We got a fence instead of the acquire time due to latching unsignaled.
+ // Ideally the client could just get the acquire time directly from
+ // the fence instead of calling this function which needs to block.
+ (*fence)->waitForever("acquireFence");
+ gpuCompleteTime = (*fence)->getSignalTime();
+ } else {
+ gpuCompleteTime = std::get<int64_t>(stats.acquireTimeOrFence);
+ }
- nsecs_t gpuCompleteTime = functions.getAcquireTimeFunc(stats);
if (gpuCompleteTime == Fence::SIGNAL_TIME_PENDING) {
gpuCompleteTime = -1;
}
- uint64_t frameNumber = functions.getFrameNumberFunc(stats);
+
+ uint64_t frameNumber = stats.eventStats.frameNumber;
FrameInfo* frameInfo = instance->getFrameInfoFromLastFew(frameNumber, surfaceControlId);
@@ -919,6 +947,7 @@ void CanvasContext::onSurfaceStatsAvailable(void* context, int32_t surfaceContro
instance->mJankTracker.finishFrame(*frameInfo, instance->mFrameMetricsReporter, frameNumber,
surfaceControlId);
}
+#endif
}
// Called by choreographer to do an RT-driven animation
@@ -1140,10 +1169,11 @@ CanvasContext* CanvasContext::getActiveContext() {
return ScopedActiveContext::getActiveContext();
}
-bool CanvasContext::mergeTransaction(ASurfaceTransaction* transaction, ASurfaceControl* control) {
+bool CanvasContext::mergeTransaction(ASurfaceTransaction* transaction,
+ const sp<SurfaceControl>& control) {
if (!mASurfaceTransactionCallback) return false;
return std::invoke(mASurfaceTransactionCallback, reinterpret_cast<int64_t>(transaction),
- reinterpret_cast<int64_t>(control), getFrameNumber());
+ reinterpret_cast<int64_t>(control.get()), getFrameNumber());
}
void CanvasContext::prepareSurfaceControlForWebview() {
diff --git a/libs/hwui/renderthread/CanvasContext.h b/libs/hwui/renderthread/CanvasContext.h
index 3de8e0516070..655aebada954 100644
--- a/libs/hwui/renderthread/CanvasContext.h
+++ b/libs/hwui/renderthread/CanvasContext.h
@@ -50,6 +50,9 @@
#include "utils/RingBuffer.h"
namespace android {
+
+class SurfaceStats;
+
namespace uirenderer {
class AnimationContext;
@@ -121,7 +124,9 @@ public:
*/
GrDirectContext* getGrContext() const { return mRenderThread.getGrContext(); }
- ASurfaceControl* getSurfaceControl() const { return mSurfaceControl; }
+#ifdef __ANDROID__
+ sp<SurfaceControl> getSurfaceControl() const;
+#endif
int32_t getSurfaceControlGenerationId() const { return mSurfaceControlGenerationId; }
// Won't take effect until next EGLSurface creation
@@ -129,7 +134,7 @@ public:
void setHardwareBuffer(AHardwareBuffer* buffer);
void setSurface(ANativeWindow* window, bool enableTimeout = true);
- void setSurfaceControl(ASurfaceControl* surfaceControl);
+ void setSurfaceControl(sp<SurfaceControl> surfaceControl);
bool pauseSurface();
void setStopped(bool stopped);
bool isStopped() { return mStopped || !hasOutputTarget(); }
@@ -207,7 +212,7 @@ public:
// Called when SurfaceStats are available.
static void onSurfaceStatsAvailable(void* context, int32_t surfaceControlId,
- ASurfaceControlStats* stats);
+ const SurfaceStats& stats);
void setASurfaceTransactionCallback(
const std::function<bool(int64_t, int64_t, int64_t)>& callback) {
@@ -218,7 +223,7 @@ public:
mBufferParams = params;
}
- bool mergeTransaction(ASurfaceTransaction* transaction, ASurfaceControl* control);
+ bool mergeTransaction(ASurfaceTransaction* transaction, const sp<SurfaceControl>& control);
void setPrepareSurfaceControlForWebviewCallback(const std::function<void()>& callback) {
mPrepareSurfaceControlForWebviewCallback = callback;
@@ -286,7 +291,9 @@ private:
std::unique_ptr<ReliableSurface> mNativeSurface;
// The SurfaceControl reference is passed from ViewRootImpl, can be set to
// NULL to remove the reference
- ASurfaceControl* mSurfaceControl = nullptr;
+#ifdef __ANDROID__
+ sp<SurfaceControl> mSurfaceControl = nullptr;
+#endif
// id to track surface control changes and WebViewFunctor uses it to determine
// whether reparenting is needed also used by FrameMetricsReporter to determine
// if a frame is from an "old" surface (i.e. one that existed before the
diff --git a/libs/hwui/renderthread/RenderProxy.cpp b/libs/hwui/renderthread/RenderProxy.cpp
index ebfd8fde91f6..e4be5fa8d39e 100644
--- a/libs/hwui/renderthread/RenderProxy.cpp
+++ b/libs/hwui/renderthread/RenderProxy.cpp
@@ -21,6 +21,11 @@
#include <SkPicture.h>
#include <gui/TraceUtils.h>
#include <pthread.h>
+
+#ifdef __ANDROID__
+#include <gui/SurfaceControl.h>
+#endif
+
#include <ui/GraphicBufferAllocator.h>
#include "DeferredLayerUpdater.h"
@@ -115,17 +120,12 @@ void RenderProxy::setSurface(ANativeWindow* window, bool enableTimeout) {
});
}
-void RenderProxy::setSurfaceControl(ASurfaceControl* surfaceControl) {
- auto funcs = mRenderThread.getASurfaceControlFunctions();
- if (surfaceControl) {
- funcs.acquireFunc(surfaceControl);
- }
- mRenderThread.queue().post([this, control = surfaceControl, funcs]() mutable {
- mContext->setSurfaceControl(control);
- if (control) {
- funcs.releaseFunc(control);
- }
+void RenderProxy::setSurfaceControl(sp<SurfaceControl> surfaceControl) {
+#ifdef __ANDROID__
+ mRenderThread.queue().post([this, control = std::move(surfaceControl)]() mutable {
+ mContext->setSurfaceControl(std::move(control));
});
+#endif
}
void RenderProxy::allocateBuffers() {
diff --git a/libs/hwui/renderthread/RenderProxy.h b/libs/hwui/renderthread/RenderProxy.h
index ad6d54bfcf91..23b3ebd4b360 100644
--- a/libs/hwui/renderthread/RenderProxy.h
+++ b/libs/hwui/renderthread/RenderProxy.h
@@ -20,7 +20,6 @@
#include <SkRefCnt.h>
#include <android/hardware_buffer.h>
#include <android/native_window.h>
-#include <android/surface_control.h>
#include <cutils/compiler.h>
#include <utils/Functor.h>
@@ -39,6 +38,7 @@ class SkImage;
namespace android {
class GraphicBuffer;
+class SurfaceControl;
class Surface;
namespace uirenderer {
@@ -80,7 +80,7 @@ public:
void setName(const char* name);
void setHardwareBuffer(AHardwareBuffer* buffer);
void setSurface(ANativeWindow* window, bool enableTimeout = true);
- void setSurfaceControl(ASurfaceControl* surfaceControl);
+ void setSurfaceControl(sp<SurfaceControl> surfaceControl);
void allocateBuffers();
bool pause();
void setStopped(bool stopped);
diff --git a/libs/hwui/renderthread/RenderThread.cpp b/libs/hwui/renderthread/RenderThread.cpp
index 6ab8e4e0e2ab..5e404247376f 100644
--- a/libs/hwui/renderthread/RenderThread.cpp
+++ b/libs/hwui/renderthread/RenderThread.cpp
@@ -55,66 +55,6 @@ static bool gHasRenderThreadInstance = false;
static JVMAttachHook gOnStartHook = nullptr;
-ASurfaceControlFunctions::ASurfaceControlFunctions() {
- void* handle_ = dlopen("libandroid.so", RTLD_NOW | RTLD_NODELETE);
- createFunc = (ASC_create)dlsym(handle_, "ASurfaceControl_create");
- LOG_ALWAYS_FATAL_IF(createFunc == nullptr,
- "Failed to find required symbol ASurfaceControl_create!");
-
- acquireFunc = (ASC_acquire) dlsym(handle_, "ASurfaceControl_acquire");
- LOG_ALWAYS_FATAL_IF(acquireFunc == nullptr,
- "Failed to find required symbol ASurfaceControl_acquire!");
-
- releaseFunc = (ASC_release) dlsym(handle_, "ASurfaceControl_release");
- LOG_ALWAYS_FATAL_IF(releaseFunc == nullptr,
- "Failed to find required symbol ASurfaceControl_release!");
-
- registerListenerFunc = (ASC_registerSurfaceStatsListener) dlsym(handle_,
- "ASurfaceControl_registerSurfaceStatsListener");
- LOG_ALWAYS_FATAL_IF(registerListenerFunc == nullptr,
- "Failed to find required symbol ASurfaceControl_registerSurfaceStatsListener!");
-
- unregisterListenerFunc = (ASC_unregisterSurfaceStatsListener) dlsym(handle_,
- "ASurfaceControl_unregisterSurfaceStatsListener");
- LOG_ALWAYS_FATAL_IF(unregisterListenerFunc == nullptr,
- "Failed to find required symbol ASurfaceControl_unregisterSurfaceStatsListener!");
-
- getAcquireTimeFunc = (ASCStats_getAcquireTime) dlsym(handle_,
- "ASurfaceControlStats_getAcquireTime");
- LOG_ALWAYS_FATAL_IF(getAcquireTimeFunc == nullptr,
- "Failed to find required symbol ASurfaceControlStats_getAcquireTime!");
-
- getFrameNumberFunc = (ASCStats_getFrameNumber) dlsym(handle_,
- "ASurfaceControlStats_getFrameNumber");
- LOG_ALWAYS_FATAL_IF(getFrameNumberFunc == nullptr,
- "Failed to find required symbol ASurfaceControlStats_getFrameNumber!");
-
- transactionCreateFunc = (AST_create)dlsym(handle_, "ASurfaceTransaction_create");
- LOG_ALWAYS_FATAL_IF(transactionCreateFunc == nullptr,
- "Failed to find required symbol ASurfaceTransaction_create!");
-
- transactionDeleteFunc = (AST_delete)dlsym(handle_, "ASurfaceTransaction_delete");
- LOG_ALWAYS_FATAL_IF(transactionDeleteFunc == nullptr,
- "Failed to find required symbol ASurfaceTransaction_delete!");
-
- transactionApplyFunc = (AST_apply)dlsym(handle_, "ASurfaceTransaction_apply");
- LOG_ALWAYS_FATAL_IF(transactionApplyFunc == nullptr,
- "Failed to find required symbol ASurfaceTransaction_apply!");
-
- transactionReparentFunc = (AST_reparent)dlsym(handle_, "ASurfaceTransaction_reparent");
- LOG_ALWAYS_FATAL_IF(transactionReparentFunc == nullptr,
- "Failed to find required symbol transactionReparentFunc!");
-
- transactionSetVisibilityFunc =
- (AST_setVisibility)dlsym(handle_, "ASurfaceTransaction_setVisibility");
- LOG_ALWAYS_FATAL_IF(transactionSetVisibilityFunc == nullptr,
- "Failed to find required symbol ASurfaceTransaction_setVisibility!");
-
- transactionSetZOrderFunc = (AST_setZOrder)dlsym(handle_, "ASurfaceTransaction_setZOrder");
- LOG_ALWAYS_FATAL_IF(transactionSetZOrderFunc == nullptr,
- "Failed to find required symbol ASurfaceTransaction_setZOrder!");
-}
-
void RenderThread::extendedFrameCallback(const AChoreographerFrameCallbackData* cbData,
void* data) {
RenderThread* rt = reinterpret_cast<RenderThread*>(data);
diff --git a/libs/hwui/renderthread/RenderThread.h b/libs/hwui/renderthread/RenderThread.h
index 86fddbae0831..f733c7c58ef3 100644
--- a/libs/hwui/renderthread/RenderThread.h
+++ b/libs/hwui/renderthread/RenderThread.h
@@ -77,49 +77,6 @@ struct VsyncSource {
virtual ~VsyncSource() {}
};
-typedef ASurfaceControl* (*ASC_create)(ASurfaceControl* parent, const char* debug_name);
-typedef void (*ASC_acquire)(ASurfaceControl* control);
-typedef void (*ASC_release)(ASurfaceControl* control);
-
-typedef void (*ASC_registerSurfaceStatsListener)(ASurfaceControl* control, int32_t id,
- void* context,
- ASurfaceControl_SurfaceStatsListener func);
-typedef void (*ASC_unregisterSurfaceStatsListener)(void* context,
- ASurfaceControl_SurfaceStatsListener func);
-
-typedef int64_t (*ASCStats_getAcquireTime)(ASurfaceControlStats* stats);
-typedef uint64_t (*ASCStats_getFrameNumber)(ASurfaceControlStats* stats);
-
-typedef ASurfaceTransaction* (*AST_create)();
-typedef void (*AST_delete)(ASurfaceTransaction* transaction);
-typedef void (*AST_apply)(ASurfaceTransaction* transaction);
-typedef void (*AST_reparent)(ASurfaceTransaction* aSurfaceTransaction,
- ASurfaceControl* aSurfaceControl,
- ASurfaceControl* newParentASurfaceControl);
-typedef void (*AST_setVisibility)(ASurfaceTransaction* transaction,
- ASurfaceControl* surface_control, int8_t visibility);
-typedef void (*AST_setZOrder)(ASurfaceTransaction* transaction, ASurfaceControl* surface_control,
- int32_t z_order);
-
-struct ASurfaceControlFunctions {
- ASurfaceControlFunctions();
-
- ASC_create createFunc;
- ASC_acquire acquireFunc;
- ASC_release releaseFunc;
- ASC_registerSurfaceStatsListener registerListenerFunc;
- ASC_unregisterSurfaceStatsListener unregisterListenerFunc;
- ASCStats_getAcquireTime getAcquireTimeFunc;
- ASCStats_getFrameNumber getFrameNumberFunc;
-
- AST_create transactionCreateFunc;
- AST_delete transactionDeleteFunc;
- AST_apply transactionApplyFunc;
- AST_reparent transactionReparentFunc;
- AST_setVisibility transactionSetVisibilityFunc;
- AST_setZOrder transactionSetZOrderFunc;
-};
-
class ChoreographerSource;
class DummyVsyncSource;
@@ -166,10 +123,6 @@ public:
void preload();
- const ASurfaceControlFunctions& getASurfaceControlFunctions() {
- return mASurfaceControlFunctions;
- }
-
void trimMemory(TrimLevel level);
void trimCaches(CacheTrimLevel level);
@@ -244,7 +197,6 @@ private:
CacheManager* mCacheManager;
sp<VulkanManager> mVkManager;
- ASurfaceControlFunctions mASurfaceControlFunctions;
std::mutex mJankDataMutex;
};
diff --git a/media/java/android/media/AudioDeviceVolumeManager.java b/media/java/android/media/AudioDeviceVolumeManager.java
index 56d3df3b2555..311d64f6c7e8 100644
--- a/media/java/android/media/AudioDeviceVolumeManager.java
+++ b/media/java/android/media/AudioDeviceVolumeManager.java
@@ -29,6 +29,7 @@ import android.annotation.NonNull;
import android.annotation.Nullable;
import android.annotation.RequiresPermission;
import android.annotation.SystemApi;
+import android.annotation.TestApi;
import android.content.Context;
import android.os.IBinder;
import android.os.RemoteException;
@@ -52,6 +53,127 @@ public class AudioDeviceVolumeManager {
private static final String TAG = "AudioDeviceVolumeManager";
+ /**
+ * @hide
+ * Volume behavior for an audio device that has no particular volume behavior set. Invalid as
+ * an argument to {@link #setDeviceVolumeBehavior(AudioDeviceAttributes, int)} and should not
+ * be returned by {@link #getDeviceVolumeBehavior(AudioDeviceAttributes)}.
+ */
+ public static final int DEVICE_VOLUME_BEHAVIOR_UNSET = -1;
+ /**
+ * @hide
+ * Volume behavior for an audio device where a software attenuation is applied
+ * @see #setDeviceVolumeBehavior(AudioDeviceAttributes, int)
+ */
+ @SystemApi
+ @FlaggedApi(FLAG_UNIFY_ABSOLUTE_VOLUME_MANAGEMENT)
+ public static final int DEVICE_VOLUME_BEHAVIOR_VARIABLE = 0;
+ /**
+ * @hide
+ * Volume behavior for an audio device where the volume is always set to provide no attenuation
+ * nor gain (e.g. unit gain).
+ * @see #setDeviceVolumeBehavior(AudioDeviceAttributes, int)
+ */
+ @SystemApi
+ @FlaggedApi(FLAG_UNIFY_ABSOLUTE_VOLUME_MANAGEMENT)
+ public static final int DEVICE_VOLUME_BEHAVIOR_FULL = 1;
+ /**
+ * @hide
+ * Volume behavior for an audio device where the volume is either set to muted, or to provide
+ * no attenuation nor gain (e.g. unit gain).
+ * @see #setDeviceVolumeBehavior(AudioDeviceAttributes, int)
+ */
+ @SystemApi
+ @FlaggedApi(FLAG_UNIFY_ABSOLUTE_VOLUME_MANAGEMENT)
+ public static final int DEVICE_VOLUME_BEHAVIOR_FIXED = 2;
+ /**
+ * @hide
+ * Volume behavior for an audio device where no software attenuation is applied, and
+ * the volume is kept synchronized between the host and the device itself through a
+ * device-specific protocol such as BT AVRCP.
+ * @see #setDeviceVolumeBehavior(AudioDeviceAttributes, int)
+ */
+ @SystemApi
+ @FlaggedApi(FLAG_UNIFY_ABSOLUTE_VOLUME_MANAGEMENT)
+ public static final int DEVICE_VOLUME_BEHAVIOR_ABSOLUTE = 3;
+ /**
+ * @hide
+ * Volume behavior for an audio device where no software attenuation is applied, and
+ * the volume is kept synchronized between the host and the device itself through a
+ * device-specific protocol (such as for hearing aids), based on the audio mode (e.g.
+ * normal vs in phone call).
+ * @see AudioManager#setMode(int)
+ * @see #setDeviceVolumeBehavior(AudioDeviceAttributes, int)
+ */
+ @SystemApi
+ @FlaggedApi(FLAG_UNIFY_ABSOLUTE_VOLUME_MANAGEMENT)
+ public static final int DEVICE_VOLUME_BEHAVIOR_ABSOLUTE_MULTI_MODE = 4;
+
+ /**
+ * @hide
+ * A variant of {@link #DEVICE_VOLUME_BEHAVIOR_ABSOLUTE} where the host cannot reliably set
+ * the volume percentage of the audio device. Specifically, {@link AudioManager#setStreamVolume}
+ * will have no effect, or an unreliable effect.
+ */
+ @SystemApi
+ @FlaggedApi(FLAG_UNIFY_ABSOLUTE_VOLUME_MANAGEMENT)
+ public static final int DEVICE_VOLUME_BEHAVIOR_ABSOLUTE_ADJUST_ONLY = 5;
+
+ /** @hide */
+ @IntDef({
+ DEVICE_VOLUME_BEHAVIOR_VARIABLE,
+ DEVICE_VOLUME_BEHAVIOR_FULL,
+ DEVICE_VOLUME_BEHAVIOR_FIXED,
+ DEVICE_VOLUME_BEHAVIOR_ABSOLUTE,
+ DEVICE_VOLUME_BEHAVIOR_ABSOLUTE_MULTI_MODE,
+ DEVICE_VOLUME_BEHAVIOR_ABSOLUTE_ADJUST_ONLY,
+ })
+ @Retention(RetentionPolicy.SOURCE)
+ public @interface DeviceVolumeBehavior {}
+
+ /** @hide */
+ @IntDef({
+ DEVICE_VOLUME_BEHAVIOR_UNSET,
+ DEVICE_VOLUME_BEHAVIOR_VARIABLE,
+ DEVICE_VOLUME_BEHAVIOR_FULL,
+ DEVICE_VOLUME_BEHAVIOR_FIXED,
+ DEVICE_VOLUME_BEHAVIOR_ABSOLUTE,
+ DEVICE_VOLUME_BEHAVIOR_ABSOLUTE_MULTI_MODE,
+ DEVICE_VOLUME_BEHAVIOR_ABSOLUTE_ADJUST_ONLY,
+ })
+ @Retention(RetentionPolicy.SOURCE)
+ public @interface DeviceVolumeBehaviorState {}
+
+ /**
+ * Variants of absolute volume behavior that are set in for absolute volume management.
+ * @hide
+ */
+ @IntDef({
+ DEVICE_VOLUME_BEHAVIOR_ABSOLUTE,
+ DEVICE_VOLUME_BEHAVIOR_ABSOLUTE_ADJUST_ONLY,
+ })
+ @Retention(RetentionPolicy.SOURCE)
+ public @interface AbsoluteDeviceVolumeBehavior {}
+
+ /**
+ * @hide
+ * Throws IAE on an invalid volume behavior value
+ * @param volumeBehavior behavior value to check
+ */
+ public static void enforceValidVolumeBehavior(int volumeBehavior) {
+ switch (volumeBehavior) {
+ case DEVICE_VOLUME_BEHAVIOR_VARIABLE:
+ case DEVICE_VOLUME_BEHAVIOR_FULL:
+ case DEVICE_VOLUME_BEHAVIOR_FIXED:
+ case DEVICE_VOLUME_BEHAVIOR_ABSOLUTE:
+ case DEVICE_VOLUME_BEHAVIOR_ABSOLUTE_MULTI_MODE:
+ case DEVICE_VOLUME_BEHAVIOR_ABSOLUTE_ADJUST_ONLY:
+ return;
+ default:
+ throw new IllegalArgumentException("Illegal volume behavior " + volumeBehavior);
+ }
+ }
+
/** @hide
* Indicates no special treatment in the handling of the volume adjustment */
public static final int ADJUST_MODE_NORMAL = 0;
@@ -158,7 +280,7 @@ public class AudioDeviceVolumeManager {
android.Manifest.permission.BLUETOOTH_PRIVILEGED })
public void register(boolean register, @NonNull AudioDeviceAttributes device,
@NonNull List<VolumeInfo> volumes, boolean handlesVolumeAdjustment,
- @AudioManager.AbsoluteDeviceVolumeBehavior int behavior) {
+ @AbsoluteDeviceVolumeBehavior int behavior) {
try {
getService().registerDeviceVolumeDispatcherForAbsoluteVolume(register,
this, mPackageName,
@@ -204,6 +326,94 @@ public class AudioDeviceVolumeManager {
/**
* @hide
+ * Sets the volume behavior for an audio output device.
+ * @see #DEVICE_VOLUME_BEHAVIOR_VARIABLE
+ * @see #DEVICE_VOLUME_BEHAVIOR_FULL
+ * @see #DEVICE_VOLUME_BEHAVIOR_FIXED
+ * @see #DEVICE_VOLUME_BEHAVIOR_ABSOLUTE
+ * @see #DEVICE_VOLUME_BEHAVIOR_ABSOLUTE_MULTI_MODE
+ * @param device the device to be affected
+ * @param deviceVolumeBehavior one of the device behaviors
+ */
+ @SystemApi
+ @RequiresPermission(anyOf = {
+ Manifest.permission.MODIFY_AUDIO_ROUTING,
+ Manifest.permission.MODIFY_AUDIO_SETTINGS_PRIVILEGED
+ })
+ @FlaggedApi(FLAG_UNIFY_ABSOLUTE_VOLUME_MANAGEMENT)
+ public void setDeviceVolumeBehavior(@NonNull AudioDeviceAttributes device,
+ @DeviceVolumeBehavior int deviceVolumeBehavior) {
+ // verify arguments (validity of device type is enforced in server)
+ Objects.requireNonNull(device);
+ enforceValidVolumeBehavior(deviceVolumeBehavior);
+ // communicate with service
+ final IAudioService service = getService();
+ try {
+ service.setDeviceVolumeBehavior(device, deviceVolumeBehavior, mPackageName);
+ } catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
+ }
+ }
+
+ /**
+ * @hide
+ * Returns the volume device behavior for the given audio device
+ * @param device the audio device
+ * @return the volume behavior for the device
+ */
+ @SystemApi
+ @RequiresPermission(anyOf = {
+ Manifest.permission.MODIFY_AUDIO_ROUTING,
+ Manifest.permission.QUERY_AUDIO_STATE,
+ Manifest.permission.MODIFY_AUDIO_SETTINGS_PRIVILEGED
+ })
+ @FlaggedApi(FLAG_UNIFY_ABSOLUTE_VOLUME_MANAGEMENT)
+ public @DeviceVolumeBehavior int getDeviceVolumeBehavior(
+ @NonNull AudioDeviceAttributes device) {
+ // verify arguments (validity of device type is enforced in server)
+ Objects.requireNonNull(device);
+ // communicate with service
+ final IAudioService service = getService();
+ try {
+ return service.getDeviceVolumeBehavior(device);
+ } catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
+ }
+ }
+
+ /**
+ * @hide
+ * Returns {@code true} if the volume device behavior is {@link #DEVICE_VOLUME_BEHAVIOR_FULL}.
+ */
+ @TestApi
+ @RequiresPermission(anyOf = {
+ Manifest.permission.MODIFY_AUDIO_ROUTING,
+ Manifest.permission.QUERY_AUDIO_STATE,
+ Manifest.permission.MODIFY_AUDIO_SETTINGS_PRIVILEGED
+ })
+ @SuppressWarnings("UnflaggedApi") // @TestApi without associated feature.
+ public boolean isFullVolumeDevice() {
+ final AudioAttributes attributes = new AudioAttributes.Builder()
+ .setUsage(AudioAttributes.USAGE_MEDIA)
+ .build();
+ List<AudioDeviceAttributes> devices;
+ final IAudioService service = getService();
+ try {
+ devices = service.getDevicesForAttributes(attributes);
+ } catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
+ }
+
+ for (AudioDeviceAttributes device : devices) {
+ if (getDeviceVolumeBehavior(device) == DEVICE_VOLUME_BEHAVIOR_FULL) {
+ return true;
+ }
+ }
+ return false;
+ }
+
+ /**
+ * @hide
* Configures a device to use absolute volume model, and registers a listener for receiving
* volume updates to apply on that device
* @param device the audio device set to absolute volume mode
@@ -297,7 +507,7 @@ public class AudioDeviceVolumeManager {
@NonNull @CallbackExecutor Executor executor,
@NonNull OnAudioDeviceVolumeChangedListener vclistener) {
baseSetDeviceAbsoluteMultiVolumeBehavior(device, volumes, executor, vclistener,
- handlesVolumeAdjustment, AudioManager.DEVICE_VOLUME_BEHAVIOR_ABSOLUTE);
+ handlesVolumeAdjustment, DEVICE_VOLUME_BEHAVIOR_ABSOLUTE);
}
/**
@@ -355,12 +565,12 @@ public class AudioDeviceVolumeManager {
@NonNull @CallbackExecutor Executor executor,
@NonNull OnAudioDeviceVolumeChangedListener vclistener) {
baseSetDeviceAbsoluteMultiVolumeBehavior(device, volumes, executor, vclistener,
- handlesVolumeAdjustment, AudioManager.DEVICE_VOLUME_BEHAVIOR_ABSOLUTE_ADJUST_ONLY);
+ handlesVolumeAdjustment, DEVICE_VOLUME_BEHAVIOR_ABSOLUTE_ADJUST_ONLY);
}
/**
* Base method for configuring a device to use absolute volume behavior, or one of its variants.
- * See {@link AudioManager.AbsoluteDeviceVolumeBehavior} for a list of allowed behaviors.
+ * See {@link AbsoluteDeviceVolumeBehavior} for a list of allowed behaviors.
*
* @param behavior the variant of absolute device volume behavior to adopt
*/
@@ -372,7 +582,7 @@ public class AudioDeviceVolumeManager {
@NonNull @CallbackExecutor Executor executor,
@NonNull OnAudioDeviceVolumeChangedListener vclistener,
boolean handlesVolumeAdjustment,
- @AudioManager.AbsoluteDeviceVolumeBehavior int behavior) {
+ @AbsoluteDeviceVolumeBehavior int behavior) {
Objects.requireNonNull(device);
Objects.requireNonNull(volumes);
Objects.requireNonNull(executor);
@@ -417,7 +627,7 @@ public class AudioDeviceVolumeManager {
*/
void onDeviceVolumeBehaviorChanged(
@NonNull AudioDeviceAttributes device,
- @AudioManager.DeviceVolumeBehavior int volumeBehavior);
+ @DeviceVolumeBehavior int volumeBehavior);
}
/**
@@ -580,19 +790,19 @@ public class AudioDeviceVolumeManager {
* @param behavior one of the volume behaviors defined in AudioManager
* @return a string for the given behavior
*/
- public static String volumeBehaviorName(@AudioManager.DeviceVolumeBehavior int behavior) {
+ public static String volumeBehaviorName(@DeviceVolumeBehavior int behavior) {
switch (behavior) {
- case AudioManager.DEVICE_VOLUME_BEHAVIOR_VARIABLE:
+ case DEVICE_VOLUME_BEHAVIOR_VARIABLE:
return "DEVICE_VOLUME_BEHAVIOR_VARIABLE";
- case AudioManager.DEVICE_VOLUME_BEHAVIOR_FULL:
+ case DEVICE_VOLUME_BEHAVIOR_FULL:
return "DEVICE_VOLUME_BEHAVIOR_FULL";
- case AudioManager.DEVICE_VOLUME_BEHAVIOR_FIXED:
+ case DEVICE_VOLUME_BEHAVIOR_FIXED:
return "DEVICE_VOLUME_BEHAVIOR_FIXED";
- case AudioManager.DEVICE_VOLUME_BEHAVIOR_ABSOLUTE:
+ case DEVICE_VOLUME_BEHAVIOR_ABSOLUTE:
return "DEVICE_VOLUME_BEHAVIOR_ABSOLUTE";
- case AudioManager.DEVICE_VOLUME_BEHAVIOR_ABSOLUTE_MULTI_MODE:
+ case DEVICE_VOLUME_BEHAVIOR_ABSOLUTE_MULTI_MODE:
return "DEVICE_VOLUME_BEHAVIOR_ABSOLUTE_MULTI_MODE";
- case AudioManager.DEVICE_VOLUME_BEHAVIOR_ABSOLUTE_ADJUST_ONLY:
+ case DEVICE_VOLUME_BEHAVIOR_ABSOLUTE_ADJUST_ONLY:
return "DEVICE_VOLUME_BEHAVIOR_ABSOLUTE_ADJUST_ONLY";
default:
return "invalid volume behavior " + behavior;
@@ -611,7 +821,7 @@ public class AudioDeviceVolumeManager {
@Override
public void dispatchDeviceVolumeBehaviorChanged(@NonNull AudioDeviceAttributes device,
- @AudioManager.DeviceVolumeBehavior int volumeBehavior) {
+ @DeviceVolumeBehavior int volumeBehavior) {
mDeviceVolumeBehaviorChangedListenerMgr.callListeners((listener) ->
listener.onDeviceVolumeBehaviorChanged(device, volumeBehavior));
}
diff --git a/media/java/android/media/AudioManager.java b/media/java/android/media/AudioManager.java
index 32af7c6fca68..4aba491c291e 100644
--- a/media/java/android/media/AudioManager.java
+++ b/media/java/android/media/AudioManager.java
@@ -19,6 +19,7 @@ package android.media;
import static android.companion.virtual.VirtualDeviceParams.DEVICE_POLICY_DEFAULT;
import static android.companion.virtual.VirtualDeviceParams.POLICY_TYPE_AUDIO;
import static android.content.Context.DEVICE_ID_DEFAULT;
+import static android.media.audio.Flags.FLAG_UNIFY_ABSOLUTE_VOLUME_MANAGEMENT;
import static android.media.audio.Flags.autoPublicVolumeApiHardening;
import static android.media.audio.Flags.cacheGetStreamMinMaxVolume;
import static android.media.audio.Flags.cacheGetStreamVolume;
@@ -6659,24 +6660,30 @@ public class AudioManager {
* @hide
* Volume behavior for an audio device where a software attenuation is applied
* @see #setDeviceVolumeBehavior(AudioDeviceAttributes, int)
+ * @deprecated use {@link AudioDeviceVolumeManager#DEVICE_VOLUME_BEHAVIOR_VARIABLE} instead
*/
@SystemApi
+ @FlaggedApi(FLAG_UNIFY_ABSOLUTE_VOLUME_MANAGEMENT)
public static final int DEVICE_VOLUME_BEHAVIOR_VARIABLE = 0;
/**
* @hide
* Volume behavior for an audio device where the volume is always set to provide no attenuation
* nor gain (e.g. unit gain).
* @see #setDeviceVolumeBehavior(AudioDeviceAttributes, int)
+ * @deprecated use {@link AudioDeviceVolumeManager#DEVICE_VOLUME_BEHAVIOR_FULL} instead
*/
@SystemApi
+ @FlaggedApi(FLAG_UNIFY_ABSOLUTE_VOLUME_MANAGEMENT)
public static final int DEVICE_VOLUME_BEHAVIOR_FULL = 1;
/**
* @hide
* Volume behavior for an audio device where the volume is either set to muted, or to provide
* no attenuation nor gain (e.g. unit gain).
* @see #setDeviceVolumeBehavior(AudioDeviceAttributes, int)
+ * @deprecated use {@link AudioDeviceVolumeManager#DEVICE_VOLUME_BEHAVIOR_FIXED} instead
*/
@SystemApi
+ @FlaggedApi(FLAG_UNIFY_ABSOLUTE_VOLUME_MANAGEMENT)
public static final int DEVICE_VOLUME_BEHAVIOR_FIXED = 2;
/**
* @hide
@@ -6684,8 +6691,10 @@ public class AudioManager {
* the volume is kept synchronized between the host and the device itself through a
* device-specific protocol such as BT AVRCP.
* @see #setDeviceVolumeBehavior(AudioDeviceAttributes, int)
+ * @deprecated use {@link AudioDeviceVolumeManager#DEVICE_VOLUME_BEHAVIOR_ABSOLUTE} instead
*/
@SystemApi
+ @FlaggedApi(FLAG_UNIFY_ABSOLUTE_VOLUME_MANAGEMENT)
public static final int DEVICE_VOLUME_BEHAVIOR_ABSOLUTE = 3;
/**
* @hide
@@ -6695,8 +6704,11 @@ public class AudioManager {
* normal vs in phone call).
* @see #setMode(int)
* @see #setDeviceVolumeBehavior(AudioDeviceAttributes, int)
+ * @deprecated use {@link AudioDeviceVolumeManager#DEVICE_VOLUME_BEHAVIOR_ABSOLUTE_MULTI_MODE}
+ * instead
*/
@SystemApi
+ @FlaggedApi(FLAG_UNIFY_ABSOLUTE_VOLUME_MANAGEMENT)
public static final int DEVICE_VOLUME_BEHAVIOR_ABSOLUTE_MULTI_MODE = 4;
/**
@@ -6704,8 +6716,11 @@ public class AudioManager {
* A variant of {@link #DEVICE_VOLUME_BEHAVIOR_ABSOLUTE} where the host cannot reliably set
* the volume percentage of the audio device. Specifically, {@link #setStreamVolume} will have
* no effect, or an unreliable effect.
+ * @deprecated use {@link AudioDeviceVolumeManager#DEVICE_VOLUME_BEHAVIOR_ABSOLUTE_ADJUST_ONLY}
+ * instead
*/
@SystemApi
+ @FlaggedApi(FLAG_UNIFY_ABSOLUTE_VOLUME_MANAGEMENT)
public static final int DEVICE_VOLUME_BEHAVIOR_ABSOLUTE_ADJUST_ONLY = 5;
/** @hide */
@@ -6720,49 +6735,6 @@ public class AudioManager {
@Retention(RetentionPolicy.SOURCE)
public @interface DeviceVolumeBehavior {}
- /** @hide */
- @IntDef({
- DEVICE_VOLUME_BEHAVIOR_UNSET,
- DEVICE_VOLUME_BEHAVIOR_VARIABLE,
- DEVICE_VOLUME_BEHAVIOR_FULL,
- DEVICE_VOLUME_BEHAVIOR_FIXED,
- DEVICE_VOLUME_BEHAVIOR_ABSOLUTE,
- DEVICE_VOLUME_BEHAVIOR_ABSOLUTE_MULTI_MODE,
- DEVICE_VOLUME_BEHAVIOR_ABSOLUTE_ADJUST_ONLY,
- })
- @Retention(RetentionPolicy.SOURCE)
- public @interface DeviceVolumeBehaviorState {}
-
- /**
- * Variants of absolute volume behavior that are set in {@link AudioDeviceVolumeManager}.
- * @hide
- */
- @IntDef({
- DEVICE_VOLUME_BEHAVIOR_ABSOLUTE,
- DEVICE_VOLUME_BEHAVIOR_ABSOLUTE_ADJUST_ONLY,
- })
- @Retention(RetentionPolicy.SOURCE)
- public @interface AbsoluteDeviceVolumeBehavior {}
-
- /**
- * @hide
- * Throws IAE on an invalid volume behavior value
- * @param volumeBehavior behavior value to check
- */
- public static void enforceValidVolumeBehavior(int volumeBehavior) {
- switch (volumeBehavior) {
- case DEVICE_VOLUME_BEHAVIOR_VARIABLE:
- case DEVICE_VOLUME_BEHAVIOR_FULL:
- case DEVICE_VOLUME_BEHAVIOR_FIXED:
- case DEVICE_VOLUME_BEHAVIOR_ABSOLUTE:
- case DEVICE_VOLUME_BEHAVIOR_ABSOLUTE_MULTI_MODE:
- case DEVICE_VOLUME_BEHAVIOR_ABSOLUTE_ADJUST_ONLY:
- return;
- default:
- throw new IllegalArgumentException("Illegal volume behavior " + volumeBehavior);
- }
- }
-
/**
* @hide
* Sets the volume behavior for an audio output device.
@@ -6773,17 +6745,21 @@ public class AudioManager {
* @see #DEVICE_VOLUME_BEHAVIOR_ABSOLUTE_MULTI_MODE
* @param device the device to be affected
* @param deviceVolumeBehavior one of the device behaviors
+ *
+ * @deprecated use
+ * {@link AudioDeviceVolumeManager#setDeviceVolumeBehavior(AudioDeviceAttributes, int)} instead
*/
@SystemApi
@RequiresPermission(anyOf = {
Manifest.permission.MODIFY_AUDIO_ROUTING,
Manifest.permission.MODIFY_AUDIO_SETTINGS_PRIVILEGED
})
+ @FlaggedApi(FLAG_UNIFY_ABSOLUTE_VOLUME_MANAGEMENT)
public void setDeviceVolumeBehavior(@NonNull AudioDeviceAttributes device,
@DeviceVolumeBehavior int deviceVolumeBehavior) {
// verify arguments (validity of device type is enforced in server)
Objects.requireNonNull(device);
- enforceValidVolumeBehavior(deviceVolumeBehavior);
+ AudioDeviceVolumeManager.enforceValidVolumeBehavior(deviceVolumeBehavior);
// communicate with service
final IAudioService service = getService();
try {
@@ -6810,6 +6786,8 @@ public class AudioManager {
* Returns the volume device behavior for the given audio device
* @param device the audio device
* @return the volume behavior for the device
+ * @deprecated use
+ * {@link AudioDeviceVolumeManager#getDeviceVolumeBehavior(AudioDeviceAttributes)} instead
*/
@SystemApi
@RequiresPermission(anyOf = {
@@ -6817,6 +6795,7 @@ public class AudioManager {
Manifest.permission.QUERY_AUDIO_STATE,
Manifest.permission.MODIFY_AUDIO_SETTINGS_PRIVILEGED
})
+ @FlaggedApi(FLAG_UNIFY_ABSOLUTE_VOLUME_MANAGEMENT)
public @DeviceVolumeBehavior
int getDeviceVolumeBehavior(@NonNull AudioDeviceAttributes device) {
// verify arguments (validity of device type is enforced in server)
@@ -6836,29 +6815,6 @@ public class AudioManager {
}
/**
- * @hide
- * Returns {@code true} if the volume device behavior is {@link #DEVICE_VOLUME_BEHAVIOR_FULL}.
- */
- @TestApi
- @RequiresPermission(anyOf = {
- Manifest.permission.MODIFY_AUDIO_ROUTING,
- Manifest.permission.QUERY_AUDIO_STATE,
- Manifest.permission.MODIFY_AUDIO_SETTINGS_PRIVILEGED
- })
- public boolean isFullVolumeDevice() {
- final AudioAttributes attributes = new AudioAttributes.Builder()
- .setUsage(AudioAttributes.USAGE_MEDIA)
- .build();
- final List<AudioDeviceAttributes> devices = getDevicesForAttributes(attributes);
- for (AudioDeviceAttributes device : devices) {
- if (getDeviceVolumeBehavior(device) == DEVICE_VOLUME_BEHAVIOR_FULL) {
- return true;
- }
- }
- return false;
- }
-
- /**
* Indicate wired accessory connection state change.
* @param device type of device connected/disconnected (AudioManager.DEVICE_OUT_xxx)
* @param state new connection state: 1 connected, 0 disconnected
diff --git a/media/java/android/media/MediaRecorder.java b/media/java/android/media/MediaRecorder.java
index 7af78b81cda5..03bcc6afc1b7 100644
--- a/media/java/android/media/MediaRecorder.java
+++ b/media/java/android/media/MediaRecorder.java
@@ -1299,6 +1299,7 @@ public class MediaRecorder implements AudioRouting,
* start() or before setOutputFormat().
* @throws IOException if prepare fails otherwise.
*/
+ @RequiresPermission(value = android.Manifest.permission.RECORD_AUDIO, conditional = true)
public void prepare() throws IllegalStateException, IOException
{
if (mPath != null) {
@@ -1337,6 +1338,7 @@ public class MediaRecorder implements AudioRouting,
* @throws IllegalStateException if it is called before
* prepare() or when the camera is already in use by another app.
*/
+ @RequiresPermission(value = android.Manifest.permission.RECORD_AUDIO, conditional = true)
public native void start() throws IllegalStateException;
/**
diff --git a/packages/SettingsLib/ButtonPreference/src/com/android/settingslib/widget/ButtonPreference.java b/packages/SettingsLib/ButtonPreference/src/com/android/settingslib/widget/ButtonPreference.java
index be711accd542..89e5372b530e 100644
--- a/packages/SettingsLib/ButtonPreference/src/com/android/settingslib/widget/ButtonPreference.java
+++ b/packages/SettingsLib/ButtonPreference/src/com/android/settingslib/widget/ButtonPreference.java
@@ -27,6 +27,7 @@ import android.widget.Button;
import android.widget.LinearLayout;
import androidx.annotation.GravityInt;
+import androidx.annotation.IntDef;
import androidx.preference.Preference;
import androidx.preference.PreferenceViewHolder;
@@ -34,21 +35,46 @@ import com.android.settingslib.widget.preference.button.R;
import com.google.android.material.button.MaterialButton;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+
/**
* A preference handled a button
*/
public class ButtonPreference extends Preference implements GroupSectionDividerMixin {
+ public static final int TYPE_FILLED = 0;
+ public static final int TYPE_TONAL = 1;
+ public static final int TYPE_OUTLINE = 2;
+
+ @IntDef({TYPE_FILLED, TYPE_TONAL, TYPE_OUTLINE})
+ @Retention(RetentionPolicy.SOURCE)
+ public @interface Type {
+ }
+
+ public static final int SIZE_NORMAL = 0;
+ public static final int SIZE_LARGE = 1;
+ public static final int SIZE_EXTRA_LARGE = 2;
+
+ @IntDef({SIZE_NORMAL, SIZE_LARGE, SIZE_EXTRA_LARGE})
+ @Retention(RetentionPolicy.SOURCE)
+ public @interface Size {
+ }
+
enum ButtonStyle {
- FILLED_NORMAL(0, 0, R.layout.settingslib_expressive_button_filled),
- FILLED_LARGE(0, 1, R.layout.settingslib_expressive_button_filled_large),
- FILLED_EXTRA(0, 2, R.layout.settingslib_expressive_button_filled_extra),
- TONAL_NORMAL(1, 0, R.layout.settingslib_expressive_button_tonal),
- TONAL_LARGE(1, 1, R.layout.settingslib_expressive_button_tonal_large),
- TONAL_EXTRA(1, 2, R.layout.settingslib_expressive_button_tonal_extra),
- OUTLINE_NORMAL(2, 0, R.layout.settingslib_expressive_button_outline),
- OUTLINE_LARGE(2, 1, R.layout.settingslib_expressive_button_outline_large),
- OUTLINE_EXTRA(2, 2, R.layout.settingslib_expressive_button_outline_extra);
+ FILLED_NORMAL(TYPE_FILLED, SIZE_NORMAL, R.layout.settingslib_expressive_button_filled),
+ FILLED_LARGE(TYPE_FILLED, SIZE_LARGE, R.layout.settingslib_expressive_button_filled_large),
+ FILLED_EXTRA(TYPE_FILLED, SIZE_EXTRA_LARGE,
+ R.layout.settingslib_expressive_button_filled_extra),
+ TONAL_NORMAL(TYPE_TONAL, SIZE_NORMAL, R.layout.settingslib_expressive_button_tonal),
+ TONAL_LARGE(TYPE_TONAL, SIZE_LARGE, R.layout.settingslib_expressive_button_tonal_large),
+ TONAL_EXTRA(TYPE_TONAL, SIZE_EXTRA_LARGE,
+ R.layout.settingslib_expressive_button_tonal_extra),
+ OUTLINE_NORMAL(TYPE_OUTLINE, SIZE_NORMAL, R.layout.settingslib_expressive_button_outline),
+ OUTLINE_LARGE(TYPE_OUTLINE, SIZE_LARGE,
+ R.layout.settingslib_expressive_button_outline_large),
+ OUTLINE_EXTRA(TYPE_OUTLINE, SIZE_EXTRA_LARGE,
+ R.layout.settingslib_expressive_button_outline_extra);
private final int mType;
private final int mSize;
@@ -60,7 +86,7 @@ public class ButtonPreference extends Preference implements GroupSectionDividerM
this.mLayoutId = layoutId;
}
- static int getLayoutId(int type, int size) {
+ static int getLayoutId(@Type int type, @Size int size) {
for (ButtonStyle style : values()) {
if (style.mType == type && style.mSize == size) {
return style.mLayoutId;
@@ -266,7 +292,7 @@ public class ButtonPreference extends Preference implements GroupSectionDividerM
* <li>2: extra large</li>
* </ul>
*/
- public void setButtonStyle(int type, int size) {
+ public void setButtonStyle(@Type int type, @Size int size) {
int layoutId = ButtonStyle.getLayoutId(type, size);
setLayoutResource(layoutId);
notifyChanged();
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/panels/ui/viewmodel/DetailsViewModelTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/panels/ui/viewmodel/DetailsViewModelTest.kt
index 1d42424bc6ed..8d50cdc001ca 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/panels/ui/viewmodel/DetailsViewModelTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/panels/ui/viewmodel/DetailsViewModelTest.kt
@@ -19,13 +19,17 @@ package com.android.systemui.qs.panels.ui.viewmodel
import androidx.test.ext.junit.runners.AndroidJUnit4
import androidx.test.filters.SmallTest
import com.android.systemui.SysuiTestCase
+import com.android.systemui.flags.EnableSceneContainer
import com.android.systemui.kosmos.testScope
import com.android.systemui.qs.FakeQSTile
import com.android.systemui.qs.pipeline.data.repository.tileSpecRepository
import com.android.systemui.qs.pipeline.domain.interactor.currentTilesInteractor
import com.android.systemui.qs.pipeline.shared.TileSpec
+import com.android.systemui.shade.domain.interactor.disableDualShade
+import com.android.systemui.shade.domain.interactor.enableDualShade
import com.android.systemui.testKosmos
import com.google.common.truth.Truth.assertThat
+import kotlinx.coroutines.ExperimentalCoroutinesApi
import kotlinx.coroutines.test.runCurrent
import kotlinx.coroutines.test.runTest
import org.junit.Before
@@ -34,6 +38,7 @@ import org.junit.runner.RunWith
@RunWith(AndroidJUnit4::class)
@SmallTest
+@EnableSceneContainer
class DetailsViewModelTest : SysuiTestCase() {
private val kosmos = testKosmos()
private lateinit var underTest: DetailsViewModel
@@ -45,10 +50,12 @@ class DetailsViewModelTest : SysuiTestCase() {
underTest = kosmos.detailsViewModel
}
+ @OptIn(ExperimentalCoroutinesApi::class)
@Test
- fun changeTileDetailsViewModel() =
+ fun changeTileDetailsViewModelWithDualShadeEnabled() =
with(kosmos) {
testScope.runTest {
+ kosmos.enableDualShade()
val specs = listOf(spec, specNoDetails)
tileSpecRepository.setTiles(0, specs)
runCurrent()
@@ -85,4 +92,36 @@ class DetailsViewModelTest : SysuiTestCase() {
assertThat(underTest.onTileClicked(null)).isFalse()
}
}
+
+ @OptIn(ExperimentalCoroutinesApi::class)
+ @Test
+ fun ignoreChangingTileDetailsViewModelWithDualShadeDisabled() =
+ with(kosmos) {
+ testScope.runTest {
+ kosmos.disableDualShade()
+ val specs = listOf(spec, specNoDetails)
+ tileSpecRepository.setTiles(0, specs)
+ runCurrent()
+
+ val tiles = currentTilesInteractor.currentTiles.value
+
+ assertThat(currentTilesInteractor.currentTilesSpecs.size).isEqualTo(2)
+ assertThat(tiles[1].spec).isEqualTo(specNoDetails)
+ (tiles[1].tile as FakeQSTile).hasDetailsViewModel = false
+
+ assertThat(underTest.activeTileDetails).isNull()
+
+ // Click on the tile who has the `spec`.
+ assertThat(underTest.onTileClicked(spec)).isFalse()
+ assertThat(underTest.activeTileDetails).isNull()
+
+ // Click on a tile who dose not have a valid spec.
+ assertThat(underTest.onTileClicked(null)).isFalse()
+ assertThat(underTest.activeTileDetails).isNull()
+
+ // Click on a tile who dose not have a detailed view.
+ assertThat(underTest.onTileClicked(specNoDetails)).isFalse()
+ assertThat(underTest.activeTileDetails).isNull()
+ }
+ }
}
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/row/NotificationMenuRowTest.java b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/row/NotificationMenuRowTest.java
index ce120c51db6a..95366568a37a 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/row/NotificationMenuRowTest.java
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/row/NotificationMenuRowTest.java
@@ -28,6 +28,7 @@ import static org.mockito.Mockito.times;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
+import android.platform.test.annotations.DisableFlags;
import android.provider.Settings;
import android.testing.TestableLooper;
import android.testing.TestableLooper.RunWithLooper;
@@ -38,6 +39,7 @@ import android.view.ViewGroup;
import androidx.test.ext.junit.runners.AndroidJUnit4;
import androidx.test.filters.SmallTest;
+import com.android.systemui.Flags;
import com.android.systemui.kosmos.KosmosJavaAdapter;
import com.android.systemui.plugins.statusbar.NotificationMenuRowPlugin;
import com.android.systemui.statusbar.notification.collection.EntryAdapter;
@@ -418,6 +420,7 @@ public class NotificationMenuRowTest extends LeakCheckedTest {
assertTrue("when alpha is .5, menu is visible", row.isMenuVisible());
}
+ @DisableFlags(Flags.FLAG_MAGNETIC_NOTIFICATION_SWIPES)
@Test
public void testOnTouchMove() {
NotificationMenuRow row = Mockito.spy(
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/stack/MagneticNotificationRowManagerImplTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/stack/MagneticNotificationRowManagerImplTest.kt
index ccc8be7de038..6c6ba933c03a 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/stack/MagneticNotificationRowManagerImplTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/stack/MagneticNotificationRowManagerImplTest.kt
@@ -130,7 +130,9 @@ class MagneticNotificationRowManagerImplTest : SysuiTestCase() {
kosmos.testScope.runTest {
// GIVEN a threshold of 100 px
val threshold = 100f
- underTest.setSwipeThresholdPx(threshold)
+ underTest.onDensityChange(
+ threshold / MagneticNotificationRowManager.MAGNETIC_DETACH_THRESHOLD_DP
+ )
// GIVEN that targets are set and the rows are being pulled
setTargets()
@@ -150,7 +152,9 @@ class MagneticNotificationRowManagerImplTest : SysuiTestCase() {
kosmos.testScope.runTest {
// GIVEN a threshold of 100 px
val threshold = 100f
- underTest.setSwipeThresholdPx(threshold)
+ underTest.onDensityChange(
+ threshold / MagneticNotificationRowManager.MAGNETIC_DETACH_THRESHOLD_DP
+ )
// GIVEN that targets are set and the rows are being pulled
canRowBeDismissed = false
@@ -172,7 +176,9 @@ class MagneticNotificationRowManagerImplTest : SysuiTestCase() {
kosmos.testScope.runTest {
// GIVEN a threshold of 100 px
val threshold = 100f
- underTest.setSwipeThresholdPx(threshold)
+ underTest.onDensityChange(
+ threshold / MagneticNotificationRowManager.MAGNETIC_DETACH_THRESHOLD_DP
+ )
// GIVEN that targets are set and the rows are being pulled
setTargets()
@@ -192,7 +198,9 @@ class MagneticNotificationRowManagerImplTest : SysuiTestCase() {
kosmos.testScope.runTest {
// GIVEN a threshold of 100 px
val threshold = 100f
- underTest.setSwipeThresholdPx(threshold)
+ underTest.onDensityChange(
+ threshold / MagneticNotificationRowManager.MAGNETIC_DETACH_THRESHOLD_DP
+ )
// GIVEN that targets are set and the rows are being pulled
canRowBeDismissed = false
@@ -294,6 +302,29 @@ class MagneticNotificationRowManagerImplTest : SysuiTestCase() {
assertThat(underTest.isSwipedViewRoundableSet).isFalse()
}
+ @Test
+ fun isMagneticRowDismissible_isDismissibleWhenDetached() =
+ kosmos.testScope.runTest {
+ setDetachedState()
+
+ val isDismissible = underTest.isMagneticRowSwipeDetached(swipedRow)
+ assertThat(isDismissible).isTrue()
+ }
+
+ @Test
+ fun setMagneticRowTranslation_whenDetached_belowAttachThreshold_reattaches() =
+ kosmos.testScope.runTest {
+ // GIVEN that the swiped view has been detached
+ setDetachedState()
+
+ // WHEN setting a new translation above the attach threshold
+ val translation = 50f
+ underTest.setMagneticRowTranslation(swipedRow, translation)
+
+ // THEN the swiped view reattaches magnetically and the state becomes PULLING
+ assertThat(underTest.currentState).isEqualTo(State.PULLING)
+ }
+
@After
fun tearDown() {
// We reset the manager so that all MagneticRowListener can cancel all animations
@@ -302,7 +333,9 @@ class MagneticNotificationRowManagerImplTest : SysuiTestCase() {
private fun setDetachedState() {
val threshold = 100f
- underTest.setSwipeThresholdPx(threshold)
+ underTest.onDensityChange(
+ threshold / MagneticNotificationRowManager.MAGNETIC_DETACH_THRESHOLD_DP
+ )
// Set the pulling state
setTargets()
@@ -327,8 +360,8 @@ class MagneticNotificationRowManagerImplTest : SysuiTestCase() {
private fun MagneticRowListener.asTestableListener(rowIndex: Int): MagneticRowListener {
val delegate = this
return object : MagneticRowListener {
- override fun setMagneticTranslation(translation: Float) {
- delegate.setMagneticTranslation(translation)
+ override fun setMagneticTranslation(translation: Float, trackEagerly: Boolean) {
+ delegate.setMagneticTranslation(translation, trackEagerly)
}
override fun triggerMagneticForce(
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/stack/NotificationSwipeHelperTest.java b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/stack/NotificationSwipeHelperTest.java
index 789701f5e4b0..de48f4018989 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/stack/NotificationSwipeHelperTest.java
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/stack/NotificationSwipeHelperTest.java
@@ -49,6 +49,7 @@ import android.view.ViewConfiguration;
import androidx.test.ext.junit.runners.AndroidJUnit4;
import androidx.test.filters.SmallTest;
+import com.android.systemui.Flags;
import com.android.systemui.SysuiTestCase;
import com.android.systemui.classifier.FalsingManagerFake;
import com.android.systemui.flags.FakeFeatureFlags;
@@ -362,6 +363,7 @@ public class NotificationSwipeHelperTest extends SysuiTestCase {
verify(mSwipeHelper, times(1)).isFalseGesture();
}
+ @DisableFlags(Flags.FLAG_MAGNETIC_NOTIFICATION_SWIPES)
@Test
public void testIsDismissGesture_farEnough() {
doReturn(false).when(mSwipeHelper).isFalseGesture();
@@ -374,6 +376,20 @@ public class NotificationSwipeHelperTest extends SysuiTestCase {
verify(mSwipeHelper, times(1)).isFalseGesture();
}
+ @EnableFlags(Flags.FLAG_MAGNETIC_NOTIFICATION_SWIPES)
+ @Test
+ public void testIsDismissGesture_magneticSwipeIsDismissible() {
+ doReturn(false).when(mSwipeHelper).isFalseGesture();
+ doReturn(false).when(mSwipeHelper).swipedFarEnough();
+ doReturn(false).when(mSwipeHelper).swipedFastEnough();
+ doReturn(true).when(mCallback).isMagneticViewDetached(any());
+ when(mCallback.canChildBeDismissedInDirection(any(), anyBoolean())).thenReturn(true);
+ when(mEvent.getActionMasked()).thenReturn(MotionEvent.ACTION_UP);
+
+ assertTrue("Should be a dismissal", mSwipeHelper.isDismissGesture(mEvent));
+ verify(mSwipeHelper, times(1)).isFalseGesture();
+ }
+
@Test
public void testIsDismissGesture_notFarOrFastEnough() {
doReturn(false).when(mSwipeHelper).isFalseGesture();
diff --git a/packages/SystemUI/src/com/android/systemui/SwipeHelper.java b/packages/SystemUI/src/com/android/systemui/SwipeHelper.java
index 089466707298..d017754ae653 100644
--- a/packages/SystemUI/src/com/android/systemui/SwipeHelper.java
+++ b/packages/SystemUI/src/com/android/systemui/SwipeHelper.java
@@ -778,18 +778,26 @@ public class SwipeHelper implements Gefingerpoken, Dumpable {
protected boolean swipedFarEnough() {
float translation = getTranslation(mTouchedView);
- return Math.abs(translation) > SWIPED_FAR_ENOUGH_SIZE_FRACTION * getSize(
- mTouchedView);
+ return Math.abs(translation) > SWIPED_FAR_ENOUGH_SIZE_FRACTION * getSize(mTouchedView);
}
public boolean isDismissGesture(MotionEvent ev) {
float translation = getTranslation(mTouchedView);
return ev.getActionMasked() == MotionEvent.ACTION_UP
&& !mFalsingManager.isUnlockingDisabled()
- && !isFalseGesture() && (swipedFastEnough() || swipedFarEnough())
+ && !isFalseGesture() && isSwipeDismissible()
&& mCallback.canChildBeDismissedInDirection(mTouchedView, translation > 0);
}
+ /** Can the swipe gesture on the touched view be considered as a dismiss intention */
+ public boolean isSwipeDismissible() {
+ if (magneticNotificationSwipes()) {
+ return mCallback.isMagneticViewDetached(mTouchedView) || swipedFastEnough();
+ } else {
+ return swipedFastEnough() || swipedFarEnough();
+ }
+ }
+
/** Returns true if the gesture should be rejected. */
public boolean isFalseGesture() {
boolean falsingDetected = mCallback.isAntiFalsingNeeded();
@@ -970,6 +978,13 @@ public class SwipeHelper implements Gefingerpoken, Dumpable {
void onMagneticInteractionEnd(View view, float velocity);
/**
+ * Determine if a view managed by magnetic interactions is magnetically detached
+ * @param view The magnetic view
+ * @return if the view is detached according to its magnetic state.
+ */
+ boolean isMagneticViewDetached(View view);
+
+ /**
* Called when the child is long pressed and available to start drag and drop.
*
* @param v the view that was long pressed.
diff --git a/packages/SystemUI/src/com/android/systemui/accessibility/hearingaid/HearingDevicesDialogDelegate.java b/packages/SystemUI/src/com/android/systemui/accessibility/hearingaid/HearingDevicesDialogDelegate.java
index 14b13d105482..24b955152093 100644
--- a/packages/SystemUI/src/com/android/systemui/accessibility/hearingaid/HearingDevicesDialogDelegate.java
+++ b/packages/SystemUI/src/com/android/systemui/accessibility/hearingaid/HearingDevicesDialogDelegate.java
@@ -286,7 +286,9 @@ public class HearingDevicesDialogDelegate implements SystemUIDialog.Delegate,
mLaunchSourceId);
final Intent intent = new Intent(Settings.ACTION_ACCESSIBILITY_DETAILS_SETTINGS)
.putExtra(Intent.EXTRA_COMPONENT_NAME,
- ACCESSIBILITY_HEARING_AIDS_COMPONENT_NAME.flattenToString());
+ ACCESSIBILITY_HEARING_AIDS_COMPONENT_NAME.flattenToString())
+ .setPackage(mQSSettingsPackageRepository.getSettingsPackageName());
+
mActivityStarter.postStartActivityDismissingKeyguard(intent, /* delay= */ 0,
mDialogTransitionAnimator.createActivityTransitionController(
dialog));
@@ -588,9 +590,7 @@ public class HearingDevicesDialogDelegate implements SystemUIDialog.Delegate,
com.android.internal.R.color.materialColorOnPrimaryContainer));
}
text.setText(item.getToolName());
- Intent intent = item.getToolIntent()
- .setPackage(mQSSettingsPackageRepository.getSettingsPackageName());
-
+ Intent intent = item.getToolIntent();
view.setOnClickListener(v -> {
final String name = intent.getComponent() != null
? intent.getComponent().flattenToString()
diff --git a/packages/SystemUI/src/com/android/systemui/qs/panels/ui/viewmodel/DetailsViewModel.kt b/packages/SystemUI/src/com/android/systemui/qs/panels/ui/viewmodel/DetailsViewModel.kt
index 3287443f0405..60ca6e6e67a7 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/panels/ui/viewmodel/DetailsViewModel.kt
+++ b/packages/SystemUI/src/com/android/systemui/qs/panels/ui/viewmodel/DetailsViewModel.kt
@@ -23,11 +23,15 @@ import com.android.systemui.dagger.SysUISingleton
import com.android.systemui.plugins.qs.TileDetailsViewModel
import com.android.systemui.qs.pipeline.domain.interactor.CurrentTilesInteractor
import com.android.systemui.qs.pipeline.shared.TileSpec
+import com.android.systemui.shade.domain.interactor.ShadeModeInteractor
import javax.inject.Inject
@SysUISingleton
@Stable
-class DetailsViewModel @Inject constructor(val currentTilesInteractor: CurrentTilesInteractor) {
+class DetailsViewModel @Inject constructor(
+ val currentTilesInteractor: CurrentTilesInteractor,
+ val shadeModeInteractor: ShadeModeInteractor
+) {
/**
* The current active [TileDetailsViewModel]. If it's `null`, it means the qs overlay is not
@@ -52,6 +56,10 @@ class DetailsViewModel @Inject constructor(val currentTilesInteractor: CurrentTi
* @see activeTileDetails
*/
fun onTileClicked(spec: TileSpec?): Boolean {
+ if (!shadeModeInteractor.isDualShade){
+ return false
+ }
+
if (spec == null) {
_activeTileDetails.value = null
return false
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/OWNERS b/packages/SystemUI/src/com/android/systemui/statusbar/notification/OWNERS
index d06f24fdb81b..ba4001014681 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/OWNERS
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/OWNERS
@@ -17,3 +17,4 @@ valiiftime@google.com
yurilin@google.com
per-file MediaNotificationProcessor.java = ethibodeau@google.com
+per-file MagicActionBackgroundDrawable.kt = dupin@google.com
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/BundleEntry.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/BundleEntry.java
index f6535730cf77..8fc6cbe7c9e7 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/BundleEntry.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/BundleEntry.java
@@ -69,10 +69,13 @@ public class BundleEntry extends PipelineEntry {
return mUnmodifiableChildren;
}
+ void clearChildren() {
+ mChildren.clear();
+ }
+
/**
* @return Null because bundles do not have an associated NotificationEntry.
*/
-
@Nullable
@Override
public NotificationEntry getRepresentativeEntry() {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/ShadeListBuilder.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/ShadeListBuilder.java
index 5cea82140692..fe2bd345d559 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/ShadeListBuilder.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/ShadeListBuilder.java
@@ -567,7 +567,7 @@ public class ShadeListBuilder implements Dumpable, PipelineDumpable {
for (BundleEntry be : mIdToBundleEntry.values()) {
be.beginNewAttachState();
- // TODO(b/399736937) Clear bundle children
+ be.clearChildren();
// BundleEntry has not representative summary so we do not need to clear it here.
}
mNotifList.clear();
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/GroupCountCoordinator.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/GroupCountCoordinator.kt
index 2f0701f96f28..3747aba3a109 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/GroupCountCoordinator.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/GroupCountCoordinator.kt
@@ -17,6 +17,7 @@
package com.android.systemui.statusbar.notification.collection.coordinator
import android.util.ArrayMap
+import com.android.systemui.statusbar.notification.collection.BundleEntry
import com.android.systemui.statusbar.notification.collection.GroupEntry
import com.android.systemui.statusbar.notification.collection.PipelineEntry
import com.android.systemui.statusbar.notification.collection.NotifPipeline
@@ -37,9 +38,17 @@ class GroupCountCoordinator @Inject constructor() : Coordinator {
private fun onBeforeFinalizeFilter(entries: List<PipelineEntry>) {
// save untruncated child counts to our internal map
untruncatedChildCounts.clear()
- entries.asSequence().filterIsInstance<GroupEntry>().forEach { groupEntry ->
- untruncatedChildCounts[groupEntry] = groupEntry.children.size
- }
+ entries.asSequence()
+ .flatMap { entry ->
+ when (entry) {
+ is GroupEntry -> listOf(entry)
+ is BundleEntry -> entry.children.filterIsInstance<GroupEntry>()
+ else -> emptyList()
+ }
+ }
+ .forEach { groupEntry ->
+ untruncatedChildCounts[groupEntry] = groupEntry.children.size
+ }
}
private fun onAfterRenderGroup(group: GroupEntry, controller: NotifGroupController) {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/PreparationCoordinator.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/PreparationCoordinator.java
index 1be415d7bf47..20169ef481bf 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/PreparationCoordinator.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/PreparationCoordinator.java
@@ -36,6 +36,7 @@ import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.statusbar.IStatusBarService;
import com.android.systemui.statusbar.notification.collection.BundleEntry;
import com.android.systemui.statusbar.notification.collection.GroupEntry;
+import com.android.systemui.statusbar.notification.collection.ListEntry;
import com.android.systemui.statusbar.notification.collection.PipelineEntry;
import com.android.systemui.statusbar.notification.collection.NotifPipeline;
import com.android.systemui.statusbar.notification.collection.NotificationEntry;
@@ -307,8 +308,15 @@ public class PreparationCoordinator implements Coordinator {
private void inflateAllRequiredViews(List<PipelineEntry> entries) {
for (int i = 0, size = entries.size(); i < size; i++) {
PipelineEntry entry = entries.get(i);
- if (NotificationBundleUi.isEnabled() && entry instanceof BundleEntry) {
- // TODO(b/399738511) Inflate bundle views.
+ if (NotificationBundleUi.isEnabled() && entry instanceof BundleEntry bundleEntry) {
+ for (ListEntry listEntry : bundleEntry.getChildren()) {
+ if (listEntry instanceof GroupEntry groupEntry) {
+ inflateRequiredGroupViews(groupEntry);
+ } else {
+ NotificationEntry notifEntry = (NotificationEntry) listEntry;
+ inflateRequiredNotifViews(notifEntry);
+ }
+ }
} else if (entry instanceof GroupEntry) {
GroupEntry groupEntry = (GroupEntry) entry;
inflateRequiredGroupViews(groupEntry);
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ExpandableView.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ExpandableView.java
index 292f74a65554..f36a0cf51b97 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ExpandableView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ExpandableView.java
@@ -19,6 +19,8 @@ package com.android.systemui.statusbar.notification.row;
import static com.android.systemui.Flags.notificationColorUpdateLogger;
import static com.android.systemui.Flags.physicalNotificationMovement;
+import static java.lang.Math.abs;
+
import android.animation.AnimatorListenerAdapter;
import android.content.Context;
import android.content.res.Configuration;
@@ -29,6 +31,7 @@ import android.util.FloatProperty;
import android.util.IndentingPrintWriter;
import android.util.Log;
import android.view.View;
+import android.view.ViewConfiguration;
import android.view.ViewGroup;
import android.view.ViewParent;
import android.widget.FrameLayout;
@@ -110,14 +113,27 @@ public abstract class ExpandableView extends FrameLayout implements Dumpable, Ro
protected SpringAnimation mMagneticAnimator = new SpringAnimation(
this /* object */, DynamicAnimation.TRANSLATION_X);
+ private int mTouchSlop;
+
protected MagneticRowListener mMagneticRowListener = new MagneticRowListener() {
@Override
- public void setMagneticTranslation(float translation) {
- if (mMagneticAnimator.isRunning()) {
- mMagneticAnimator.animateToFinalPosition(translation);
- } else {
+ public void setMagneticTranslation(float translation, boolean trackEagerly) {
+ if (!mMagneticAnimator.isRunning()) {
setTranslation(translation);
+ return;
+ }
+
+ if (trackEagerly) {
+ float delta = abs(getTranslation() - translation);
+ if (delta > mTouchSlop) {
+ mMagneticAnimator.animateToFinalPosition(translation);
+ } else {
+ mMagneticAnimator.cancel();
+ setTranslation(translation);
+ }
+ } else {
+ mMagneticAnimator.animateToFinalPosition(translation);
}
}
@@ -183,6 +199,7 @@ public abstract class ExpandableView extends FrameLayout implements Dumpable, Ro
private void initDimens() {
mContentShift = getResources().getDimensionPixelSize(
R.dimen.shelf_transform_content_shift);
+ mTouchSlop = ViewConfiguration.get(getContext()).getScaledTouchSlop();
}
@Override
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationMenuRow.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationMenuRow.java
index 977936fa34fc..c03dc279888f 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationMenuRow.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationMenuRow.java
@@ -46,7 +46,6 @@ import com.android.systemui.Flags;
import com.android.systemui.plugins.statusbar.NotificationMenuRowPlugin;
import com.android.systemui.res.R;
import com.android.systemui.statusbar.AlphaOptimizedImageView;
-import com.android.systemui.statusbar.notification.collection.NotificationEntry;
import com.android.systemui.statusbar.notification.people.PeopleNotificationIdentifier;
import com.android.systemui.statusbar.notification.row.NotificationGuts.GutsContent;
import com.android.systemui.statusbar.notification.shared.NotificationBundleUi;
@@ -363,7 +362,9 @@ public class NotificationMenuRow implements NotificationMenuRowPlugin, View.OnCl
final float dismissThreshold = getDismissThreshold();
final boolean snappingToDismiss = delta < -dismissThreshold || delta > dismissThreshold;
if (mSnappingToDismiss != snappingToDismiss) {
- getMenuView().performHapticFeedback(CLOCK_TICK);
+ if (!Flags.magneticNotificationSwipes()) {
+ getMenuView().performHapticFeedback(CLOCK_TICK);
+ }
}
mSnappingToDismiss = snappingToDismiss;
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/MagneticNotificationRowManager.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/MagneticNotificationRowManager.kt
index aa6951715755..48cff7497e3c 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/MagneticNotificationRowManager.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/MagneticNotificationRowManager.kt
@@ -33,12 +33,12 @@ import com.android.systemui.statusbar.notification.row.ExpandableNotificationRow
interface MagneticNotificationRowManager {
/**
- * Set the swipe threshold in pixels. After crossing the threshold, the magnetic target detaches
- * and the magnetic neighbors snap back.
+ * Notifies a change in the device density. The density can be used to compute the values of
+ * thresholds in pixels.
*
- * @param[threshold] Swipe threshold in pixels.
+ * @param[density] The device density.
*/
- fun setSwipeThresholdPx(thresholdPx: Float)
+ fun onDensityChange(density: Float)
/**
* Set the magnetic and roundable targets of a magnetic swipe interaction.
@@ -87,6 +87,9 @@ interface MagneticNotificationRowManager {
*/
fun onMagneticInteractionEnd(row: ExpandableNotificationRow, velocity: Float? = null)
+ /** Determine if the given [ExpandableNotificationRow] has been magnetically detached. */
+ fun isMagneticRowSwipeDetached(row: ExpandableNotificationRow): Boolean
+
/* Reset any roundness that magnetic targets may have */
fun resetRoundness()
@@ -104,12 +107,15 @@ interface MagneticNotificationRowManager {
/** Detaching threshold in dp */
const val MAGNETIC_DETACH_THRESHOLD_DP = 56
+ /** Re-attaching threshold in dp */
+ const val MAGNETIC_ATTACH_THRESHOLD_DP = 40
+
/* An empty implementation of a manager */
@JvmStatic
val Empty: MagneticNotificationRowManager
get() =
object : MagneticNotificationRowManager {
- override fun setSwipeThresholdPx(thresholdPx: Float) {}
+ override fun onDensityChange(density: Float) {}
override fun setMagneticAndRoundableTargets(
swipingRow: ExpandableNotificationRow,
@@ -127,6 +133,10 @@ interface MagneticNotificationRowManager {
velocity: Float?,
) {}
+ override fun isMagneticRowSwipeDetached(
+ row: ExpandableNotificationRow
+ ): Boolean = false
+
override fun resetRoundness() {}
override fun reset() {}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/MagneticNotificationRowManagerImpl.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/MagneticNotificationRowManagerImpl.kt
index 5a23f7cc2861..6e8b2226b4f6 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/MagneticNotificationRowManagerImpl.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/MagneticNotificationRowManagerImpl.kt
@@ -47,6 +47,7 @@ constructor(
private set
private var magneticDetachThreshold = Float.POSITIVE_INFINITY
+ private var magneticAttachThreshold = 0f
// Has the roundable target been set for the magnetic view that is being swiped.
val isSwipedViewRoundableSet: Boolean
@@ -57,13 +58,25 @@ constructor(
SpringForce().setStiffness(DETACH_STIFFNESS).setDampingRatio(DETACH_DAMPING_RATIO)
private val snapForce =
SpringForce().setStiffness(SNAP_BACK_STIFFNESS).setDampingRatio(SNAP_BACK_DAMPING_RATIO)
+ private val attachForce =
+ SpringForce().setStiffness(ATTACH_STIFFNESS).setDampingRatio(ATTACH_DAMPING_RATIO)
// Multiplier applied to the translation of a row while swiped
val swipedRowMultiplier =
MAGNETIC_TRANSLATION_MULTIPLIERS[MAGNETIC_TRANSLATION_MULTIPLIERS.size / 2]
- override fun setSwipeThresholdPx(thresholdPx: Float) {
- magneticDetachThreshold = thresholdPx
+ /**
+ * An offset applied to input translation that increases on subsequent re-attachments of a
+ * detached magnetic view. This helps keep computations consistent when the drag gesture input
+ * and the swiped notification don't share the same origin point after a re-attaching animation.
+ */
+ private var translationOffset = 0f
+
+ override fun onDensityChange(density: Float) {
+ magneticDetachThreshold =
+ density * MagneticNotificationRowManager.MAGNETIC_DETACH_THRESHOLD_DP
+ magneticAttachThreshold =
+ density * MagneticNotificationRowManager.MAGNETIC_ATTACH_THRESHOLD_DP
}
override fun setMagneticAndRoundableTargets(
@@ -72,6 +85,7 @@ constructor(
sectionsManager: NotificationSectionsManager,
) {
if (currentState == State.IDLE) {
+ translationOffset = 0f
updateMagneticAndRoundableTargets(swipingRow, stackScrollLayout, sectionsManager)
currentState = State.TARGETS_SET
} else {
@@ -121,36 +135,36 @@ constructor(
val canTargetBeDismissed =
currentMagneticListeners.swipedListener()?.canRowBeDismissed() ?: false
+ val correctedTranslation = translation - translationOffset
when (currentState) {
State.IDLE -> {
logger.logMagneticRowTranslationNotSet(currentState, row.getLoggingKey())
return false
}
State.TARGETS_SET -> {
- pullTargets(translation, canTargetBeDismissed)
+ pullTargets(correctedTranslation, canTargetBeDismissed)
currentState = State.PULLING
}
State.PULLING -> {
- updateRoundness(translation)
+ updateRoundness(correctedTranslation)
if (canTargetBeDismissed) {
- pullDismissibleRow(translation)
+ pullDismissibleRow(correctedTranslation)
} else {
- pullTargets(translation, canSwipedBeDismissed = false)
+ pullTargets(correctedTranslation, canSwipedBeDismissed = false)
}
}
State.DETACHED -> {
- val swiped = currentMagneticListeners.swipedListener()
- swiped?.setMagneticTranslation(translation)
+ translateDetachedRow(correctedTranslation)
}
}
return true
}
- private fun updateRoundness(translation: Float) {
+ private fun updateRoundness(translation: Float, animate: Boolean = false) {
val normalizedTranslation = abs(swipedRowMultiplier * translation) / magneticDetachThreshold
notificationRoundnessManager.setRoundnessForAffectedViews(
/* roundness */ normalizedTranslation.coerceIn(0f, MAX_PRE_DETACH_ROUNDNESS),
- /* animate */ false,
+ animate,
)
}
@@ -232,7 +246,28 @@ constructor(
)
}
+ private fun translateDetachedRow(translation: Float) {
+ val targetTranslation = swipedRowMultiplier * translation
+ val crossedThreshold = abs(targetTranslation) <= magneticAttachThreshold
+ if (crossedThreshold) {
+ translationOffset += translation
+ updateRoundness(translation = 0f, animate = true)
+ currentMagneticListeners.swipedListener()?.let { attach(it) }
+ currentState = State.PULLING
+ } else {
+ val swiped = currentMagneticListeners.swipedListener()
+ swiped?.setMagneticTranslation(translation, trackEagerly = false)
+ }
+ }
+
+ private fun attach(listener: MagneticRowListener) {
+ listener.cancelMagneticAnimations()
+ listener.triggerMagneticForce(endTranslation = 0f, attachForce)
+ msdlPlayer.playToken(MSDLToken.SWIPE_THRESHOLD_INDICATOR)
+ }
+
override fun onMagneticInteractionEnd(row: ExpandableNotificationRow, velocity: Float?) {
+ translationOffset = 0f
if (row.isSwipedTarget()) {
when (currentState) {
State.PULLING -> {
@@ -254,9 +289,13 @@ constructor(
}
}
+ override fun isMagneticRowSwipeDetached(row: ExpandableNotificationRow): Boolean =
+ row.isSwipedTarget() && currentState == State.DETACHED
+
override fun resetRoundness() = notificationRoundnessManager.clear()
override fun reset() {
+ translationOffset = 0f
currentMagneticListeners.forEach {
it?.cancelMagneticAnimations()
it?.cancelTranslationAnimations()
@@ -300,6 +339,8 @@ constructor(
private const val DETACH_DAMPING_RATIO = 0.95f
private const val SNAP_BACK_STIFFNESS = 550f
private const val SNAP_BACK_DAMPING_RATIO = 0.6f
+ private const val ATTACH_STIFFNESS = 800f
+ private const val ATTACH_DAMPING_RATIO = 0.95f
// Maximum value of corner roundness that gets applied during the pre-detach dragging
private const val MAX_PRE_DETACH_ROUNDNESS = 0.8f
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/MagneticRowListener.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/MagneticRowListener.kt
index 5959ef1e093b..344dab4369f2 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/MagneticRowListener.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/MagneticRowListener.kt
@@ -21,8 +21,17 @@ import androidx.dynamicanimation.animation.SpringForce
/** A listener that responds to magnetic forces applied to an [ExpandableNotificationRow] */
interface MagneticRowListener {
- /** Set a translation due to a magnetic attachment. */
- fun setMagneticTranslation(translation: Float)
+ /**
+ * Set a translation due to a magnetic attachment.
+ *
+ * If a magnetic animation is running, [trackEagerly] decides if the new translation is applied
+ * immediately or if the animation finishes first. When applying the translation immediately,
+ * the change in translation must be greater than a touch slop threshold.
+ *
+ * @param[translation] Incoming gesture translation.
+ * @param[trackEagerly] Whether we eagerly track the incoming translation or not.
+ */
+ fun setMagneticTranslation(translation: Float, trackEagerly: Boolean = true)
/**
* Trigger the magnetic behavior when the row detaches or snaps back from its magnetic
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayoutController.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayoutController.java
index f3d8ee245540..612c19fc6696 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayoutController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayoutController.java
@@ -486,15 +486,22 @@ public class NotificationStackScrollLayoutController implements Dumpable {
}
@Override
+ public boolean isMagneticViewDetached(View view) {
+ if (view instanceof ExpandableNotificationRow row) {
+ return mMagneticNotificationRowManager.isMagneticRowSwipeDetached(row);
+ } else {
+ return false;
+ }
+ }
+
+ @Override
public float getTotalTranslationLength(View animView) {
return mView.getTotalTranslationLength(animView);
}
@Override
public void onDensityScaleChange(float density) {
- mMagneticNotificationRowManager.setSwipeThresholdPx(
- density * MagneticNotificationRowManager.MAGNETIC_DETACH_THRESHOLD_DP
- );
+ mMagneticNotificationRowManager.onDensityChange(density);
}
@Override
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationSwipeHelper.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationSwipeHelper.java
index c5a846e1da05..5105e55b0a5c 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationSwipeHelper.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationSwipeHelper.java
@@ -255,12 +255,13 @@ class NotificationSwipeHelper extends SwipeHelper implements NotificationSwipeAc
int menuSnapTarget = menuRow.getMenuSnapTarget();
boolean isNonFalseMenuRevealingGesture =
isMenuRevealingGestureAwayFromMenu && !isFalseGesture();
+ boolean isMagneticViewDetached = mCallback.isMagneticViewDetached(animView);
if ((isNonDismissGestureTowardsMenu || isNonFalseMenuRevealingGesture)
&& menuSnapTarget != 0) {
// Menu has not been snapped to previously and this is menu revealing gesture
snapOpen(animView, menuSnapTarget, velocity);
menuRow.onSnapOpen();
- } else if (isDismissGesture && !gestureTowardsMenu) {
+ } else if (isDismissGesture && (!gestureTowardsMenu || isMagneticViewDetached)) {
dismiss(animView, velocity);
menuRow.onDismiss();
} else {
@@ -272,6 +273,7 @@ class NotificationSwipeHelper extends SwipeHelper implements NotificationSwipeAc
private void handleSwipeFromOpenState(MotionEvent ev, View animView, float velocity,
NotificationMenuRowPlugin menuRow) {
boolean isDismissGesture = isDismissGesture(ev);
+ boolean isMagneticViewDetached = mCallback.isMagneticViewDetached(animView);
final boolean withinSnapMenuThreshold =
menuRow.isWithinSnapMenuThreshold();
@@ -280,7 +282,7 @@ class NotificationSwipeHelper extends SwipeHelper implements NotificationSwipeAc
// Haven't moved enough to unsnap from the menu
menuRow.onSnapOpen();
snapOpen(animView, menuRow.getMenuSnapTarget(), velocity);
- } else if (isDismissGesture && !menuRow.shouldSnapBack()) {
+ } else if (isDismissGesture && (!menuRow.shouldSnapBack() || isMagneticViewDetached)) {
// Only dismiss if we're not moving towards the menu
dismiss(animView, velocity);
menuRow.onDismiss();
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/qs/panels/ui/viewmodel/DetailsViewModelKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/qs/panels/ui/viewmodel/DetailsViewModelKosmos.kt
index dc22905ba320..56fd270dffb7 100644
--- a/packages/SystemUI/tests/utils/src/com/android/systemui/qs/panels/ui/viewmodel/DetailsViewModelKosmos.kt
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/qs/panels/ui/viewmodel/DetailsViewModelKosmos.kt
@@ -18,5 +18,11 @@ package com.android.systemui.qs.panels.ui.viewmodel
import com.android.systemui.kosmos.Kosmos
import com.android.systemui.qs.pipeline.domain.interactor.currentTilesInteractor
+import com.android.systemui.shade.domain.interactor.shadeModeInteractor
-val Kosmos.detailsViewModel by Kosmos.Fixture { DetailsViewModel(currentTilesInteractor) }
+val Kosmos.detailsViewModel by Kosmos.Fixture {
+ DetailsViewModel(
+ currentTilesInteractor,
+ shadeModeInteractor
+ )
+}
diff --git a/services/accessibility/java/com/android/server/accessibility/HearingDevicePhoneCallNotificationController.java b/services/accessibility/java/com/android/server/accessibility/HearingDevicePhoneCallNotificationController.java
index 94cef418b6c8..edcf5748a8fc 100644
--- a/services/accessibility/java/com/android/server/accessibility/HearingDevicePhoneCallNotificationController.java
+++ b/services/accessibility/java/com/android/server/accessibility/HearingDevicePhoneCallNotificationController.java
@@ -17,6 +17,7 @@
package com.android.server.accessibility;
import android.Manifest;
+import android.annotation.CallbackExecutor;
import android.annotation.NonNull;
import android.annotation.SuppressLint;
import android.app.Notification;
@@ -149,11 +150,7 @@ public class HearingDevicePhoneCallNotificationController {
}
if (state == TelephonyManager.CALL_STATE_IDLE) {
- if (mIsCommDeviceChangedRegistered) {
- mIsCommDeviceChangedRegistered = false;
- mAudioManager.removeOnCommunicationDeviceChangedListener(
- mCommDeviceChangedListener);
- }
+ removeOnCommunicationDeviceChangedListenerIfNeeded(mCommDeviceChangedListener);
dismissNotificationIfNeeded();
if (mHearingDevice != null) {
@@ -172,10 +169,8 @@ public class HearingDevicePhoneCallNotificationController {
if (mHearingDevice != null) {
showNotificationIfNeeded();
} else {
- mAudioManager.addOnCommunicationDeviceChangedListener(
- mCommDeviceChangedExecutor,
+ addOnCommunicationDeviceChangedListenerIfNeeded(mCommDeviceChangedExecutor,
mCommDeviceChangedListener);
- mIsCommDeviceChangedRegistered = true;
}
} else {
mHearingDevice = getSupportedInputHearingDeviceInfo(
@@ -187,6 +182,27 @@ public class HearingDevicePhoneCallNotificationController {
}
}
+ private void addOnCommunicationDeviceChangedListenerIfNeeded(
+ @NonNull @CallbackExecutor Executor executor,
+ @NonNull AudioManager.OnCommunicationDeviceChangedListener listener) {
+ if (mIsCommDeviceChangedRegistered) {
+ return;
+ }
+
+ mIsCommDeviceChangedRegistered = true;
+ mAudioManager.addOnCommunicationDeviceChangedListener(executor, listener);
+ }
+
+ private void removeOnCommunicationDeviceChangedListenerIfNeeded(
+ @NonNull AudioManager.OnCommunicationDeviceChangedListener listener) {
+ if (!mIsCommDeviceChangedRegistered) {
+ return;
+ }
+
+ mAudioManager.removeOnCommunicationDeviceChangedListener(listener);
+ mIsCommDeviceChangedRegistered = false;
+ }
+
private void showNotificationIfNeeded() {
if (mIsNotificationShown) {
return;
diff --git a/services/core/java/com/android/server/adb/AdbDebuggingManager.java b/services/core/java/com/android/server/adb/AdbDebuggingManager.java
index a4cbf420b93b..193d82743a34 100644
--- a/services/core/java/com/android/server/adb/AdbDebuggingManager.java
+++ b/services/core/java/com/android/server/adb/AdbDebuggingManager.java
@@ -788,7 +788,6 @@ public class AdbDebuggingManager {
// === Messages we can send to adbd ===========
static final String MSG_DISCONNECT_DEVICE = "DD";
- static final String MSG_DISABLE_ADBDWIFI = "DA";
@Nullable @VisibleForTesting AdbKeyStore mAdbKeyStore;
@@ -1093,9 +1092,6 @@ public class AdbDebuggingManager {
setAdbConnectionInfo(null);
mContext.unregisterReceiver(mBroadcastReceiver);
- if (mThread != null) {
- mThread.sendResponse(MSG_DISABLE_ADBDWIFI);
- }
onAdbdWifiServerDisconnected(-1);
stopAdbDebuggingThread();
break;
diff --git a/services/core/java/com/android/server/audio/AudioService.java b/services/core/java/com/android/server/audio/AudioService.java
index bf7f1946531c..6b3661a2a004 100644
--- a/services/core/java/com/android/server/audio/AudioService.java
+++ b/services/core/java/com/android/server/audio/AudioService.java
@@ -929,7 +929,8 @@ public class AudioService extends IAudioService.Stub
private final Object mAbsoluteVolumeDeviceInfoMapLock = new Object();
// Devices where the framework sends a full scale audio signal, and controls the volume of
// the external audio system separately.
- // For possible volume behaviors, see {@link AudioManager.AbsoluteDeviceVolumeBehavior}.
+ // For possible volume behaviors, see
+ // {@link AudioDeviceVolumeManager.AbsoluteDeviceVolumeBehavior}.
@GuardedBy("mAbsoluteVolumeDeviceInfoMapLock")
Map<Integer, AbsoluteVolumeDeviceInfo> mAbsoluteVolumeDeviceInfoMap = new ArrayMap<>();
@@ -942,7 +943,7 @@ public class AudioService extends IAudioService.Stub
private final List<VolumeInfo> mVolumeInfos;
private final IAudioDeviceVolumeDispatcher mCallback;
private final boolean mHandlesVolumeAdjustment;
- private @AudioManager.AbsoluteDeviceVolumeBehavior int mDeviceVolumeBehavior;
+ private @AudioDeviceVolumeManager.AbsoluteDeviceVolumeBehavior int mDeviceVolumeBehavior;
private AbsoluteVolumeDeviceInfo(
AudioService parent,
@@ -950,7 +951,7 @@ public class AudioService extends IAudioService.Stub
List<VolumeInfo> volumeInfos,
IAudioDeviceVolumeDispatcher callback,
boolean handlesVolumeAdjustment,
- @AudioManager.AbsoluteDeviceVolumeBehavior int behavior) {
+ @AudioDeviceVolumeManager.AbsoluteDeviceVolumeBehavior int behavior) {
this.mParent = parent;
this.mDevice = device;
this.mVolumeInfos = volumeInfos;
@@ -8173,7 +8174,7 @@ public class AudioService extends IAudioService.Stub
IAudioDeviceVolumeDispatcher cb, String packageName,
AudioDeviceAttributes device, List<VolumeInfo> volumes,
boolean handlesVolumeAdjustment,
- @AudioManager.AbsoluteDeviceVolumeBehavior int deviceVolumeBehavior) {
+ @AudioDeviceVolumeManager.AbsoluteDeviceVolumeBehavior int deviceVolumeBehavior) {
// verify permissions
if (mContext.checkCallingOrSelfPermission(MODIFY_AUDIO_ROUTING)
!= PackageManager.PERMISSION_GRANTED
@@ -8240,12 +8241,13 @@ public class AudioService extends IAudioService.Stub
@android.annotation.EnforcePermission(anyOf = {
MODIFY_AUDIO_ROUTING, MODIFY_AUDIO_SETTINGS_PRIVILEGED })
public void setDeviceVolumeBehavior(@NonNull AudioDeviceAttributes device,
- @AudioManager.DeviceVolumeBehavior int deviceVolumeBehavior, @Nullable String pkgName) {
+ @AudioDeviceVolumeManager.DeviceVolumeBehavior int deviceVolumeBehavior,
+ @Nullable String pkgName) {
// verify permissions
super.setDeviceVolumeBehavior_enforcePermission();
// verify arguments
Objects.requireNonNull(device);
- AudioManager.enforceValidVolumeBehavior(deviceVolumeBehavior);
+ AudioDeviceVolumeManager.enforceValidVolumeBehavior(deviceVolumeBehavior);
device = retrieveBluetoothAddress(device);
@@ -8268,7 +8270,8 @@ public class AudioService extends IAudioService.Stub
}
private void setDeviceVolumeBehaviorInternal(@NonNull AudioDeviceAttributes device,
- @AudioManager.DeviceVolumeBehavior int deviceVolumeBehavior, @NonNull String caller) {
+ @AudioDeviceVolumeManager.DeviceVolumeBehavior int deviceVolumeBehavior,
+ @NonNull String caller) {
int audioSystemDeviceOut = device.getInternalType();
boolean volumeBehaviorChanged = false;
// update device masks based on volume behavior
@@ -8323,7 +8326,7 @@ public class AudioService extends IAudioService.Stub
@android.annotation.EnforcePermission(anyOf = {
MODIFY_AUDIO_ROUTING, QUERY_AUDIO_STATE, MODIFY_AUDIO_SETTINGS_PRIVILEGED
})
- public @AudioManager.DeviceVolumeBehavior
+ public @AudioDeviceVolumeManager.DeviceVolumeBehavior
int getDeviceVolumeBehavior(@NonNull AudioDeviceAttributes device) {
// verify permissions
super.getDeviceVolumeBehavior_enforcePermission();
@@ -8335,7 +8338,7 @@ public class AudioService extends IAudioService.Stub
return getDeviceVolumeBehaviorInt(device);
}
- private @AudioManager.DeviceVolumeBehavior
+ private @AudioDeviceVolumeManager.DeviceVolumeBehavior
int getDeviceVolumeBehaviorInt(@NonNull AudioDeviceAttributes device) {
// Get the internal type set by the AudioDeviceAttributes constructor which is always more
// exact (avoids double conversions) than a conversion from SDK type via
@@ -15354,7 +15357,8 @@ public class AudioService extends IAudioService.Stub
/**
* Returns whether the input device uses absolute volume behavior, including its variants.
- * For included volume behaviors, see {@link AudioManager.AbsoluteDeviceVolumeBehavior}.
+ * For included volume behaviors, see
+ * {@link AudioDeviceVolumeManager.AbsoluteDeviceVolumeBehavior}.
* <p>This is distinct from Bluetooth A2DP absolute volume behavior
* ({@link #isA2dpAbsoluteVolumeDevice}).
*/
@@ -15381,7 +15385,7 @@ public class AudioService extends IAudioService.Stub
}
private void persistDeviceVolumeBehavior(int deviceType,
- @AudioManager.DeviceVolumeBehavior int deviceVolumeBehavior) {
+ @AudioDeviceVolumeManager.DeviceVolumeBehavior int deviceVolumeBehavior) {
if (DEBUG_VOL) {
Log.d(TAG, "Persisting Volume Behavior for DeviceType: " + deviceType);
}
@@ -15396,7 +15400,7 @@ public class AudioService extends IAudioService.Stub
}
}
- @AudioManager.DeviceVolumeBehaviorState
+ @AudioDeviceVolumeManager.DeviceVolumeBehaviorState
private int retrieveStoredDeviceVolumeBehavior(int deviceType) {
return mSettings.getSystemIntForUser(mContentResolver,
getSettingsNameForDeviceVolumeBehavior(deviceType),
diff --git a/services/core/java/com/android/server/hdmi/AudioDeviceVolumeManagerWrapper.java b/services/core/java/com/android/server/hdmi/AudioDeviceVolumeManagerWrapper.java
index ab86433ca50d..62c3dbd3df8c 100644
--- a/services/core/java/com/android/server/hdmi/AudioDeviceVolumeManagerWrapper.java
+++ b/services/core/java/com/android/server/hdmi/AudioDeviceVolumeManagerWrapper.java
@@ -23,6 +23,7 @@ import android.annotation.CallbackExecutor;
import android.annotation.NonNull;
import android.media.AudioDeviceAttributes;
import android.media.AudioDeviceVolumeManager;
+import android.media.AudioManager;
import android.media.VolumeInfo;
import java.util.concurrent.Executor;
@@ -53,7 +54,7 @@ public interface AudioDeviceVolumeManagerWrapper {
/**
* Wrapper for {@link AudioDeviceVolumeManager#setDeviceAbsoluteVolumeBehavior(
- * AudioDeviceAttributes, VolumeInfo, Executor, OnAudioDeviceVolumeChangedListener, boolean)}
+ * AudioDeviceAttributes, VolumeInfo, boolean, Executor, OnAudioDeviceVolumeChangedListener)}
*/
void setDeviceAbsoluteVolumeBehavior(
@NonNull AudioDeviceAttributes device,
@@ -64,7 +65,7 @@ public interface AudioDeviceVolumeManagerWrapper {
/**
* Wrapper for {@link AudioDeviceVolumeManager#setDeviceAbsoluteVolumeAdjustOnlyBehavior(
- * AudioDeviceAttributes, VolumeInfo, Executor, OnAudioDeviceVolumeChangedListener, boolean)}
+ * AudioDeviceAttributes, VolumeInfo, boolean, Executor, OnAudioDeviceVolumeChangedListener)}
*/
void setDeviceAbsoluteVolumeAdjustOnlyBehavior(
@NonNull AudioDeviceAttributes device,
@@ -72,4 +73,16 @@ public interface AudioDeviceVolumeManagerWrapper {
boolean handlesVolumeAdjustment,
@NonNull @CallbackExecutor Executor executor,
@NonNull AudioDeviceVolumeManager.OnAudioDeviceVolumeChangedListener vclistener);
+
+ /**
+ * Wraps {@link AudioDeviceVolumeManager#getDeviceVolumeBehavior(AudioDeviceAttributes)}
+ */
+ @AudioManager.DeviceVolumeBehavior
+ int getDeviceVolumeBehavior(@NonNull AudioDeviceAttributes device);
+
+ /**
+ * Wraps {@link AudioDeviceVolumeManager#setDeviceVolumeBehavior(AudioDeviceAttributes, int)}
+ */
+ void setDeviceVolumeBehavior(@NonNull AudioDeviceAttributes device,
+ @AudioDeviceVolumeManager.DeviceVolumeBehavior int deviceVolumeBehavior);
}
diff --git a/services/core/java/com/android/server/hdmi/AudioManagerWrapper.java b/services/core/java/com/android/server/hdmi/AudioManagerWrapper.java
index fd4dd516fd51..6d01e2da3e9d 100644
--- a/services/core/java/com/android/server/hdmi/AudioManagerWrapper.java
+++ b/services/core/java/com/android/server/hdmi/AudioManagerWrapper.java
@@ -85,18 +85,6 @@ public interface AudioManagerWrapper {
void setWiredDeviceConnectionState(int device, int state, String address, String name);
/**
- * Wraps {@link AudioManager#getDeviceVolumeBehavior(AudioDeviceAttributes)}
- */
- @AudioManager.DeviceVolumeBehavior
- int getDeviceVolumeBehavior(@NonNull AudioDeviceAttributes device);
-
- /**
- * Wraps {@link AudioManager#setDeviceVolumeBehavior(AudioDeviceAttributes, int)}
- */
- void setDeviceVolumeBehavior(@NonNull AudioDeviceAttributes device,
- @AudioManager.DeviceVolumeBehavior int deviceVolumeBehavior);
-
- /**
* Wraps {@link AudioManager#getDevicesForAttributes(AudioAttributes)}
*/
@NonNull
diff --git a/services/core/java/com/android/server/hdmi/DefaultAudioDeviceVolumeManagerWrapper.java b/services/core/java/com/android/server/hdmi/DefaultAudioDeviceVolumeManagerWrapper.java
index 10cbb00d2398..02d8579f738f 100644
--- a/services/core/java/com/android/server/hdmi/DefaultAudioDeviceVolumeManagerWrapper.java
+++ b/services/core/java/com/android/server/hdmi/DefaultAudioDeviceVolumeManagerWrapper.java
@@ -16,11 +16,14 @@
package com.android.server.hdmi;
+import static android.media.audio.Flags.unifyAbsoluteVolumeManagement;
+
import android.annotation.CallbackExecutor;
import android.annotation.NonNull;
import android.content.Context;
import android.media.AudioDeviceAttributes;
import android.media.AudioDeviceVolumeManager;
+import android.media.AudioManager;
import android.media.VolumeInfo;
import java.util.concurrent.Executor;
@@ -38,9 +41,11 @@ public class DefaultAudioDeviceVolumeManagerWrapper
private static final String TAG = "AudioDeviceVolumeManagerWrapper";
private final AudioDeviceVolumeManager mAudioDeviceVolumeManager;
+ private final AudioManager mAudioManager;
public DefaultAudioDeviceVolumeManagerWrapper(Context context) {
mAudioDeviceVolumeManager = new AudioDeviceVolumeManager(context);
+ mAudioManager = context.getSystemService(AudioManager.class);
}
@Override
@@ -78,4 +83,24 @@ public class DefaultAudioDeviceVolumeManagerWrapper
mAudioDeviceVolumeManager.setDeviceAbsoluteVolumeAdjustOnlyBehavior(device, volume,
handlesVolumeAdjustment, executor, vclistener);
}
+
+ @Override
+ @AudioDeviceVolumeManager.DeviceVolumeBehavior
+ public int getDeviceVolumeBehavior(@NonNull AudioDeviceAttributes device) {
+ if (!unifyAbsoluteVolumeManagement()) {
+ int deviceBehavior = mAudioManager.getDeviceVolumeBehavior(device);
+ return deviceBehavior;
+ }
+ return mAudioDeviceVolumeManager.getDeviceVolumeBehavior(device);
+ }
+
+ @Override
+ public void setDeviceVolumeBehavior(@NonNull AudioDeviceAttributes device,
+ @AudioDeviceVolumeManager.DeviceVolumeBehavior int deviceVolumeBehavior) {
+ if (!unifyAbsoluteVolumeManagement()) {
+ int deviceBehavior = deviceVolumeBehavior;
+ mAudioManager.setDeviceVolumeBehavior(device, deviceBehavior);
+ }
+ mAudioDeviceVolumeManager.setDeviceVolumeBehavior(device, deviceVolumeBehavior);
+ }
}
diff --git a/services/core/java/com/android/server/hdmi/DefaultAudioManagerWrapper.java b/services/core/java/com/android/server/hdmi/DefaultAudioManagerWrapper.java
index 061e145c27f3..662715420ec6 100644
--- a/services/core/java/com/android/server/hdmi/DefaultAudioManagerWrapper.java
+++ b/services/core/java/com/android/server/hdmi/DefaultAudioManagerWrapper.java
@@ -94,18 +94,6 @@ public class DefaultAudioManagerWrapper implements AudioManagerWrapper {
}
@Override
- @AudioManager.DeviceVolumeBehavior
- public int getDeviceVolumeBehavior(@NonNull AudioDeviceAttributes device) {
- return mAudioManager.getDeviceVolumeBehavior(device);
- }
-
- @Override
- public void setDeviceVolumeBehavior(@NonNull AudioDeviceAttributes device,
- @AudioManager.DeviceVolumeBehavior int deviceVolumeBehavior) {
- mAudioManager.setDeviceVolumeBehavior(device, deviceVolumeBehavior);
- }
-
- @Override
@NonNull
public List<AudioDeviceAttributes> getDevicesForAttributes(
@NonNull AudioAttributes attributes) {
diff --git a/services/core/java/com/android/server/hdmi/HdmiControlService.java b/services/core/java/com/android/server/hdmi/HdmiControlService.java
index fdd0ef2f90e1..41b0b4dc716a 100644
--- a/services/core/java/com/android/server/hdmi/HdmiControlService.java
+++ b/services/core/java/com/android/server/hdmi/HdmiControlService.java
@@ -4595,7 +4595,7 @@ public class HdmiControlService extends SystemService {
* Wrapper for {@link AudioManager#getDeviceVolumeBehavior} that takes advantage of cached
* results for the volume behaviors of HDMI audio devices.
*/
- @AudioManager.DeviceVolumeBehavior
+ @AudioDeviceVolumeManager.DeviceVolumeBehavior
private int getDeviceVolumeBehavior(AudioDeviceAttributes device) {
if (AVB_AUDIO_OUTPUT_DEVICES.contains(device)) {
synchronized (mLock) {
@@ -4604,7 +4604,7 @@ public class HdmiControlService extends SystemService {
}
}
}
- return getAudioManager().getDeviceVolumeBehavior(device);
+ return getAudioDeviceVolumeManager().getDeviceVolumeBehavior(device);
}
/**
@@ -4695,7 +4695,7 @@ public class HdmiControlService extends SystemService {
// Condition 3: All AVB-capable audio outputs already use full/absolute volume behavior
// We only need to check the first AVB-capable audio output because only TV panels
// have more than one of them, and they always have the same volume behavior.
- @AudioManager.DeviceVolumeBehavior int currentVolumeBehavior =
+ @AudioDeviceVolumeManager.DeviceVolumeBehavior int currentVolumeBehavior =
getDeviceVolumeBehavior(getAvbCapableAudioOutputDevices().get(0));
boolean alreadyUsingFullOrAbsoluteVolume =
FULL_AND_ABSOLUTE_VOLUME_BEHAVIORS.contains(currentVolumeBehavior);
@@ -4719,7 +4719,8 @@ public class HdmiControlService extends SystemService {
// Condition 5: The System Audio device supports <Set Audio Volume Level>
switch (systemAudioDeviceInfo.getDeviceFeatures().getSetAudioVolumeLevelSupport()) {
case DeviceFeatures.FEATURE_SUPPORTED:
- if (currentVolumeBehavior != AudioManager.DEVICE_VOLUME_BEHAVIOR_ABSOLUTE) {
+ if (currentVolumeBehavior
+ != AudioDeviceVolumeManager.DEVICE_VOLUME_BEHAVIOR_ABSOLUTE) {
// Start an action that will call enableAbsoluteVolumeBehavior
// once the System Audio device sends <Report Audio Status>
localCecDevice.startNewAvbAudioStatusAction(
@@ -4731,13 +4732,15 @@ public class HdmiControlService extends SystemService {
// This allows the device to display numeric volume UI for the System Audio device.
if (tv() != null && mNumericSoundbarVolumeUiOnTvFeatureFlagEnabled) {
if (currentVolumeBehavior
- != AudioManager.DEVICE_VOLUME_BEHAVIOR_ABSOLUTE_ADJUST_ONLY) {
+ != AudioDeviceVolumeManager
+ .DEVICE_VOLUME_BEHAVIOR_ABSOLUTE_ADJUST_ONLY) {
// If we're currently using absolute volume behavior, switch to full volume
// behavior until we successfully adopt adjust-only absolute volume behavior
- if (currentVolumeBehavior == AudioManager.DEVICE_VOLUME_BEHAVIOR_ABSOLUTE) {
+ if (currentVolumeBehavior
+ == AudioDeviceVolumeManager.DEVICE_VOLUME_BEHAVIOR_ABSOLUTE) {
for (AudioDeviceAttributes device : getAvbCapableAudioOutputDevices()) {
- getAudioManager().setDeviceVolumeBehavior(device,
- AudioManager.DEVICE_VOLUME_BEHAVIOR_FULL);
+ getAudioDeviceVolumeManager().setDeviceVolumeBehavior(device,
+ AudioDeviceVolumeManager.DEVICE_VOLUME_BEHAVIOR_FULL);
}
}
// Start an action that will call enableAbsoluteVolumeBehavior
@@ -4750,7 +4753,8 @@ public class HdmiControlService extends SystemService {
}
return;
case DeviceFeatures.FEATURE_SUPPORT_UNKNOWN:
- if (currentVolumeBehavior == AudioManager.DEVICE_VOLUME_BEHAVIOR_ABSOLUTE) {
+ if (currentVolumeBehavior
+ == AudioDeviceVolumeManager.DEVICE_VOLUME_BEHAVIOR_ABSOLUTE) {
switchToFullVolumeBehavior();
}
localCecDevice.querySetAudioVolumeLevelSupport(
@@ -4773,8 +4777,8 @@ public class HdmiControlService extends SystemService {
for (AudioDeviceAttributes device : getAvbCapableAudioOutputDevices()) {
if (ABSOLUTE_VOLUME_BEHAVIORS.contains(getDeviceVolumeBehavior(device))) {
- getAudioManager().setDeviceVolumeBehavior(device,
- AudioManager.DEVICE_VOLUME_BEHAVIOR_FULL);
+ getAudioDeviceVolumeManager().setDeviceVolumeBehavior(device,
+ AudioDeviceVolumeManager.DEVICE_VOLUME_BEHAVIOR_FULL);
}
}
}
diff --git a/services/core/java/com/android/server/pm/UserManagerService.java b/services/core/java/com/android/server/pm/UserManagerService.java
index 233b577e1c61..33a7e7476cf6 100644
--- a/services/core/java/com/android/server/pm/UserManagerService.java
+++ b/services/core/java/com/android/server/pm/UserManagerService.java
@@ -7724,6 +7724,7 @@ public class UserManagerService extends IUserManager.Stub {
pw.print(" Has profile owner: ");
pw.println(mIsUserManaged.get(userId));
+
pw.println(" Restrictions:");
synchronized (mRestrictionsLock) {
UserRestrictionsUtils.dumpRestrictions(
@@ -7756,6 +7757,9 @@ public class UserManagerService extends IUserManager.Stub {
}
}
+ pw.print(" Can have profile: ");
+ pw.println(userInfo.canHaveProfile());
+
if (userData.userProperties != null) {
userData.userProperties.println(pw, " ");
}
diff --git a/services/core/java/com/android/server/wallpaper/WallpaperManagerInternal.java b/services/core/java/com/android/server/wallpaper/WallpaperManagerInternal.java
index f413fe33c3f2..58f34d0404d0 100644
--- a/services/core/java/com/android/server/wallpaper/WallpaperManagerInternal.java
+++ b/services/core/java/com/android/server/wallpaper/WallpaperManagerInternal.java
@@ -36,7 +36,4 @@ public abstract class WallpaperManagerInternal {
/** Notifies when the screen starts turning on and is not yet visible to the user. */
public abstract void onScreenTurningOn(int displayId);
-
- /** Notifies when the keyguard is going away. Sent right after the bouncer is gone. */
- public abstract void onKeyguardGoingAway();
}
diff --git a/services/core/java/com/android/server/wallpaper/WallpaperManagerService.java b/services/core/java/com/android/server/wallpaper/WallpaperManagerService.java
index e7da33d50b27..274175aa71ba 100644
--- a/services/core/java/com/android/server/wallpaper/WallpaperManagerService.java
+++ b/services/core/java/com/android/server/wallpaper/WallpaperManagerService.java
@@ -22,6 +22,7 @@ import static android.Manifest.permission.READ_WALLPAPER_INTERNAL;
import static android.app.ActivityManager.RunningAppProcessInfo.IMPORTANCE_FOREGROUND;
import static android.app.Flags.fixWallpaperChanged;
import static android.app.Flags.liveWallpaperContentHandling;
+import static android.app.Flags.notifyKeyguardEvents;
import static android.app.Flags.removeNextWallpaperComponent;
import static android.app.WallpaperManager.COMMAND_REAPPLY;
import static android.app.WallpaperManager.FLAG_LOCK;
@@ -1709,8 +1710,32 @@ public class WallpaperManagerService extends IWallpaperManager.Stub
mWallpaperDataParser = new WallpaperDataParser(mContext, mWallpaperDisplayHelper,
mWallpaperCropper);
LocalServices.addService(WallpaperManagerInternal.class, new LocalService());
+
+ LocalServices.getService(ActivityTaskManagerInternal.class)
+ .registerScreenObserver(mKeyguardObserver);
+
}
+ private final ActivityTaskManagerInternal.ScreenObserver mKeyguardObserver =
+ new ActivityTaskManagerInternal.ScreenObserver() {
+ @Override
+ public void onKeyguardStateChanged(boolean isShowing) {
+ if (!notifyKeyguardEvents()) {
+ return;
+ }
+ if (isShowing) {
+ notifyKeyguardAppearing();
+ } else {
+ notifyKeyguardGoingAway();
+ }
+ }
+
+ @Override
+ public void onKeyguardGoingAway() {
+ notifyKeyguardGoingAway();
+ }
+ };
+
private final class LocalService extends WallpaperManagerInternal {
@Override
public void onDisplayAddSystemDecorations(int displayId) {
@@ -1733,11 +1758,6 @@ public class WallpaperManagerService extends IWallpaperManager.Stub
public void onScreenTurningOn(int displayId) {
notifyScreenTurningOn(displayId);
}
-
- @Override
- public void onKeyguardGoingAway() {
- notifyKeyguardGoingAway();
- }
}
void initialize() {
@@ -2571,6 +2591,18 @@ public class WallpaperManagerService extends IWallpaperManager.Stub
return mContext.checkCallingOrSelfPermission(permission) == PERMISSION_GRANTED;
}
+ private boolean hasPermission(WallpaperData data, String permission) {
+ try {
+ return PackageManager.PERMISSION_GRANTED == mIPackageManager.checkPermission(
+ permission,
+ data.getComponent().getPackageName(),
+ data.userId);
+ } catch (RemoteException e) {
+ Slog.e(TAG, "Failed to check wallpaper service permission", e);
+ return false;
+ }
+ }
+
private boolean hasAppOpPermission(String permission, int callingUid, String callingPackage,
String attributionTag, String message) {
final String op = AppOpsManager.permissionToOp(permission);
@@ -2873,16 +2905,37 @@ public class WallpaperManagerService extends IWallpaperManager.Stub
* Propagate a keyguard going away event to the wallpaper engine.
*/
private void notifyKeyguardGoingAway() {
+ dispatchKeyguardCommand(WallpaperManager.COMMAND_KEYGUARD_GOING_AWAY);
+ }
+
+ /**
+ * Propagate a keyguard appearing event to the wallpaper engine.
+ */
+ private void notifyKeyguardAppearing() {
+ dispatchKeyguardCommand(WallpaperManager.COMMAND_KEYGUARD_APPEARING);
+ }
+
+ /**
+ * Propagate a keyguard-related event to the wallpaper engine.
+ *
+ * When the flag below is enabled, the event will only be dispatched in case the recipient
+ * has {@link android.Manifest.pertmission.SUBSCRIBE_TO_KEYGUARD_LOCKED_STATE} permission.
+ */
+ private void dispatchKeyguardCommand(String command) {
synchronized (mLock) {
for (WallpaperData data : getActiveWallpapers()) {
+ if (notifyKeyguardEvents() && !hasPermission(
+ data, android.Manifest.permission.SUBSCRIBE_TO_KEYGUARD_LOCKED_STATE)) {
+ continue;
+ }
+
data.connection.forEachDisplayConnector(displayConnector -> {
if (displayConnector.mEngine != null) {
try {
displayConnector.mEngine.dispatchWallpaperCommand(
- WallpaperManager.COMMAND_KEYGUARD_GOING_AWAY,
- -1, -1, -1, new Bundle());
+ command, -1, -1, -1, new Bundle());
} catch (RemoteException e) {
- Slog.w(TAG, "Failed to notify that the keyguard is going away", e);
+ Slog.w(TAG, "Failed to dispatch wallpaper command: " + command, e);
}
}
});
diff --git a/services/core/java/com/android/server/wm/AbsAppSnapshotController.java b/services/core/java/com/android/server/wm/AbsAppSnapshotController.java
index a731bf7c64b3..70fc6bace868 100644
--- a/services/core/java/com/android/server/wm/AbsAppSnapshotController.java
+++ b/services/core/java/com/android/server/wm/AbsAppSnapshotController.java
@@ -82,6 +82,7 @@ abstract class AbsAppSnapshotController<TYPE extends WindowContainer,
*/
@VisibleForTesting
static final int SNAPSHOT_MODE_NONE = 2;
+ static final float THEME_SNAPSHOT_MIN_Length = 128.0f;
protected final WindowManagerService mService;
protected final float mHighResSnapshotScale;
@@ -436,14 +437,21 @@ abstract class AbsAppSnapshotController<TYPE extends WindowContainer,
final Rect taskBounds = source.getBounds();
final InsetsState insetsState = mainWindow.getInsetsStateWithVisibilityOverride();
final Rect systemBarInsets = getSystemBarInsets(mainWindow.getFrame(), insetsState);
+ final int taskWidth = taskBounds.width();
+ final int taskHeight = taskBounds.height();
+ float scale = mHighResSnapshotScale;
+ if (Flags.reduceTaskSnapshotMemoryUsage()) {
+ final int minLength = Math.min(taskWidth, taskHeight);
+ if (THEME_SNAPSHOT_MIN_Length < minLength) {
+ scale = Math.min(THEME_SNAPSHOT_MIN_Length / minLength, scale);
+ }
+ }
final SnapshotDrawerUtils.SystemBarBackgroundPainter
decorPainter = new SnapshotDrawerUtils.SystemBarBackgroundPainter(attrs.flags,
attrs.privateFlags, attrs.insetsFlags.appearance, taskDescription,
- mHighResSnapshotScale, mainWindow.getRequestedVisibleTypes());
- final int taskWidth = taskBounds.width();
- final int taskHeight = taskBounds.height();
- final int width = (int) (taskWidth * mHighResSnapshotScale);
- final int height = (int) (taskHeight * mHighResSnapshotScale);
+ scale, mainWindow.getRequestedVisibleTypes());
+ final int width = (int) (taskWidth * scale);
+ final int height = (int) (taskHeight * scale);
final RenderNode node = RenderNode.create("SnapshotController", null);
node.setLeftTopRightBottom(0, 0, width, height);
node.setClipToBounds(false);
diff --git a/services/core/java/com/android/server/wm/ActivityStartInterceptor.java b/services/core/java/com/android/server/wm/ActivityStartInterceptor.java
index 5cc186c40b6c..a19f4388a7c8 100644
--- a/services/core/java/com/android/server/wm/ActivityStartInterceptor.java
+++ b/services/core/java/com/android/server/wm/ActivityStartInterceptor.java
@@ -272,6 +272,12 @@ class ActivityStartInterceptor {
mActivityOptions = interceptResult.getActivityOptions();
mCallingPid = mRealCallingPid;
mCallingUid = mRealCallingUid;
+ // When an activity launch is intercepted, Intent#prepareToLeaveProcess is not called
+ // since the interception happens in the system_server. So if any activity is calling
+ // a trampoline activity, the keys do not get collected. Since all the interceptors
+ // are present in the system_server, add the creator token before launching the
+ // intercepted intent.
+ mService.mAmInternal.addCreatorToken(mIntent, mCallingPackage);
if (interceptResult.isActivityResolved()) {
return true;
}
diff --git a/services/core/java/com/android/server/wm/ActivityTaskManagerInternal.java b/services/core/java/com/android/server/wm/ActivityTaskManagerInternal.java
index c243cdc23137..21b730e13585 100644
--- a/services/core/java/com/android/server/wm/ActivityTaskManagerInternal.java
+++ b/services/core/java/com/android/server/wm/ActivityTaskManagerInternal.java
@@ -124,8 +124,9 @@ public abstract class ActivityTaskManagerInternal {
public static final String ASSIST_KEY_RECEIVER_EXTRAS = "receiverExtras";
public interface ScreenObserver {
- void onAwakeStateChanged(boolean isAwake);
- void onKeyguardStateChanged(boolean isShowing);
+ default void onAwakeStateChanged(boolean isAwake) {}
+ default void onKeyguardStateChanged(boolean isShowing) {}
+ default void onKeyguardGoingAway() {}
}
/**
diff --git a/services/core/java/com/android/server/wm/ActivityTaskManagerService.java b/services/core/java/com/android/server/wm/ActivityTaskManagerService.java
index 9c9656671519..46d24b0d3201 100644
--- a/services/core/java/com/android/server/wm/ActivityTaskManagerService.java
+++ b/services/core/java/com/android/server/wm/ActivityTaskManagerService.java
@@ -281,7 +281,6 @@ import com.android.server.sdksandbox.SdkSandboxManagerLocal;
import com.android.server.statusbar.StatusBarManagerInternal;
import com.android.server.uri.NeededUriGrants;
import com.android.server.uri.UriGrantsManagerInternal;
-import com.android.server.wallpaper.WallpaperManagerInternal;
import com.android.server.wm.utils.WindowStyleCache;
import com.android.wm.shell.Flags;
@@ -373,7 +372,6 @@ public class ActivityTaskManagerService extends IActivityTaskManager.Stub {
private ComponentName mSysUiServiceComponent;
private PermissionPolicyInternal mPermissionPolicyInternal;
private StatusBarManagerInternal mStatusBarManagerInternal;
- private WallpaperManagerInternal mWallpaperManagerInternal;
private UserManagerInternal mUserManagerInternal;
@VisibleForTesting
final ActivityTaskManagerInternal mInternal;
@@ -3719,10 +3717,12 @@ public class ActivityTaskManagerService extends IActivityTaskManager.Stub {
if (isPowerModePreApplied && !foundResumed) {
endPowerMode(POWER_MODE_REASON_START_ACTIVITY);
}
- }
- WallpaperManagerInternal wallpaperManagerInternal = getWallpaperManagerInternal();
- if (wallpaperManagerInternal != null) {
- wallpaperManagerInternal.onKeyguardGoingAway();
+
+ mH.post(() -> {
+ for (int i = mScreenObservers.size() - 1; i >= 0; i--) {
+ mScreenObservers.get(i).onKeyguardGoingAway();
+ }
+ });
}
} finally {
Binder.restoreCallingIdentity(token);
@@ -5573,13 +5573,6 @@ public class ActivityTaskManagerService extends IActivityTaskManager.Stub {
return mStatusBarManagerInternal;
}
- WallpaperManagerInternal getWallpaperManagerInternal() {
- if (mWallpaperManagerInternal == null) {
- mWallpaperManagerInternal = LocalServices.getService(WallpaperManagerInternal.class);
- }
- return mWallpaperManagerInternal;
- }
-
UserManagerInternal getUserManagerInternal() {
if (mUserManagerInternal == null) {
mUserManagerInternal = LocalServices.getService(UserManagerInternal.class);
diff --git a/services/core/java/com/android/server/wm/SnapshotPersistQueue.java b/services/core/java/com/android/server/wm/SnapshotPersistQueue.java
index eafc8be7bf77..016cebac2b86 100644
--- a/services/core/java/com/android/server/wm/SnapshotPersistQueue.java
+++ b/services/core/java/com/android/server/wm/SnapshotPersistQueue.java
@@ -24,6 +24,10 @@ import static com.android.server.wm.WindowManagerDebugConfig.TAG_WM;
import android.annotation.NonNull;
import android.graphics.Bitmap;
+import android.graphics.PixelFormat;
+import android.hardware.HardwareBuffer;
+import android.media.Image;
+import android.media.ImageReader;
import android.os.Process;
import android.os.SystemClock;
import android.os.Trace;
@@ -33,10 +37,12 @@ import android.window.TaskSnapshot;
import com.android.internal.annotations.GuardedBy;
import com.android.internal.annotations.VisibleForTesting;
+import com.android.internal.policy.TransitionAnimation;
import com.android.server.LocalServices;
import com.android.server.pm.UserManagerInternal;
import com.android.server.wm.BaseAppSnapshotPersister.PersistInfoProvider;
import com.android.server.wm.nano.WindowManagerProtos.TaskSnapshotProto;
+import com.android.window.flags.Flags;
import java.io.File;
import java.io.FileOutputStream;
@@ -400,23 +406,20 @@ class SnapshotPersistQueue {
Slog.e(TAG, "Invalid task snapshot hw buffer, taskId=" + mId);
return false;
}
- final Bitmap bitmap = Bitmap.wrapHardwareBuffer(
- mSnapshot.getHardwareBuffer(), mSnapshot.getColorSpace());
- if (bitmap == null) {
- Slog.e(TAG, "Invalid task snapshot hw bitmap");
- return false;
- }
- final Bitmap swBitmap = bitmap.copy(Bitmap.Config.ARGB_8888, false /* isMutable */);
+ final HardwareBuffer hwBuffer = mSnapshot.getHardwareBuffer();
+ final int width = hwBuffer.getWidth();
+ final int height = hwBuffer.getHeight();
+ final int pixelFormat = hwBuffer.getFormat();
+ final Bitmap swBitmap = !Flags.reduceTaskSnapshotMemoryUsage()
+ || (pixelFormat != PixelFormat.RGB_565 && pixelFormat != PixelFormat.RGBA_8888)
+ || !mSnapshot.isRealSnapshot()
+ || TransitionAnimation.hasProtectedContent(hwBuffer)
+ ? copyToSwBitmapReadBack()
+ : copyToSwBitmapDirect(width, height, pixelFormat);
if (swBitmap == null) {
- Slog.e(TAG, "Bitmap conversion from (config=" + bitmap.getConfig() + ", isMutable="
- + bitmap.isMutable() + ") to (config=ARGB_8888, isMutable=false) failed.");
return false;
}
- final int width = bitmap.getWidth();
- final int height = bitmap.getHeight();
- bitmap.recycle();
-
final File file = mPersistInfoProvider.getHighResolutionBitmapFile(mId, mUserId);
try (FileOutputStream fos = new FileOutputStream(file)) {
swBitmap.compress(JPEG, COMPRESS_QUALITY, fos);
@@ -448,6 +451,58 @@ class SnapshotPersistQueue {
return true;
}
+ private Bitmap copyToSwBitmapReadBack() {
+ final Bitmap bitmap = Bitmap.wrapHardwareBuffer(
+ mSnapshot.getHardwareBuffer(), mSnapshot.getColorSpace());
+ if (bitmap == null) {
+ Slog.e(TAG, "Invalid task snapshot hw bitmap");
+ return null;
+ }
+
+ final Bitmap swBitmap = bitmap.copy(Bitmap.Config.ARGB_8888, false /* isMutable */);
+ if (swBitmap == null) {
+ Slog.e(TAG, "Bitmap conversion from (config=" + bitmap.getConfig()
+ + ", isMutable=" + bitmap.isMutable()
+ + ") to (config=ARGB_8888, isMutable=false) failed.");
+ return null;
+ }
+ bitmap.recycle();
+ return swBitmap;
+ }
+
+ /**
+ * Use ImageReader to create the software bitmap, so SkImage won't create an extra texture.
+ */
+ private Bitmap copyToSwBitmapDirect(int width, int height, int pixelFormat) {
+ try (ImageReader ir = ImageReader.newInstance(width, height,
+ pixelFormat, 1 /* maxImages */)) {
+ ir.getSurface().attachAndQueueBufferWithColorSpace(mSnapshot.getHardwareBuffer(),
+ mSnapshot.getColorSpace());
+ try (Image image = ir.acquireLatestImage()) {
+ if (image == null || image.getPlaneCount() < 1) {
+ Slog.e(TAG, "Image reader cannot acquire image");
+ return null;
+ }
+
+ final Image.Plane[] planes = image.getPlanes();
+ if (planes.length != 1) {
+ Slog.e(TAG, "Image reader cannot get plane");
+ return null;
+ }
+ final Image.Plane plane = planes[0];
+ final int rowPadding = plane.getRowStride() - plane.getPixelStride()
+ * image.getWidth();
+ final Bitmap swBitmap = Bitmap.createBitmap(
+ image.getWidth() + rowPadding / plane.getPixelStride() /* width */,
+ image.getHeight() /* height */,
+ pixelFormat == PixelFormat.RGB_565
+ ? Bitmap.Config.RGB_565 : Bitmap.Config.ARGB_8888);
+ swBitmap.copyPixelsFromBuffer(plane.getBuffer());
+ return swBitmap;
+ }
+ }
+ }
+
@Override
public boolean equals(Object o) {
if (o == null || getClass() != o.getClass()) return false;
diff --git a/services/core/java/com/android/server/wm/Transition.java b/services/core/java/com/android/server/wm/Transition.java
index 2c10af4c5851..65001f436d3f 100644
--- a/services/core/java/com/android/server/wm/Transition.java
+++ b/services/core/java/com/android/server/wm/Transition.java
@@ -3401,7 +3401,6 @@ class Transition implements BLASTSyncEngine.TransactionReadyListener {
* Applies the new configuration for the changed displays. Returns the activities that should
* check whether to deliver the new configuration to clients.
*/
- @Nullable
void applyDisplayChangeIfNeeded(@NonNull ArraySet<WindowContainer<?>> activitiesMayChange) {
for (int i = mParticipants.size() - 1; i >= 0; --i) {
final WindowContainer<?> wc = mParticipants.valueAt(i);
diff --git a/services/tests/mockingservicestests/src/com/android/server/job/JobSchedulerServiceTest.java b/services/tests/mockingservicestests/src/com/android/server/job/JobSchedulerServiceTest.java
index 8c09f26bb7fa..fdf78ad88311 100644
--- a/services/tests/mockingservicestests/src/com/android/server/job/JobSchedulerServiceTest.java
+++ b/services/tests/mockingservicestests/src/com/android/server/job/JobSchedulerServiceTest.java
@@ -56,12 +56,12 @@ import android.app.ActivityManagerInternal;
import android.app.AppGlobals;
import android.app.IActivityManager;
import android.app.UiModeManager;
+import android.app.compat.CompatChanges;
import android.app.job.JobInfo;
import android.app.job.JobParameters;
import android.app.job.JobScheduler;
import android.app.job.JobWorkItem;
import android.app.usage.UsageStatsManagerInternal;
-import android.compat.testing.PlatformCompatChangeRule;
import android.content.ComponentName;
import android.content.ContentResolver;
import android.content.Context;
@@ -81,6 +81,7 @@ import android.os.BatteryManagerInternal.ChargingPolicyChangeListener;
import android.os.Looper;
import android.os.Process;
import android.os.RemoteException;
+import android.os.ServiceManager;
import android.os.SystemClock;
import android.os.WorkSource;
import android.os.WorkSource.WorkChain;
@@ -98,6 +99,7 @@ import com.android.server.DeviceIdleInternal;
import com.android.server.LocalServices;
import com.android.server.PowerAllowlistInternal;
import com.android.server.SystemServiceManager;
+import com.android.server.compat.PlatformCompat;
import com.android.server.job.controllers.ConnectivityController;
import com.android.server.job.controllers.JobStatus;
import com.android.server.job.controllers.QuotaController;
@@ -106,14 +108,10 @@ import com.android.server.job.restrictions.ThermalStatusRestriction;
import com.android.server.pm.UserManagerInternal;
import com.android.server.usage.AppStandbyInternal;
-import libcore.junit.util.compat.CoreCompatChangeRule.DisableCompatChanges;
-import libcore.junit.util.compat.CoreCompatChangeRule.EnableCompatChanges;
-
import org.junit.After;
import org.junit.Before;
import org.junit.Rule;
import org.junit.Test;
-import org.junit.rules.TestRule;
import org.mockito.ArgumentCaptor;
import org.mockito.ArgumentMatchers;
import org.mockito.Mock;
@@ -147,9 +145,6 @@ public class JobSchedulerServiceTest {
@Rule
public final CheckFlagsRule mCheckFlagsRule = DeviceFlagsValueProvider.createCheckFlagsRule();
- @Rule
- public TestRule compatChangeRule = new PlatformCompatChangeRule();
-
private ChargingPolicyChangeListener mChargingPolicyChangeListener;
private int mSourceUid;
@@ -166,8 +161,10 @@ public class JobSchedulerServiceTest {
mMockingSession = mockitoSession()
.initMocks(this)
.strictness(Strictness.LENIENT)
+ .mockStatic(CompatChanges.class)
.mockStatic(LocalServices.class)
.mockStatic(PermissionChecker.class)
+ .mockStatic(ServiceManager.class)
.startMocking();
// Called in JobSchedulerService constructor.
@@ -230,6 +227,9 @@ public class JobSchedulerServiceTest {
ArgumentCaptor<ChargingPolicyChangeListener> chargingPolicyChangeListenerCaptor =
ArgumentCaptor.forClass(ChargingPolicyChangeListener.class);
+ doReturn(mock(PlatformCompat.class))
+ .when(() -> ServiceManager.getService(Context.PLATFORM_COMPAT_SERVICE));
+
mService = new TestJobSchedulerService(mContext);
mService.waitOnAsyncLoadingForTesting();
@@ -1074,12 +1074,15 @@ public class JobSchedulerServiceTest {
*/
@Test
@EnableFlags(FLAG_HANDLE_ABANDONED_JOBS)
- @DisableCompatChanges({JobParameters.OVERRIDE_HANDLE_ABANDONED_JOBS})
public void testGetRescheduleJobForFailure_abandonedJob() {
final long nowElapsed = sElapsedRealtimeClock.millis();
final long initialBackoffMs = MINUTE_IN_MILLIS;
mService.mConstants.SYSTEM_STOP_TO_FAILURE_RATIO = 3;
+ // Mock the OVERRIDE_HANDLE_ABANDONED_JOBS compat change overrides.
+ when(CompatChanges.isChangeEnabled(
+ eq(JobParameters.OVERRIDE_HANDLE_ABANDONED_JOBS), anyInt())).thenReturn(false);
+
JobStatus originalJob = createJobStatus("testGetRescheduleJobForFailure",
createJobInfo()
.setBackoffCriteria(initialBackoffMs, JobInfo.BACKOFF_POLICY_LINEAR));
@@ -1148,8 +1151,10 @@ public class JobSchedulerServiceTest {
*/
@Test
@EnableFlags(FLAG_HANDLE_ABANDONED_JOBS)
- @DisableCompatChanges({JobParameters.OVERRIDE_HANDLE_ABANDONED_JOBS})
public void testGetRescheduleJobForFailure_EnableFlagDisableCompatCheckAggressiveBackoff() {
+ // Mock the OVERRIDE_HANDLE_ABANDONED_JOBS compat change overrides.
+ when(CompatChanges.isChangeEnabled(
+ eq(JobParameters.OVERRIDE_HANDLE_ABANDONED_JOBS), anyInt())).thenReturn(false);
assertFalse(mService.shouldUseAggressiveBackoff(
mService.mConstants.ABANDONED_JOB_TIMEOUTS_BEFORE_AGGRESSIVE_BACKOFF - 1,
mSourceUid));
@@ -1167,8 +1172,10 @@ public class JobSchedulerServiceTest {
*/
@Test
@EnableFlags(FLAG_HANDLE_ABANDONED_JOBS)
- @EnableCompatChanges({JobParameters.OVERRIDE_HANDLE_ABANDONED_JOBS})
public void testGetRescheduleJobForFailure_EnableFlagEnableCompatCheckAggressiveBackoff() {
+ // Mock the OVERRIDE_HANDLE_ABANDONED_JOBS compat change overrides.
+ when(CompatChanges.isChangeEnabled(
+ eq(JobParameters.OVERRIDE_HANDLE_ABANDONED_JOBS), anyInt())).thenReturn(true);
assertFalse(mService.shouldUseAggressiveBackoff(
mService.mConstants.ABANDONED_JOB_TIMEOUTS_BEFORE_AGGRESSIVE_BACKOFF - 1,
mSourceUid));
diff --git a/services/tests/mockingservicestests/src/com/android/server/job/controllers/QuotaControllerTest.java b/services/tests/mockingservicestests/src/com/android/server/job/controllers/QuotaControllerTest.java
index 2d84887afb41..924fe9586af9 100644
--- a/services/tests/mockingservicestests/src/com/android/server/job/controllers/QuotaControllerTest.java
+++ b/services/tests/mockingservicestests/src/com/android/server/job/controllers/QuotaControllerTest.java
@@ -76,6 +76,7 @@ import android.os.BatteryManagerInternal;
import android.os.Handler;
import android.os.Looper;
import android.os.RemoteException;
+import android.os.ServiceManager;
import android.os.SystemClock;
import android.platform.test.annotations.DisableFlags;
import android.platform.test.annotations.EnableFlags;
@@ -93,6 +94,7 @@ import androidx.test.runner.AndroidJUnit4;
import com.android.internal.util.ArrayUtils;
import com.android.server.LocalServices;
import com.android.server.PowerAllowlistInternal;
+import com.android.server.compat.PlatformCompat;
import com.android.server.job.Flags;
import com.android.server.job.JobSchedulerInternal;
import com.android.server.job.JobSchedulerService;
@@ -104,8 +106,6 @@ import com.android.server.job.controllers.QuotaController.TimedEvent;
import com.android.server.job.controllers.QuotaController.TimingSession;
import com.android.server.usage.AppStandbyInternal;
-import libcore.junit.util.compat.CoreCompatChangeRule.EnableCompatChanges;
-
import org.junit.After;
import org.junit.Before;
import org.junit.Rule;
@@ -168,6 +168,8 @@ public class QuotaControllerTest {
private PowerAllowlistInternal mPowerAllowlistInternal;
@Mock
private UsageStatsManagerInternal mUsageStatsManager;
+ @Mock
+ private PlatformCompat mPlatformCompat;
@Rule
public final CheckFlagsRule mCheckFlagsRule =
@@ -182,6 +184,7 @@ public class QuotaControllerTest {
.strictness(Strictness.LENIENT)
.spyStatic(DeviceConfig.class)
.mockStatic(LocalServices.class)
+ .mockStatic(ServiceManager.class)
.startMocking();
// Called in StateController constructor.
@@ -198,6 +201,7 @@ public class QuotaControllerTest {
}
when(mContext.getMainLooper()).thenReturn(Looper.getMainLooper());
when(mContext.getSystemService(AlarmManager.class)).thenReturn(mAlarmManager);
+
doReturn(mActivityMangerInternal)
.when(() -> LocalServices.getService(ActivityManagerInternal.class));
doReturn(mock(AppStandbyInternal.class))
@@ -253,6 +257,8 @@ public class QuotaControllerTest {
ArgumentCaptor.forClass(PowerAllowlistInternal.TempAllowlistChangeListener.class);
ArgumentCaptor<UsageStatsManagerInternal.UsageEventListener> ueListenerCaptor =
ArgumentCaptor.forClass(UsageStatsManagerInternal.UsageEventListener.class);
+ doReturn(mPlatformCompat)
+ .when(() -> ServiceManager.getService(Context.PLATFORM_COMPAT_SERVICE));
mQuotaController = new QuotaController(mJobSchedulerService,
mock(BackgroundJobsController.class), mock(ConnectivityController.class));
@@ -5591,13 +5597,17 @@ public class QuotaControllerTest {
}
@Test
- @EnableCompatChanges({QuotaController.OVERRIDE_QUOTA_ENFORCEMENT_TO_TOP_STARTED_JOBS,
- QuotaController.OVERRIDE_QUOTA_ENFORCEMENT_TO_FGS_JOBS})
@RequiresFlagsEnabled({Flags.FLAG_ENFORCE_QUOTA_POLICY_TO_TOP_STARTED_JOBS,
Flags.FLAG_ENFORCE_QUOTA_POLICY_TO_FGS_JOBS})
public void testTracking_OutOfQuota_ForegroundAndBackground_CompactChangeOverrides() {
setDischarging();
+ // Mock the OVERRIDE_QUOTA_ENFORCEMENT_TO_TOP_STARTED_JOBS compat change overrides.
+ doReturn(true).when(mPlatformCompat).isChangeEnabledByUid(
+ eq(QuotaController.OVERRIDE_QUOTA_ENFORCEMENT_TO_TOP_STARTED_JOBS), anyInt());
+ doReturn(true).when(mPlatformCompat).isChangeEnabledByUid(
+ eq(QuotaController.OVERRIDE_QUOTA_ENFORCEMENT_TO_FGS_JOBS), anyInt());
+
JobStatus jobBg = createJobStatus("testTracking_OutOfQuota_ForegroundAndBackground", 1);
JobStatus jobTop = createJobStatus("testTracking_OutOfQuota_ForegroundAndBackground", 2);
trackJobs(jobBg, jobTop);
diff --git a/services/tests/powerstatstests/src/com/android/server/power/stats/BatteryStatsHistoryTest.java b/services/tests/powerstatstests/src/com/android/server/power/stats/BatteryStatsHistoryTest.java
index fc864dd230d9..3ed4a52bed23 100644
--- a/services/tests/powerstatstests/src/com/android/server/power/stats/BatteryStatsHistoryTest.java
+++ b/services/tests/powerstatstests/src/com/android/server/power/stats/BatteryStatsHistoryTest.java
@@ -343,12 +343,13 @@ public class BatteryStatsHistoryTest {
assertThat(mReadFiles).containsExactly("123.bh", "1000.bh");
} else if (item.eventCode == HistoryItem.EVENT_ALARM) {
eventsRead++;
- assertThat(mReadFiles).containsExactly("123.bh", "1000.bh", "2000.bh");
+ // This event is in the current buffer, so 2000.bh shouldn't be read from disk
+ assertThat(mReadFiles).containsExactly("123.bh", "1000.bh");
}
}
assertThat(eventsRead).isEqualTo(3);
- assertThat(mReadFiles).containsExactly("123.bh", "1000.bh", "2000.bh", "3000.bh");
+ assertThat(mReadFiles).containsExactly("123.bh", "1000.bh");
}
@Test
@@ -366,34 +367,41 @@ public class BatteryStatsHistoryTest {
return invocation.callRealMethod();
}).when(mHistory).readFragmentToParcel(any(), any());
- BatteryStatsHistoryIterator iterator = mHistory.iterate(1000, 3000);
+ int eventsRead = 0;
+ BatteryStatsHistoryIterator iterator = mHistory.iterate(1001, 3000);
while (iterator.hasNext()) {
HistoryItem item = iterator.next();
if (item.eventCode == HistoryItem.EVENT_JOB_START) {
fail("Event outside the range");
} else if (item.eventCode == HistoryItem.EVENT_JOB_FINISH) {
+ eventsRead++;
assertThat(mReadFiles).containsExactly("1000.bh");
} else if (item.eventCode == HistoryItem.EVENT_ALARM) {
fail("Event outside the range");
}
}
- assertThat(mReadFiles).containsExactly("1000.bh", "2000.bh");
+ assertThat(eventsRead).isEqualTo(1);
+ assertThat(mReadFiles).containsExactly("1000.bh");
}
private void prepareMultiFileHistory() {
- mClock.realtime = 1000;
- mClock.uptime = 1000;
+ mClock.realtime = 500;
+ mClock.uptime = 500;
mHistory.recordEvent(mClock.realtime, mClock.uptime,
BatteryStats.HistoryItem.EVENT_JOB_START, "job", 42);
+ mClock.realtime = 1000;
+ mClock.uptime = 1000;
mHistory.startNextFragment(mClock.realtime); // 1000.bh
- mClock.realtime = 2000;
- mClock.uptime = 2000;
+ mClock.realtime = 1500;
+ mClock.uptime = 1500;
mHistory.recordEvent(mClock.realtime, mClock.uptime,
BatteryStats.HistoryItem.EVENT_JOB_FINISH, "job", 42);
+ mClock.realtime = 2000;
+ mClock.uptime = 2000;
mHistory.startNextFragment(mClock.realtime); // 2000.bh
mClock.realtime = 3000;
@@ -401,8 +409,8 @@ public class BatteryStatsHistoryTest {
mHistory.recordEvent(mClock.realtime, mClock.uptime,
HistoryItem.EVENT_ALARM, "alarm", 42);
- // Flush accumulated history to disk
- mHistory.startNextFragment(mClock.realtime);
+ // Back up accumulated history to disk
+ mHistory.writeHistory();
}
private void verifyActiveFile(BatteryStatsHistory history, String file) {
diff --git a/services/tests/servicestests/src/com/android/server/accessibility/HearingDevicePhoneCallNotificationControllerTest.java b/services/tests/servicestests/src/com/android/server/accessibility/HearingDevicePhoneCallNotificationControllerTest.java
index 3565244d90b3..33529c3f4375 100644
--- a/services/tests/servicestests/src/com/android/server/accessibility/HearingDevicePhoneCallNotificationControllerTest.java
+++ b/services/tests/servicestests/src/com/android/server/accessibility/HearingDevicePhoneCallNotificationControllerTest.java
@@ -25,6 +25,7 @@ import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.Mockito.doReturn;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.never;
+import static org.mockito.Mockito.times;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
@@ -207,6 +208,23 @@ public class HearingDevicePhoneCallNotificationControllerTest {
eq(SystemMessageProto.SystemMessage.NOTE_HEARING_DEVICE_INPUT_SWITCH), any());
}
+ @Test
+ @EnableFlags(Flags.FLAG_HEARING_INPUT_CHANGE_WHEN_COMM_DEVICE)
+ public void onCallStateChanged_offHookMultiple_addListenerOnlyOneTime() {
+ AudioDeviceInfo a2dpDeviceInfo = createAudioDeviceInfo(TEST_ADDRESS,
+ AudioManager.DEVICE_OUT_BLUETOOTH_A2DP);
+ when(mAudioManager.getDevices(AudioManager.GET_DEVICES_INPUTS)).thenReturn(
+ new AudioDeviceInfo[]{a2dpDeviceInfo});
+ when(mAudioManager.getCommunicationDevice()).thenReturn(a2dpDeviceInfo);
+
+ mTestCallStateListener.onCallStateChanged(TelephonyManager.CALL_STATE_OFFHOOK);
+ mTestCallStateListener.onCallStateChanged(TelephonyManager.CALL_STATE_OFFHOOK);
+
+ verify(mAudioManager, times(1)).addOnCommunicationDeviceChangedListener(
+ any(Executor.class),
+ any(AudioManager.OnCommunicationDeviceChangedListener.class));
+ }
+
private AudioDeviceInfo createAudioDeviceInfo(String address, int type) {
AudioDevicePort audioDevicePort = mock(AudioDevicePort.class);
doReturn(type).when(audioDevicePort).type();
diff --git a/services/tests/servicestests/src/com/android/server/hdmi/BaseAbsoluteVolumeBehaviorTest.java b/services/tests/servicestests/src/com/android/server/hdmi/BaseAbsoluteVolumeBehaviorTest.java
index b2d48a77386f..2349120f8e76 100644
--- a/services/tests/servicestests/src/com/android/server/hdmi/BaseAbsoluteVolumeBehaviorTest.java
+++ b/services/tests/servicestests/src/com/android/server/hdmi/BaseAbsoluteVolumeBehaviorTest.java
@@ -226,13 +226,16 @@ public abstract class BaseAbsoluteVolumeBehaviorTest {
*/
protected void adoptFullVolumeBehaviorOnAvbCapableAudioOutputDevices() {
if (getDeviceType() == HdmiDeviceInfo.DEVICE_PLAYBACK) {
- mAudioManager.setDeviceVolumeBehavior(HdmiControlService.AUDIO_OUTPUT_DEVICE_HDMI,
- AudioManager.DEVICE_VOLUME_BEHAVIOR_FULL);
+ mAudioDeviceVolumeManager.setDeviceVolumeBehavior(
+ HdmiControlService.AUDIO_OUTPUT_DEVICE_HDMI,
+ AudioDeviceVolumeManager.DEVICE_VOLUME_BEHAVIOR_FULL);
} else if (getDeviceType() == HdmiDeviceInfo.DEVICE_TV) {
- mAudioManager.setDeviceVolumeBehavior(HdmiControlService.AUDIO_OUTPUT_DEVICE_HDMI_ARC,
- AudioManager.DEVICE_VOLUME_BEHAVIOR_FULL);
- mAudioManager.setDeviceVolumeBehavior(HdmiControlService.AUDIO_OUTPUT_DEVICE_HDMI_EARC,
- AudioManager.DEVICE_VOLUME_BEHAVIOR_FULL);
+ mAudioDeviceVolumeManager.setDeviceVolumeBehavior(
+ HdmiControlService.AUDIO_OUTPUT_DEVICE_HDMI_ARC,
+ AudioDeviceVolumeManager.DEVICE_VOLUME_BEHAVIOR_FULL);
+ mAudioDeviceVolumeManager.setDeviceVolumeBehavior(
+ HdmiControlService.AUDIO_OUTPUT_DEVICE_HDMI_EARC,
+ AudioDeviceVolumeManager.DEVICE_VOLUME_BEHAVIOR_FULL);
}
}
@@ -307,8 +310,9 @@ public abstract class BaseAbsoluteVolumeBehaviorTest {
INITIAL_SYSTEM_AUDIO_DEVICE_STATUS.getVolume(),
INITIAL_SYSTEM_AUDIO_DEVICE_STATUS.getMute());
- assertThat(mAudioManager.getDeviceVolumeBehavior(getAudioOutputDevice())).isEqualTo(
- AudioManager.DEVICE_VOLUME_BEHAVIOR_ABSOLUTE);
+ assertThat(mAudioDeviceVolumeManager.getDeviceVolumeBehavior(
+ getAudioOutputDevice())).isEqualTo(
+ AudioDeviceVolumeManager.DEVICE_VOLUME_BEHAVIOR_ABSOLUTE);
}
protected void enableAdjustOnlyAbsoluteVolumeBehavior() {
@@ -320,8 +324,9 @@ public abstract class BaseAbsoluteVolumeBehaviorTest {
INITIAL_SYSTEM_AUDIO_DEVICE_STATUS.getVolume(),
INITIAL_SYSTEM_AUDIO_DEVICE_STATUS.getMute());
- assertThat(mAudioManager.getDeviceVolumeBehavior(getAudioOutputDevice())).isEqualTo(
- AudioManager.DEVICE_VOLUME_BEHAVIOR_ABSOLUTE_ADJUST_ONLY);
+ assertThat(mAudioDeviceVolumeManager.getDeviceVolumeBehavior(
+ getAudioOutputDevice())).isEqualTo(
+ AudioDeviceVolumeManager.DEVICE_VOLUME_BEHAVIOR_ABSOLUTE_ADJUST_ONLY);
}
protected void verifyGiveAudioStatusNeverSent() {
@@ -419,14 +424,16 @@ public abstract class BaseAbsoluteVolumeBehaviorTest {
receiveSetAudioVolumeLevelSupport(DeviceFeatures.FEATURE_SUPPORTED);
// AVB should not be enabled before receiving <Report Audio Status>
- assertThat(mAudioManager.getDeviceVolumeBehavior(getAudioOutputDevice())).isEqualTo(
- AudioManager.DEVICE_VOLUME_BEHAVIOR_FULL);
+ assertThat(mAudioDeviceVolumeManager.getDeviceVolumeBehavior(
+ getAudioOutputDevice())).isEqualTo(
+ AudioDeviceVolumeManager.DEVICE_VOLUME_BEHAVIOR_FULL);
receiveReportAudioStatus(60, false);
// Check that absolute volume behavior was the last one adopted
- assertThat(mAudioManager.getDeviceVolumeBehavior(getAudioOutputDevice())).isEqualTo(
- AudioManager.DEVICE_VOLUME_BEHAVIOR_ABSOLUTE);
+ assertThat(mAudioDeviceVolumeManager.getDeviceVolumeBehavior(
+ getAudioOutputDevice())).isEqualTo(
+ AudioDeviceVolumeManager.DEVICE_VOLUME_BEHAVIOR_ABSOLUTE);
// Check that the volume and mute status received were included when setting AVB
verify(mAudioDeviceVolumeManager).setDeviceAbsoluteVolumeBehavior(
@@ -447,19 +454,22 @@ public abstract class BaseAbsoluteVolumeBehaviorTest {
enableSystemAudioModeIfNeeded();
receiveSetAudioVolumeLevelSupport(DeviceFeatures.FEATURE_SUPPORTED);
- assertThat(mAudioManager.getDeviceVolumeBehavior(getAudioOutputDevice())).isEqualTo(
- AudioManager.DEVICE_VOLUME_BEHAVIOR_FULL);
+ assertThat(mAudioDeviceVolumeManager.getDeviceVolumeBehavior(
+ getAudioOutputDevice())).isEqualTo(
+ AudioDeviceVolumeManager.DEVICE_VOLUME_BEHAVIOR_FULL);
receiveReportAudioStatus(127, false);
- assertThat(mAudioManager.getDeviceVolumeBehavior(getAudioOutputDevice())).isEqualTo(
- AudioManager.DEVICE_VOLUME_BEHAVIOR_FULL);
+ assertThat(mAudioDeviceVolumeManager.getDeviceVolumeBehavior(
+ getAudioOutputDevice())).isEqualTo(
+ AudioDeviceVolumeManager.DEVICE_VOLUME_BEHAVIOR_FULL);
}
@Test
public void avbEnabled_standby_avbDisabled() {
enableAbsoluteVolumeBehavior();
mHdmiControlService.onStandby(HdmiControlService.STANDBY_SCREEN_OFF);
- assertThat(mAudioManager.getDeviceVolumeBehavior(getAudioOutputDevice())).isEqualTo(
- AudioManager.DEVICE_VOLUME_BEHAVIOR_FULL);
+ assertThat(mAudioDeviceVolumeManager.getDeviceVolumeBehavior(
+ getAudioOutputDevice())).isEqualTo(
+ AudioDeviceVolumeManager.DEVICE_VOLUME_BEHAVIOR_FULL);
}
@Test
@@ -468,8 +478,9 @@ public abstract class BaseAbsoluteVolumeBehaviorTest {
setCecVolumeControlSetting(HdmiControlManager.VOLUME_CONTROL_DISABLED);
- assertThat(mAudioManager.getDeviceVolumeBehavior(getAudioOutputDevice())).isEqualTo(
- AudioManager.DEVICE_VOLUME_BEHAVIOR_FULL);
+ assertThat(mAudioDeviceVolumeManager.getDeviceVolumeBehavior(
+ getAudioOutputDevice())).isEqualTo(
+ AudioDeviceVolumeManager.DEVICE_VOLUME_BEHAVIOR_FULL);
}
@Test
@@ -477,8 +488,9 @@ public abstract class BaseAbsoluteVolumeBehaviorTest {
enableAbsoluteVolumeBehavior();
receiveSetAudioVolumeLevelSupport(DeviceFeatures.FEATURE_NOT_SUPPORTED);
- assertThat(mAudioManager.getDeviceVolumeBehavior(getAudioOutputDevice())).isEqualTo(
- AudioManager.DEVICE_VOLUME_BEHAVIOR_FULL);
+ assertThat(mAudioDeviceVolumeManager.getDeviceVolumeBehavior(
+ getAudioOutputDevice())).isEqualTo(
+ AudioDeviceVolumeManager.DEVICE_VOLUME_BEHAVIOR_FULL);
}
@Test
@@ -489,8 +501,9 @@ public abstract class BaseAbsoluteVolumeBehaviorTest {
getSystemAudioDeviceLogicalAddress(), getLogicalAddress(),
Constants.MESSAGE_SET_AUDIO_VOLUME_LEVEL, Constants.ABORT_UNRECOGNIZED_OPCODE));
mTestLooper.dispatchAll();
- assertThat(mAudioManager.getDeviceVolumeBehavior(getAudioOutputDevice())).isEqualTo(
- AudioManager.DEVICE_VOLUME_BEHAVIOR_FULL);
+ assertThat(mAudioDeviceVolumeManager.getDeviceVolumeBehavior(
+ getAudioOutputDevice())).isEqualTo(
+ AudioDeviceVolumeManager.DEVICE_VOLUME_BEHAVIOR_FULL);
}
@Test
@@ -501,8 +514,9 @@ public abstract class BaseAbsoluteVolumeBehaviorTest {
enableAbsoluteVolumeBehavior();
receiveSetSystemAudioMode(false);
- assertThat(mAudioManager.getDeviceVolumeBehavior(getAudioOutputDevice())).isEqualTo(
- AudioManager.DEVICE_VOLUME_BEHAVIOR_FULL);
+ assertThat(mAudioDeviceVolumeManager.getDeviceVolumeBehavior(
+ getAudioOutputDevice())).isEqualTo(
+ AudioDeviceVolumeManager.DEVICE_VOLUME_BEHAVIOR_FULL);
}
@Test
diff --git a/services/tests/servicestests/src/com/android/server/hdmi/BasePlaybackDeviceAvbTest.java b/services/tests/servicestests/src/com/android/server/hdmi/BasePlaybackDeviceAvbTest.java
index 4c12e436542b..7c7e2207c59c 100644
--- a/services/tests/servicestests/src/com/android/server/hdmi/BasePlaybackDeviceAvbTest.java
+++ b/services/tests/servicestests/src/com/android/server/hdmi/BasePlaybackDeviceAvbTest.java
@@ -20,7 +20,7 @@ import android.hardware.hdmi.DeviceFeatures;
import android.hardware.hdmi.HdmiControlManager;
import android.hardware.hdmi.HdmiDeviceInfo;
import android.media.AudioDeviceAttributes;
-import android.media.AudioManager;
+import android.media.AudioDeviceVolumeManager;
import org.junit.Test;
@@ -60,8 +60,8 @@ public abstract class BasePlaybackDeviceAvbTest extends BaseAbsoluteVolumeBehavi
*/
@Test
public void savlNotSupported_allOtherConditionsMet_giveAudioStatusNotSent() {
- mAudioManager.setDeviceVolumeBehavior(getAudioOutputDevice(),
- AudioManager.DEVICE_VOLUME_BEHAVIOR_FULL);
+ mAudioDeviceVolumeManager.setDeviceVolumeBehavior(getAudioOutputDevice(),
+ AudioDeviceVolumeManager.DEVICE_VOLUME_BEHAVIOR_FULL);
setCecVolumeControlSetting(HdmiControlManager.VOLUME_CONTROL_ENABLED);
enableSystemAudioModeIfNeeded();
diff --git a/services/tests/servicestests/src/com/android/server/hdmi/BaseTvToAudioSystemAvbTest.java b/services/tests/servicestests/src/com/android/server/hdmi/BaseTvToAudioSystemAvbTest.java
index f44517a47f55..7a4359889994 100644
--- a/services/tests/servicestests/src/com/android/server/hdmi/BaseTvToAudioSystemAvbTest.java
+++ b/services/tests/servicestests/src/com/android/server/hdmi/BaseTvToAudioSystemAvbTest.java
@@ -96,13 +96,15 @@ public abstract class BaseTvToAudioSystemAvbTest extends BaseAbsoluteVolumeBehav
receiveSetAudioVolumeLevelSupport(DeviceFeatures.FEATURE_NOT_SUPPORTED);
// Adjust-only AVB should not be enabled before receiving <Report Audio Status>
- assertThat(mAudioManager.getDeviceVolumeBehavior(getAudioOutputDevice())).isEqualTo(
- AudioManager.DEVICE_VOLUME_BEHAVIOR_FULL);
+ assertThat(mAudioDeviceVolumeManager.getDeviceVolumeBehavior(
+ getAudioOutputDevice())).isEqualTo(
+ AudioDeviceVolumeManager.DEVICE_VOLUME_BEHAVIOR_FULL);
receiveReportAudioStatus(20, false);
- assertThat(mAudioManager.getDeviceVolumeBehavior(getAudioOutputDevice())).isEqualTo(
- AudioManager.DEVICE_VOLUME_BEHAVIOR_ABSOLUTE_ADJUST_ONLY);
+ assertThat(mAudioDeviceVolumeManager.getDeviceVolumeBehavior(
+ getAudioOutputDevice())).isEqualTo(
+ AudioDeviceVolumeManager.DEVICE_VOLUME_BEHAVIOR_ABSOLUTE_ADJUST_ONLY);
verify(mAudioDeviceVolumeManager).setDeviceAbsoluteVolumeAdjustOnlyBehavior(
eq(getAudioOutputDevice()),
@@ -124,8 +126,9 @@ public abstract class BaseTvToAudioSystemAvbTest extends BaseAbsoluteVolumeBehav
receiveReportAudioStatus(40, true);
- assertThat(mAudioManager.getDeviceVolumeBehavior(getAudioOutputDevice())).isEqualTo(
- AudioManager.DEVICE_VOLUME_BEHAVIOR_ABSOLUTE_ADJUST_ONLY);
+ assertThat(mAudioDeviceVolumeManager.getDeviceVolumeBehavior(
+ getAudioOutputDevice())).isEqualTo(
+ AudioDeviceVolumeManager.DEVICE_VOLUME_BEHAVIOR_ABSOLUTE_ADJUST_ONLY);
verify(mAudioDeviceVolumeManager).setDeviceAbsoluteVolumeAdjustOnlyBehavior(
eq(getAudioOutputDevice()),
@@ -149,8 +152,9 @@ public abstract class BaseTvToAudioSystemAvbTest extends BaseAbsoluteVolumeBehav
receiveReportAudioStatus(40, true);
- assertThat(mAudioManager.getDeviceVolumeBehavior(getAudioOutputDevice())).isEqualTo(
- AudioManager.DEVICE_VOLUME_BEHAVIOR_ABSOLUTE_ADJUST_ONLY);
+ assertThat(mAudioDeviceVolumeManager.getDeviceVolumeBehavior(
+ getAudioOutputDevice())).isEqualTo(
+ AudioDeviceVolumeManager.DEVICE_VOLUME_BEHAVIOR_ABSOLUTE_ADJUST_ONLY);
verify(mAudioDeviceVolumeManager).setDeviceAbsoluteVolumeAdjustOnlyBehavior(
eq(getAudioOutputDevice()),
@@ -283,13 +287,15 @@ public abstract class BaseTvToAudioSystemAvbTest extends BaseAbsoluteVolumeBehav
verifyGiveAudioStatusSent();
// The device should use adjust-only AVB while waiting for <Report Audio Status>
- assertThat(mAudioManager.getDeviceVolumeBehavior(getAudioOutputDevice())).isEqualTo(
- AudioManager.DEVICE_VOLUME_BEHAVIOR_ABSOLUTE_ADJUST_ONLY);
+ assertThat(mAudioDeviceVolumeManager.getDeviceVolumeBehavior(
+ getAudioOutputDevice())).isEqualTo(
+ AudioDeviceVolumeManager.DEVICE_VOLUME_BEHAVIOR_ABSOLUTE_ADJUST_ONLY);
// The device should switch to AVB upon receiving <Report Audio Status>
receiveReportAudioStatus(60, false);
- assertThat(mAudioManager.getDeviceVolumeBehavior(getAudioOutputDevice())).isEqualTo(
- AudioManager.DEVICE_VOLUME_BEHAVIOR_ABSOLUTE);
+ assertThat(mAudioDeviceVolumeManager.getDeviceVolumeBehavior(
+ getAudioOutputDevice())).isEqualTo(
+ AudioDeviceVolumeManager.DEVICE_VOLUME_BEHAVIOR_ABSOLUTE);
}
@@ -321,8 +327,9 @@ public abstract class BaseTvToAudioSystemAvbTest extends BaseAbsoluteVolumeBehav
mTestLooper.dispatchAll();
// The device should not switch away from adjust-only AVB
- assertThat(mAudioManager.getDeviceVolumeBehavior(getAudioOutputDevice())).isEqualTo(
- AudioManager.DEVICE_VOLUME_BEHAVIOR_ABSOLUTE_ADJUST_ONLY);
+ assertThat(mAudioDeviceVolumeManager.getDeviceVolumeBehavior(
+ getAudioOutputDevice())).isEqualTo(
+ AudioDeviceVolumeManager.DEVICE_VOLUME_BEHAVIOR_ABSOLUTE_ADJUST_ONLY);
// The device should query support for <Set Audio Volume Level> again
assertThat(mNativeWrapper.getResultMessages()).contains(
diff --git a/services/tests/servicestests/src/com/android/server/hdmi/FakeAudioFramework.java b/services/tests/servicestests/src/com/android/server/hdmi/FakeAudioFramework.java
index 90f94cb4b596..e07f4f92084e 100644
--- a/services/tests/servicestests/src/com/android/server/hdmi/FakeAudioFramework.java
+++ b/services/tests/servicestests/src/com/android/server/hdmi/FakeAudioFramework.java
@@ -23,6 +23,7 @@ import android.annotation.CallbackExecutor;
import android.annotation.NonNull;
import android.media.AudioAttributes;
import android.media.AudioDeviceAttributes;
+import android.media.AudioDeviceVolumeManager;
import android.media.AudioManager;
import android.media.AudioSystem;
import android.media.VolumeInfo;
@@ -137,18 +138,6 @@ public class FakeAudioFramework {
// Do nothing
}
-
- @Override
- @AudioManager.DeviceVolumeBehavior
- public int getDeviceVolumeBehavior(@NonNull AudioDeviceAttributes device) {
- return mDeviceVolumeBehaviors.getOrDefault(device, DEFAULT_DEVICE_VOLUME_BEHAVIOR);
- }
-
- public void setDeviceVolumeBehavior(@NonNull AudioDeviceAttributes device,
- @AudioManager.DeviceVolumeBehavior int deviceVolumeBehavior) {
- setVolumeBehaviorHelper(device, deviceVolumeBehavior);
- }
-
@Override
@NonNull
public List<AudioDeviceAttributes> getDevicesForAttributes(
@@ -186,7 +175,8 @@ public class FakeAudioFramework {
boolean handlesVolumeAdjustment,
@NonNull @CallbackExecutor Executor executor,
@NonNull OnAudioDeviceVolumeChangedListener vclistener) {
- setVolumeBehaviorHelper(device, AudioManager.DEVICE_VOLUME_BEHAVIOR_ABSOLUTE);
+ setVolumeBehaviorHelper(device,
+ AudioDeviceVolumeManager.DEVICE_VOLUME_BEHAVIOR_ABSOLUTE);
}
@Override
@@ -197,7 +187,19 @@ public class FakeAudioFramework {
@NonNull @CallbackExecutor Executor executor,
@NonNull OnAudioDeviceVolumeChangedListener vclistener) {
setVolumeBehaviorHelper(device,
- AudioManager.DEVICE_VOLUME_BEHAVIOR_ABSOLUTE_ADJUST_ONLY);
+ AudioDeviceVolumeManager.DEVICE_VOLUME_BEHAVIOR_ABSOLUTE_ADJUST_ONLY);
+ }
+
+ @Override
+ @AudioDeviceVolumeManager.DeviceVolumeBehavior
+ public int getDeviceVolumeBehavior(@NonNull AudioDeviceAttributes device) {
+ return mDeviceVolumeBehaviors.getOrDefault(device, DEFAULT_DEVICE_VOLUME_BEHAVIOR);
+ }
+
+ @Override
+ public void setDeviceVolumeBehavior(@NonNull AudioDeviceAttributes device,
+ @AudioDeviceVolumeManager.DeviceVolumeBehavior int deviceVolumeBehavior) {
+ setVolumeBehaviorHelper(device, deviceVolumeBehavior);
}
}
@@ -222,7 +224,7 @@ public class FakeAudioFramework {
* Helper method for changing an audio device's volume behavior. Notifies listeners.
*/
private void setVolumeBehaviorHelper(AudioDeviceAttributes device,
- @AudioManager.DeviceVolumeBehavior int newVolumeBehavior) {
+ @AudioDeviceVolumeManager.DeviceVolumeBehavior int newVolumeBehavior) {
int currentVolumeBehavior = mDeviceVolumeBehaviors.getOrDefault(
device, DEFAULT_DEVICE_VOLUME_BEHAVIOR);
diff --git a/services/tests/servicestests/src/com/android/server/hdmi/PlaybackDeviceToAudioSystemAvbTest.java b/services/tests/servicestests/src/com/android/server/hdmi/PlaybackDeviceToAudioSystemAvbTest.java
index 43ab804e04be..ffc1c62f79b3 100644
--- a/services/tests/servicestests/src/com/android/server/hdmi/PlaybackDeviceToAudioSystemAvbTest.java
+++ b/services/tests/servicestests/src/com/android/server/hdmi/PlaybackDeviceToAudioSystemAvbTest.java
@@ -21,7 +21,7 @@ import static com.google.common.truth.Truth.assertThat;
import android.hardware.hdmi.DeviceFeatures;
import android.hardware.hdmi.HdmiControlManager;
import android.hardware.hdmi.HdmiDeviceInfo;
-import android.media.AudioManager;
+import android.media.AudioDeviceVolumeManager;
import android.platform.test.annotations.Presubmit;
import androidx.test.filters.SmallTest;
@@ -64,8 +64,9 @@ public class PlaybackDeviceToAudioSystemAvbTest extends BasePlaybackDeviceAvbTes
// Audio System disables System Audio Mode. AVB should be disabled.
receiveSetSystemAudioMode(false);
- assertThat(mAudioManager.getDeviceVolumeBehavior(getAudioOutputDevice())).isEqualTo(
- AudioManager.DEVICE_VOLUME_BEHAVIOR_FULL);
+ assertThat(mAudioDeviceVolumeManager.getDeviceVolumeBehavior(
+ getAudioOutputDevice())).isEqualTo(
+ AudioDeviceVolumeManager.DEVICE_VOLUME_BEHAVIOR_FULL);
// TV reports support for <Set Audio Volume Level>
mNativeWrapper.onCecMessage(ReportFeaturesMessage.build(
@@ -85,7 +86,8 @@ public class PlaybackDeviceToAudioSystemAvbTest extends BasePlaybackDeviceAvbTes
false));
mTestLooper.dispatchAll();
- assertThat(mAudioManager.getDeviceVolumeBehavior(getAudioOutputDevice())).isEqualTo(
- AudioManager.DEVICE_VOLUME_BEHAVIOR_ABSOLUTE);
+ assertThat(mAudioDeviceVolumeManager.getDeviceVolumeBehavior(
+ getAudioOutputDevice())).isEqualTo(
+ AudioDeviceVolumeManager.DEVICE_VOLUME_BEHAVIOR_ABSOLUTE);
}
}
diff --git a/services/tests/servicestests/src/com/android/server/hdmi/PlaybackDeviceToTvAvbTest.java b/services/tests/servicestests/src/com/android/server/hdmi/PlaybackDeviceToTvAvbTest.java
index 9b343e34706a..092618072744 100644
--- a/services/tests/servicestests/src/com/android/server/hdmi/PlaybackDeviceToTvAvbTest.java
+++ b/services/tests/servicestests/src/com/android/server/hdmi/PlaybackDeviceToTvAvbTest.java
@@ -23,7 +23,7 @@ import static org.mockito.Mockito.clearInvocations;
import android.hardware.hdmi.DeviceFeatures;
import android.hardware.hdmi.HdmiControlManager;
import android.hardware.hdmi.HdmiDeviceInfo;
-import android.media.AudioManager;
+import android.media.AudioDeviceVolumeManager;
import android.platform.test.annotations.Presubmit;
import androidx.test.filters.SmallTest;
@@ -65,8 +65,9 @@ public class PlaybackDeviceToTvAvbTest extends BasePlaybackDeviceAvbTest {
// Audio System enables System Audio Mode. AVB should be disabled.
receiveSetSystemAudioMode(true);
- assertThat(mAudioManager.getDeviceVolumeBehavior(getAudioOutputDevice())).isEqualTo(
- AudioManager.DEVICE_VOLUME_BEHAVIOR_FULL);
+ assertThat(mAudioDeviceVolumeManager.getDeviceVolumeBehavior(
+ getAudioOutputDevice())).isEqualTo(
+ AudioDeviceVolumeManager.DEVICE_VOLUME_BEHAVIOR_FULL);
clearInvocations(mAudioManager, mAudioDeviceVolumeManager);
@@ -88,7 +89,8 @@ public class PlaybackDeviceToTvAvbTest extends BasePlaybackDeviceAvbTest {
false));
mTestLooper.dispatchAll();
- assertThat(mAudioManager.getDeviceVolumeBehavior(getAudioOutputDevice())).isEqualTo(
- AudioManager.DEVICE_VOLUME_BEHAVIOR_ABSOLUTE);
+ assertThat(mAudioDeviceVolumeManager.getDeviceVolumeBehavior(
+ getAudioOutputDevice())).isEqualTo(
+ AudioDeviceVolumeManager.DEVICE_VOLUME_BEHAVIOR_ABSOLUTE);
}
}
diff --git a/services/tests/servicestests/src/com/android/server/pm/UserManagerServiceUserInfoTest.java b/services/tests/servicestests/src/com/android/server/pm/UserManagerServiceUserInfoTest.java
index d1b2e8e6d868..1fb84113e278 100644
--- a/services/tests/servicestests/src/com/android/server/pm/UserManagerServiceUserInfoTest.java
+++ b/services/tests/servicestests/src/com/android/server/pm/UserManagerServiceUserInfoTest.java
@@ -274,7 +274,7 @@ public class UserManagerServiceUserInfoTest {
/** Test UserInfo.canHaveProfile for main user */
@Test
public void testCanHaveProfile() throws Exception {
- UserInfo userInfo = createUser(100, FLAG_MAIN, null);
+ UserInfo userInfo = createUser(100, FLAG_FULL | FLAG_MAIN, null);
assertTrue("Main users can have profile", userInfo.canHaveProfile());
}