summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--apex/jobscheduler/framework/java/com/android/server/job/JobSchedulerInternal.java6
-rw-r--r--apex/jobscheduler/service/java/com/android/server/job/JobSchedulerService.java21
-rw-r--r--apex/jobscheduler/service/java/com/android/server/job/controllers/JobStatus.java18
-rw-r--r--core/api/current.txt4
-rw-r--r--core/api/test-current.txt13
-rw-r--r--core/java/android/app/ActivityOptions.aidl5
-rw-r--r--core/java/android/app/ActivityOptions.java79
-rw-r--r--core/java/android/app/Instrumentation.java9
-rw-r--r--core/java/android/app/admin/DevicePolicyManager.java25
-rw-r--r--core/java/android/appwidget/AppWidgetHostView.java5
-rw-r--r--core/java/android/content/Context.java4
-rw-r--r--core/java/android/content/res/Element.java42
-rw-r--r--core/java/android/hardware/camera2/extension/CameraOutputConfig.aidl1
-rw-r--r--core/java/android/hardware/camera2/impl/CameraAdvancedExtensionSessionImpl.java3
-rw-r--r--core/java/android/os/TestLooperManager.java1
-rw-r--r--core/java/android/view/contentprotection/flags/content_protection_flags.aconfig7
-rw-r--r--core/java/com/android/internal/os/BatteryStatsHistory.java591
-rw-r--r--core/res/AndroidManifest.xml7
-rw-r--r--core/res/res/values/config.xml3
-rw-r--r--core/tests/coretests/src/android/os/BundleTest.java9
-rw-r--r--core/tests/coretests/src/android/os/TestLooperManagerTest.java91
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopModeVisualIndicator.java33
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopTasksController.kt9
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/CaptionWindowDecoration.java2
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/DesktopModeWindowDecorViewModel.java18
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/DesktopModeWindowDecoration.java2
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/DragResizeInputListener.java6
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/ResizeVeil.java26
-rw-r--r--media/java/android/media/MediaRecorder.java3
-rw-r--r--media/java/android/media/projection/IMediaProjection.aidl9
-rw-r--r--media/java/android/media/projection/MediaProjectionInfo.java14
-rw-r--r--media/java/android/media/projection/MediaProjectionManager.java30
-rw-r--r--media/java/android/media/tv/SignalingDataRequest.aidl3
-rw-r--r--media/java/android/media/tv/SignalingDataRequest.java170
-rw-r--r--media/java/android/media/tv/TvInputManager.java20
-rw-r--r--media/java/android/media/tv/interactive/ITvInteractiveAppClient.aidl2
-rw-r--r--media/java/android/media/tv/interactive/ITvInteractiveAppSessionCallback.aidl1
-rwxr-xr-xmedia/java/android/media/tv/interactive/TvInteractiveAppManager.java43
-rwxr-xr-xmedia/java/android/media/tv/interactive/TvInteractiveAppService.java44
-rw-r--r--media/jni/soundpool/SoundDecoder.cpp5
-rw-r--r--media/jni/soundpool/SoundDecoder.h2
-rw-r--r--media/jni/soundpool/SoundManager.cpp2
-rw-r--r--media/jni/soundpool/StreamManager.cpp3
-rw-r--r--media/jni/soundpool/StreamManager.h14
-rw-r--r--media/tests/projection/src/android/media/projection/FakeIMediaProjection.java8
-rw-r--r--media/tests/projection/src/android/media/projection/MediaProjectionTest.java5
-rw-r--r--packages/SystemUI/aconfig/systemui.aconfig7
-rw-r--r--packages/SystemUI/compose/features/src/com/android/systemui/shade/ui/composable/ShadeHeader.kt9
-rw-r--r--packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/domain/interactor/KeyguardQuickAffordanceInteractorTest.kt30
-rw-r--r--packages/SystemUI/multivalentTests/src/com/android/systemui/scene/domain/interactor/SceneInteractorTest.kt99
-rw-r--r--packages/SystemUI/multivalentTests/src/com/android/systemui/shade/ui/viewmodel/ShadeHeaderViewModelTest.kt72
-rw-r--r--packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/KeyguardQuickAffordanceInteractor.kt7
-rw-r--r--packages/SystemUI/src/com/android/systemui/keyguard/ui/binder/PreviewKeyguardBlueprintViewBinder.kt82
-rw-r--r--packages/SystemUI/src/com/android/systemui/keyguard/ui/preview/KeyguardPreviewRenderer.kt126
-rw-r--r--packages/SystemUI/src/com/android/systemui/mediaprojection/MediaProjectionCaptureTarget.kt8
-rw-r--r--packages/SystemUI/src/com/android/systemui/mediaprojection/appselector/MediaProjectionAppSelectorActivity.kt13
-rw-r--r--packages/SystemUI/src/com/android/systemui/mediaprojection/appselector/MediaProjectionAppSelectorResultHandler.kt4
-rw-r--r--packages/SystemUI/src/com/android/systemui/mediaprojection/appselector/view/MediaProjectionRecentsViewController.kt6
-rw-r--r--packages/SystemUI/src/com/android/systemui/mediaprojection/permission/MediaProjectionPermissionActivity.java8
-rw-r--r--packages/SystemUI/src/com/android/systemui/scene/domain/interactor/SceneInteractor.kt22
-rw-r--r--packages/SystemUI/src/com/android/systemui/shade/ui/viewmodel/ShadeHeaderViewModel.kt14
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/phone/CentralSurfacesImpl.java29
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/phone/ScrimController.java55
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/phone/ScrimState.java15
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/screenrecord/RecordingServiceTest.java4
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/CentralSurfacesImplTest.java38
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/ScrimControllerTest.java183
-rw-r--r--packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/data/repository/FakeKeyguardTransitionRepository.kt12
-rw-r--r--packages/SystemUI/tests/utils/src/com/android/systemui/kosmos/KosmosJavaAdapter.kt4
-rw-r--r--packages/services/CameraExtensionsProxy/src/com/android/cameraextensions/CameraExtensionsProxyService.java15
-rw-r--r--ravenwood/Android.bp17
-rw-r--r--ravenwood/junit-impl-src/android/platform/test/ravenwood/RavenwoodRuleImpl.java51
-rw-r--r--ravenwood/junit-src/android/platform/test/ravenwood/RavenwoodClassRule.java2
-rw-r--r--ravenwood/junit-src/android/platform/test/ravenwood/RavenwoodRule.java55
-rw-r--r--ravenwood/ravenwood-annotation-allowed-classes.txt3
-rw-r--r--services/core/java/com/android/server/BinderCallsStatsService.java33
-rw-r--r--services/core/java/com/android/server/SensitiveContentProtectionManagerService.java85
-rw-r--r--services/core/java/com/android/server/am/BatteryStatsService.java4
-rw-r--r--services/core/java/com/android/server/content/SyncManager.java9
-rw-r--r--services/core/java/com/android/server/display/DisplayManagerService.java8
-rw-r--r--services/core/java/com/android/server/inputmethod/ClientController.java17
-rw-r--r--services/core/java/com/android/server/inputmethod/InputMethodManagerService.java156
-rw-r--r--services/core/java/com/android/server/media/MediaSessionService.java39
-rw-r--r--services/core/java/com/android/server/media/projection/MediaProjectionManagerService.java14
-rw-r--r--services/core/java/com/android/server/pm/PackageManagerService.java6
-rw-r--r--services/core/java/com/android/server/power/stats/BatteryStatsImpl.java66
-rw-r--r--services/core/java/com/android/server/power/stats/BatteryUsageStatsProvider.java12
-rw-r--r--services/core/java/com/android/server/power/stats/PowerStatsAggregator.java3
-rw-r--r--services/core/java/com/android/server/power/stats/flags.aconfig8
-rw-r--r--services/core/java/com/android/server/stats/pull/StatsPullAtomService.java7
-rw-r--r--services/core/java/com/android/server/tv/interactive/TvInteractiveAppManagerService.java19
-rw-r--r--services/core/java/com/android/server/wm/ScreenRecordingCallbackController.java2
-rw-r--r--services/core/jni/com_android_server_am_CachedAppOptimizer.cpp4
-rw-r--r--services/credentials/java/com/android/server/credentials/CredentialManagerService.java102
-rw-r--r--services/tests/InputMethodSystemServerTests/src/com/android/server/inputmethod/ClientControllerTest.java4
-rw-r--r--services/tests/displayservicetests/src/com/android/server/display/DisplayManagerServiceTest.java3
-rw-r--r--services/tests/powerstatstests/src/com/android/server/power/stats/BatteryStatsHistoryTest.java30
-rw-r--r--services/tests/powerstatstests/src/com/android/server/power/stats/SystemServicePowerCalculatorTest.java8
-rw-r--r--services/tests/servicestests/Android.bp1
-rw-r--r--services/tests/servicestests/src/com/android/server/accessibility/AccessibilityInputFilterInputTest.kt280
-rw-r--r--services/tests/servicestests/src/com/android/server/accessibility/BlockingQueueEventVerifier.kt57
-rw-r--r--services/tests/servicestests/src/com/android/server/credentials/CredentialManagerServiceTest.java49
-rw-r--r--services/tests/servicestests/src/com/android/server/media/projection/MediaProjectionManagerServiceTest.java7
-rw-r--r--services/tests/servicestests/src/com/android/server/pm/parsing/AndroidPackageParsingValidationTest.kt55
-rw-r--r--tools/aapt2/cmd/Link.cpp9
-rw-r--r--tools/aapt2/cmd/Link_test.cpp8
-rw-r--r--tools/hoststubgen/hoststubgen/helper-framework-runtime-src/framework/com/android/hoststubgen/nativesubstitution/MessageQueue_host.java8
107 files changed, 2551 insertions, 970 deletions
diff --git a/apex/jobscheduler/framework/java/com/android/server/job/JobSchedulerInternal.java b/apex/jobscheduler/framework/java/com/android/server/job/JobSchedulerInternal.java
index 6c8af39015f5..ae98fe14fbe6 100644
--- a/apex/jobscheduler/framework/java/com/android/server/job/JobSchedulerInternal.java
+++ b/apex/jobscheduler/framework/java/com/android/server/job/JobSchedulerInternal.java
@@ -77,6 +77,12 @@ public interface JobSchedulerInternal {
@NonNull String notificationChannel, int userId, @NonNull String packageName);
/**
+ * @return {@code true} if the given package holds the
+ * {@link android.Manifest.permission.RUN_BACKUP_JOBS} permission.
+ */
+ boolean hasRunBackupJobsPermission(@NonNull String packageName, int packageUid);
+
+ /**
* Report a snapshot of sync-related jobs back to the sync manager
*/
JobStorePersistStats getPersistStats();
diff --git a/apex/jobscheduler/service/java/com/android/server/job/JobSchedulerService.java b/apex/jobscheduler/service/java/com/android/server/job/JobSchedulerService.java
index fc193d8147b5..57467e3cc83d 100644
--- a/apex/jobscheduler/service/java/com/android/server/job/JobSchedulerService.java
+++ b/apex/jobscheduler/service/java/com/android/server/job/JobSchedulerService.java
@@ -4197,6 +4197,11 @@ public class JobSchedulerService extends com.android.server.SystemService
}
@Override
+ public boolean hasRunBackupJobsPermission(@NonNull String packageName, int packageUid) {
+ return JobSchedulerService.this.hasRunBackupJobsPermission(packageName, packageUid);
+ }
+
+ @Override
public JobStorePersistStats getPersistStats() {
synchronized (mLock) {
return new JobStorePersistStats(mJobs.getPersistStats());
@@ -4359,6 +4364,22 @@ public class JobSchedulerService extends com.android.server.SystemService
}
/**
+ * Returns whether the app holds the {@link Manifest.permission.RUN_BACKUP_JOBS} permission.
+ */
+ private boolean hasRunBackupJobsPermission(@NonNull String packageName, int packageUid) {
+ if (packageName == null) {
+ Slog.wtfStack(TAG,
+ "Expected a non-null package name when calling hasRunBackupJobsPermission");
+ return false;
+ }
+
+ return PermissionChecker.checkPermissionForPreflight(getTestableContext(),
+ android.Manifest.permission.RUN_BACKUP_JOBS,
+ PermissionChecker.PID_UNKNOWN, packageUid, packageName)
+ == PermissionChecker.PERMISSION_GRANTED;
+ }
+
+ /**
* Binder stub trampoline implementation
*/
final class JobSchedulerStub extends IJobScheduler.Stub {
diff --git a/apex/jobscheduler/service/java/com/android/server/job/controllers/JobStatus.java b/apex/jobscheduler/service/java/com/android/server/job/controllers/JobStatus.java
index a4df5d829281..2ea980d40287 100644
--- a/apex/jobscheduler/service/java/com/android/server/job/controllers/JobStatus.java
+++ b/apex/jobscheduler/service/java/com/android/server/job/controllers/JobStatus.java
@@ -1222,21 +1222,25 @@ public final class JobStatus {
return ACTIVE_INDEX;
}
- final int bucketWithMediaExemption;
- if (actualBucket != RESTRICTED_INDEX && actualBucket != NEVER_INDEX
- && mHasMediaBackupExemption) {
+ final boolean isEligibleAsBackupJob = job.getTriggerContentUris() != null
+ && job.getRequiredNetwork() != null
+ && !job.hasLateConstraint()
+ && mJobSchedulerInternal.hasRunBackupJobsPermission(sourcePackageName, sourceUid);
+ final boolean isBackupExempt = mHasMediaBackupExemption || isEligibleAsBackupJob;
+ final int bucketWithBackupExemption;
+ if (actualBucket != RESTRICTED_INDEX && actualBucket != NEVER_INDEX && isBackupExempt) {
// Treat it as if it's at most WORKING_INDEX (lower index grants higher quota) since
// media backup jobs are important to the user, and the source package may not have
// been used directly in a while.
- bucketWithMediaExemption = Math.min(WORKING_INDEX, actualBucket);
+ bucketWithBackupExemption = Math.min(WORKING_INDEX, actualBucket);
} else {
- bucketWithMediaExemption = actualBucket;
+ bucketWithBackupExemption = actualBucket;
}
// If the app is considered buggy, but hasn't yet been put in the RESTRICTED bucket
// (potentially because it's used frequently by the user), limit its effective bucket
// so that it doesn't get to run as much as a normal ACTIVE app.
- if (isBuggy && bucketWithMediaExemption < WORKING_INDEX) {
+ if (isBuggy && bucketWithBackupExemption < WORKING_INDEX) {
if (!mIsDowngradedDueToBuggyApp) {
// Safety check to avoid logging multiple times for the same job.
Counter.logIncrementWithUid(
@@ -1246,7 +1250,7 @@ public final class JobStatus {
}
return WORKING_INDEX;
}
- return bucketWithMediaExemption;
+ return bucketWithBackupExemption;
}
/** Returns the real standby bucket of the job. */
diff --git a/core/api/current.txt b/core/api/current.txt
index cb8db9ea69a0..55ea2f4da526 100644
--- a/core/api/current.txt
+++ b/core/api/current.txt
@@ -147,6 +147,7 @@ package android {
field public static final String MANAGE_DEVICE_POLICY_CAMERA = "android.permission.MANAGE_DEVICE_POLICY_CAMERA";
field public static final String MANAGE_DEVICE_POLICY_CERTIFICATES = "android.permission.MANAGE_DEVICE_POLICY_CERTIFICATES";
field public static final String MANAGE_DEVICE_POLICY_COMMON_CRITERIA_MODE = "android.permission.MANAGE_DEVICE_POLICY_COMMON_CRITERIA_MODE";
+ field @FlaggedApi("android.view.contentprotection.flags.manage_device_policy_enabled") public static final String MANAGE_DEVICE_POLICY_CONTENT_PROTECTION = "android.permission.MANAGE_DEVICE_POLICY_CONTENT_PROTECTION";
field public static final String MANAGE_DEVICE_POLICY_DEBUGGING_FEATURES = "android.permission.MANAGE_DEVICE_POLICY_DEBUGGING_FEATURES";
field public static final String MANAGE_DEVICE_POLICY_DEFAULT_SMS = "android.permission.MANAGE_DEVICE_POLICY_DEFAULT_SMS";
field public static final String MANAGE_DEVICE_POLICY_DEVICE_IDENTIFIERS = "android.permission.MANAGE_DEVICE_POLICY_DEVICE_IDENTIFIERS";
@@ -8194,6 +8195,9 @@ package android.app.admin {
field public static final String ACTION_SET_NEW_PASSWORD = "android.app.action.SET_NEW_PASSWORD";
field public static final String ACTION_START_ENCRYPTION = "android.app.action.START_ENCRYPTION";
field public static final String ACTION_SYSTEM_UPDATE_POLICY_CHANGED = "android.app.action.SYSTEM_UPDATE_POLICY_CHANGED";
+ field @FlaggedApi("android.view.contentprotection.flags.manage_device_policy_enabled") public static final int CONTENT_PROTECTION_DISABLED = 1; // 0x1
+ field @FlaggedApi("android.view.contentprotection.flags.manage_device_policy_enabled") public static final int CONTENT_PROTECTION_ENABLED = 2; // 0x2
+ field @FlaggedApi("android.view.contentprotection.flags.manage_device_policy_enabled") public static final int CONTENT_PROTECTION_NOT_CONTROLLED_BY_POLICY = 0; // 0x0
field public static final String DELEGATION_APP_RESTRICTIONS = "delegation-app-restrictions";
field public static final String DELEGATION_BLOCK_UNINSTALL = "delegation-block-uninstall";
field public static final String DELEGATION_CERT_INSTALL = "delegation-cert-install";
diff --git a/core/api/test-current.txt b/core/api/test-current.txt
index 42cf08ff9a66..1fa2b5c33652 100644
--- a/core/api/test-current.txt
+++ b/core/api/test-current.txt
@@ -195,8 +195,11 @@ package android.app {
method public void setTaskOverlay(boolean, boolean);
}
- public static final class ActivityOptions.LaunchCookie {
+ public static final class ActivityOptions.LaunchCookie implements android.os.Parcelable {
ctor public ActivityOptions.LaunchCookie();
+ method public int describeContents();
+ method public void writeToParcel(@NonNull android.os.Parcel, int);
+ field @NonNull public static final android.os.Parcelable.Creator<android.app.ActivityOptions.LaunchCookie> CREATOR;
}
public static interface ActivityOptions.OnAnimationFinishedListener {
@@ -2108,6 +2111,14 @@ package android.media.metrics {
}
+package android.media.projection {
+
+ public final class MediaProjectionManager {
+ method @NonNull public android.content.Intent createScreenCaptureIntent(@Nullable android.app.ActivityOptions.LaunchCookie);
+ }
+
+}
+
package android.media.soundtrigger {
public final class SoundTriggerInstrumentation {
diff --git a/core/java/android/app/ActivityOptions.aidl b/core/java/android/app/ActivityOptions.aidl
index bd5cd88959a3..2d4a85f4f6f4 100644
--- a/core/java/android/app/ActivityOptions.aidl
+++ b/core/java/android/app/ActivityOptions.aidl
@@ -17,4 +17,7 @@
package android.app;
/** @hide */
-parcelable ActivityOptions.SceneTransitionInfo; \ No newline at end of file
+parcelable ActivityOptions.SceneTransitionInfo;
+
+/** @hide */
+parcelable ActivityOptions.LaunchCookie; \ No newline at end of file
diff --git a/core/java/android/app/ActivityOptions.java b/core/java/android/app/ActivityOptions.java
index 4a566db3afb3..111895e3053b 100644
--- a/core/java/android/app/ActivityOptions.java
+++ b/core/java/android/app/ActivityOptions.java
@@ -1958,14 +1958,87 @@ public class ActivityOptions extends ComponentOptions {
*/
@SuppressLint("UnflaggedApi")
@TestApi
- public static final class LaunchCookie {
+ public static final class LaunchCookie implements Parcelable {
/** @hide */
- public final IBinder binder = new Binder();
+ public final IBinder binder;
/** @hide */
@SuppressLint("UnflaggedApi")
@TestApi
- public LaunchCookie() {}
+ public LaunchCookie() {
+ binder = new Binder();
+ }
+
+ /** @hide */
+ public LaunchCookie(@Nullable String descriptor) {
+ binder = new Binder(descriptor);
+ }
+
+ private LaunchCookie(Parcel in) {
+ this.binder = in.readStrongBinder();
+ }
+
+ /** @hide */
+ @SuppressLint("UnflaggedApi")
+ @TestApi
+ @Override
+ public int describeContents() {
+ return 0;
+ }
+
+ /** @hide */
+ @SuppressLint("UnflaggedApi")
+ @TestApi
+ @Override
+ public void writeToParcel(@NonNull Parcel dest, int flags) {
+ dest.writeStrongBinder(binder);
+ }
+
+ /** @hide */
+ public static LaunchCookie readFromParcel(@NonNull Parcel in) {
+ return new LaunchCookie(in);
+ }
+
+ /** @hide */
+ public static void writeToParcel(@Nullable LaunchCookie launchCookie, Parcel out) {
+ if (launchCookie != null) {
+ launchCookie.writeToParcel(out, 0);
+ } else {
+ out.writeStrongBinder(null);
+ }
+ }
+
+ /** @hide */
+ @SuppressLint("UnflaggedApi")
+ @TestApi
+ @NonNull
+ public static final Parcelable.Creator<LaunchCookie> CREATOR =
+ new Parcelable.Creator<LaunchCookie>() {
+
+ @Override
+ public LaunchCookie createFromParcel(Parcel source) {
+ return new LaunchCookie(source);
+ }
+
+ @Override
+ public LaunchCookie[] newArray(int size) {
+ return new LaunchCookie[size];
+ }
+ };
+
+ @Override
+ public boolean equals(@Nullable Object obj) {
+ if (obj instanceof LaunchCookie) {
+ LaunchCookie other = (LaunchCookie) obj;
+ return binder == other.binder;
+ }
+ return false;
+ }
+
+ @Override
+ public int hashCode() {
+ return binder.hashCode();
+ }
}
/**
diff --git a/core/java/android/app/Instrumentation.java b/core/java/android/app/Instrumentation.java
index 2162e3a77f15..68512b8bd771 100644
--- a/core/java/android/app/Instrumentation.java
+++ b/core/java/android/app/Instrumentation.java
@@ -79,6 +79,7 @@ import java.util.concurrent.TimeoutException;
* implementation is described to the system through an AndroidManifest.xml's
* &lt;instrumentation&gt; tag.
*/
+@android.ravenwood.annotation.RavenwoodKeepPartialClass
public class Instrumentation {
/**
@@ -132,6 +133,7 @@ public class Instrumentation {
private UiAutomation mUiAutomation;
private final Object mAnimationCompleteLock = new Object();
+ @android.ravenwood.annotation.RavenwoodKeep
public Instrumentation() {
}
@@ -142,6 +144,7 @@ public class Instrumentation {
* reflection, but it will serve as noticeable discouragement from
* doing such a thing.
*/
+ @android.ravenwood.annotation.RavenwoodReplace
private void checkInstrumenting(String method) {
// Check if we have an instrumentation context, as init should only get called by
// the system in startup processes that are being instrumented.
@@ -151,6 +154,11 @@ public class Instrumentation {
}
}
+ private void checkInstrumenting$ravenwood(String method) {
+ // At the moment, Ravenwood doesn't attach a Context, but we're only ever
+ // running code as part of tests, so we continue quietly
+ }
+
/**
* Returns if it is being called in an instrumentation environment.
*
@@ -2504,6 +2512,7 @@ public class Instrumentation {
* Takes control of the execution of messages on the specified looper until
* {@link TestLooperManager#release} is called.
*/
+ @android.ravenwood.annotation.RavenwoodKeep
public TestLooperManager acquireLooperManager(Looper looper) {
checkInstrumenting("acquireLooperManager");
return new TestLooperManager(looper);
diff --git a/core/java/android/app/admin/DevicePolicyManager.java b/core/java/android/app/admin/DevicePolicyManager.java
index 5c42b0ed975a..86d0125fd7a2 100644
--- a/core/java/android/app/admin/DevicePolicyManager.java
+++ b/core/java/android/app/admin/DevicePolicyManager.java
@@ -53,6 +53,7 @@ import static android.app.admin.flags.Flags.onboardingBugreportV2Enabled;
import static android.content.Intent.LOCAL_FLAG_FROM_SYSTEM;
import static android.net.NetworkCapabilities.NET_ENTERPRISE_ID_1;
import static android.os.Build.VERSION_CODES.UPSIDE_DOWN_CAKE;
+import static android.view.contentprotection.flags.Flags.FLAG_MANAGE_DEVICE_POLICY_ENABLED;
import static com.android.internal.util.function.pooled.PooledLambda.obtainMessage;
@@ -61,6 +62,7 @@ import android.accounts.Account;
import android.annotation.BroadcastBehavior;
import android.annotation.CallbackExecutor;
import android.annotation.ColorInt;
+import android.annotation.FlaggedApi;
import android.annotation.IntDef;
import android.annotation.NonNull;
import android.annotation.Nullable;
@@ -4092,6 +4094,29 @@ public class DevicePolicyManager {
return MTE_NOT_CONTROLLED_BY_POLICY;
}
+ /** Indicates that content protection is not controlled by policy, allowing user to choose. */
+ @FlaggedApi(FLAG_MANAGE_DEVICE_POLICY_ENABLED)
+ public static final int CONTENT_PROTECTION_NOT_CONTROLLED_BY_POLICY = 0;
+
+ /** Indicates that content protection is controlled and disabled by a policy. */
+ @FlaggedApi(FLAG_MANAGE_DEVICE_POLICY_ENABLED)
+ public static final int CONTENT_PROTECTION_DISABLED = 1;
+
+ /** Indicates that content protection is controlled and enabled by a policy. */
+ @FlaggedApi(FLAG_MANAGE_DEVICE_POLICY_ENABLED)
+ public static final int CONTENT_PROTECTION_ENABLED = 2;
+
+ /** @hide */
+ @IntDef(
+ prefix = {"CONTENT_PROTECTION_"},
+ value = {
+ CONTENT_PROTECTION_NOT_CONTROLLED_BY_POLICY,
+ CONTENT_PROTECTION_DISABLED,
+ CONTENT_PROTECTION_ENABLED,
+ })
+ @Retention(RetentionPolicy.SOURCE)
+ public @interface ContentProtectionPolicy {}
+
/**
* This object is a single place to tack on invalidation and disable calls. All
* binder caches in this class derive from this Config, so all can be invalidated or
diff --git a/core/java/android/appwidget/AppWidgetHostView.java b/core/java/android/appwidget/AppWidgetHostView.java
index ec181dac6b36..1f19f817a0b3 100644
--- a/core/java/android/appwidget/AppWidgetHostView.java
+++ b/core/java/android/appwidget/AppWidgetHostView.java
@@ -907,7 +907,10 @@ public class AppWidgetHostView extends FrameLayout implements AppWidgetHost.AppW
private InteractionHandler getHandler(InteractionHandler handler) {
return (view, pendingIntent, response) -> {
- AppWidgetManager.getInstance(mContext).noteAppWidgetTapped(mAppWidgetId);
+ AppWidgetManager manager = AppWidgetManager.getInstance(mContext);
+ if (manager != null) {
+ manager.noteAppWidgetTapped(mAppWidgetId);
+ }
if (handler != null) {
return handler.onInteraction(view, pendingIntent, response);
} else {
diff --git a/core/java/android/content/Context.java b/core/java/android/content/Context.java
index b1173a25e95f..b8d754348211 100644
--- a/core/java/android/content/Context.java
+++ b/core/java/android/content/Context.java
@@ -3657,8 +3657,8 @@ public abstract class Context {
* On Android {@link android.os.Build.VERSION_CODES#S} and later,
* if the application is in a state where the service
* can not be started (such as not in the foreground in a state when services are allowed),
- * {@link android.app.BackgroundServiceStartNotAllowedException} is thrown
- * This excemption extends {@link IllegalStateException}, so apps can
+ * {@link android.app.BackgroundServiceStartNotAllowedException} is thrown.
+ * This exception extends {@link IllegalStateException}, so apps can
* use {@code catch (IllegalStateException)} to catch both.
*
* @see #startForegroundService(Intent)
diff --git a/core/java/android/content/res/Element.java b/core/java/android/content/res/Element.java
index 89f4985461b7..6ff96f42e433 100644
--- a/core/java/android/content/res/Element.java
+++ b/core/java/android/content/res/Element.java
@@ -93,6 +93,7 @@ public class Element {
protected static final String TAG_SUPPORTS_GL_TEXTURE = "supports-gl-texture";
protected static final String TAG_SUPPORTS_INPUT = "supports-input";
protected static final String TAG_SUPPORTS_SCREENS = "supports-screens";
+ protected static final String TAG_URI_RELATIVE_FILTER_GROUP = "uri-relative-filter-group";
protected static final String TAG_USES_CONFIGURATION = "uses-configuration";
protected static final String TAG_USES_FEATURE = "uses-feature";
protected static final String TAG_USES_GL_TEXTURE = "uses-gl-texture";
@@ -106,6 +107,11 @@ public class Element {
protected static final String TAG_ATTR_BACKUP_AGENT = "backupAgent";
protected static final String TAG_ATTR_CATEGORY = "category";
+ protected static final String TAG_ATTR_FRAGMENT = "fragment";
+ protected static final String TAG_ATTR_FRAGMENT_ADVANCED_PATTERN = "fragmentAdvancedPattern";
+ protected static final String TAG_ATTR_FRAGMENT_PATTERN = "fragmentPattern";
+ protected static final String TAG_ATTR_FRAGMENT_PREFIX = "fragmentPrefix";
+ protected static final String TAG_ATTR_FRAGMENT_SUFFIX = "fragmentSuffix";
protected static final String TAG_ATTR_HOST = "host";
protected static final String TAG_ATTR_MANAGE_SPACE_ACTIVITY = "manageSpaceActivity";
protected static final String TAG_ATTR_MIMETYPE = "mimeType";
@@ -122,6 +128,11 @@ public class Element {
protected static final String TAG_ATTR_PERMISSION_GROUP = "permissionGroup";
protected static final String TAG_ATTR_PORT = "port";
protected static final String TAG_ATTR_PROCESS = "process";
+ protected static final String TAG_ATTR_QUERY = "query";
+ protected static final String TAG_ATTR_QUERY_ADVANCED_PATTERN = "queryAdvancedPattern";
+ protected static final String TAG_ATTR_QUERY_PATTERN = "queryPattern";
+ protected static final String TAG_ATTR_QUERY_PREFIX = "queryPrefix";
+ protected static final String TAG_ATTR_QUERY_SUFFIX = "querySuffix";
protected static final String TAG_ATTR_READ_PERMISSION = "readPermission";
protected static final String TAG_ATTR_REQUIRED_ACCOUNT_TYPE = "requiredAccountType";
protected static final String TAG_ATTR_REQUIRED_SYSTEM_PROPERTY_NAME =
@@ -143,7 +154,7 @@ public class Element {
// The length of mTagCounters corresponds to the number of tags defined in getCounterIdx. If new
// tags are added then the size here should be increased to match.
- private final TagCounter[] mTagCounters = new TagCounter[34];
+ private final TagCounter[] mTagCounters = new TagCounter[35];
String mTag;
@@ -238,9 +249,11 @@ public class Element {
return 31;
case TAG_INTENT:
return 32;
+ case TAG_URI_RELATIVE_FILTER_GROUP:
+ return 33;
default:
// The size of the mTagCounters array should be equal to this value+1
- return 33;
+ return 34;
}
}
@@ -276,6 +289,7 @@ public class Element {
case TAG_SERVICE:
case TAG_SUPPORTS_GL_TEXTURE:
case TAG_SUPPORTS_SCREENS:
+ case TAG_URI_RELATIVE_FILTER_GROUP:
case TAG_USES_CONFIGURATION:
case TAG_USES_FEATURE:
case TAG_USES_LIBRARY:
@@ -322,6 +336,7 @@ public class Element {
break;
case TAG_INTENT:
case TAG_INTENT_FILTER:
+ initializeCounter(TAG_URI_RELATIVE_FILTER_GROUP, 100);
initializeCounter(TAG_ACTION, 20000);
initializeCounter(TAG_CATEGORY, 40000);
initializeCounter(TAG_DATA, 40000);
@@ -354,6 +369,9 @@ public class Element {
initializeCounter(TAG_INTENT, 2000);
initializeCounter(TAG_PROVIDER, 8000);
break;
+ case TAG_URI_RELATIVE_FILTER_GROUP:
+ initializeCounter(TAG_DATA, 100);
+ break;
}
}
@@ -391,11 +409,21 @@ public class Element {
case TAG_ATTR_VERSION_NAME:
case TAG_ATTR_ZYGOTE_PRELOAD_NAME:
return MAX_ATTR_LEN_NAME;
+ case TAG_ATTR_FRAGMENT:
+ case TAG_ATTR_FRAGMENT_ADVANCED_PATTERN:
+ case TAG_ATTR_FRAGMENT_PATTERN:
+ case TAG_ATTR_FRAGMENT_PREFIX:
+ case TAG_ATTR_FRAGMENT_SUFFIX:
case TAG_ATTR_PATH:
case TAG_ATTR_PATH_ADVANCED_PATTERN:
case TAG_ATTR_PATH_PATTERN:
case TAG_ATTR_PATH_PREFIX:
case TAG_ATTR_PATH_SUFFIX:
+ case TAG_ATTR_QUERY:
+ case TAG_ATTR_QUERY_ADVANCED_PATTERN:
+ case TAG_ATTR_QUERY_PATTERN:
+ case TAG_ATTR_QUERY_PREFIX:
+ case TAG_ATTR_QUERY_SUFFIX:
return MAX_ATTR_LEN_PATH;
case TAG_ATTR_VALUE:
return MAX_ATTR_LEN_VALUE;
@@ -535,6 +563,16 @@ public class Element {
case R.styleable.AndroidManifestData_pathPrefix:
case R.styleable.AndroidManifestData_pathSuffix:
case R.styleable.AndroidManifestData_pathAdvancedPattern:
+ case R.styleable.AndroidManifestData_query:
+ case R.styleable.AndroidManifestData_queryPattern:
+ case R.styleable.AndroidManifestData_queryPrefix:
+ case R.styleable.AndroidManifestData_querySuffix:
+ case R.styleable.AndroidManifestData_queryAdvancedPattern:
+ case R.styleable.AndroidManifestData_fragment:
+ case R.styleable.AndroidManifestData_fragmentPattern:
+ case R.styleable.AndroidManifestData_fragmentPrefix:
+ case R.styleable.AndroidManifestData_fragmentSuffix:
+ case R.styleable.AndroidManifestData_fragmentAdvancedPattern:
return MAX_ATTR_LEN_PATH;
default:
return DEFAULT_MAX_STRING_ATTR_LENGTH;
diff --git a/core/java/android/hardware/camera2/extension/CameraOutputConfig.aidl b/core/java/android/hardware/camera2/extension/CameraOutputConfig.aidl
index 7c54a9b01dde..509bcb8e3d23 100644
--- a/core/java/android/hardware/camera2/extension/CameraOutputConfig.aidl
+++ b/core/java/android/hardware/camera2/extension/CameraOutputConfig.aidl
@@ -26,6 +26,7 @@ parcelable CameraOutputConfig
Surface surface;
int imageFormat;
int capacity;
+ long usage;
const int TYPE_SURFACE = 0;
const int TYPE_IMAGEREADER = 1;
diff --git a/core/java/android/hardware/camera2/impl/CameraAdvancedExtensionSessionImpl.java b/core/java/android/hardware/camera2/impl/CameraAdvancedExtensionSessionImpl.java
index 98bc31161591..f6c8f36a1b01 100644
--- a/core/java/android/hardware/camera2/impl/CameraAdvancedExtensionSessionImpl.java
+++ b/core/java/android/hardware/camera2/impl/CameraAdvancedExtensionSessionImpl.java
@@ -1182,7 +1182,8 @@ public final class CameraAdvancedExtensionSessionImpl extends CameraExtensionSes
return null;
}
ImageReader reader = ImageReader.newInstance(output.size.width,
- output.size.height, output.imageFormat, output.capacity);
+ output.size.height, output.imageFormat, output.capacity,
+ output.usage);
mReaderMap.put(output.outputId.id, reader);
return reader.getSurface();
case CameraOutputConfig.TYPE_MULTIRES_IMAGEREADER:
diff --git a/core/java/android/os/TestLooperManager.java b/core/java/android/os/TestLooperManager.java
index 5e7549fa67d8..4b16c1dce463 100644
--- a/core/java/android/os/TestLooperManager.java
+++ b/core/java/android/os/TestLooperManager.java
@@ -28,6 +28,7 @@ import java.util.concurrent.LinkedBlockingQueue;
* The test code may use {@link #next()} to acquire messages that have been queued to this
* {@link Looper}/{@link MessageQueue} and then {@link #execute} to run any that desires.
*/
+@android.ravenwood.annotation.RavenwoodKeepWholeClass
public class TestLooperManager {
private static final ArraySet<Looper> sHeldLoopers = new ArraySet<>();
diff --git a/core/java/android/view/contentprotection/flags/content_protection_flags.aconfig b/core/java/android/view/contentprotection/flags/content_protection_flags.aconfig
index 2a3008a53635..5d3153c00e8a 100644
--- a/core/java/android/view/contentprotection/flags/content_protection_flags.aconfig
+++ b/core/java/android/view/contentprotection/flags/content_protection_flags.aconfig
@@ -34,3 +34,10 @@ flag {
description: "If true, an appop is logged when a notification is rapidly cleared by a notification listener."
bug: "289080543"
}
+
+flag {
+ name: "manage_device_policy_enabled"
+ namespace: "content_protection"
+ description: "If true, the APIs to manage content protection device policy will be enabled."
+ bug: "319477846"
+}
diff --git a/core/java/com/android/internal/os/BatteryStatsHistory.java b/core/java/com/android/internal/os/BatteryStatsHistory.java
index 7a79e0f7cfea..aa60cc9e672c 100644
--- a/core/java/com/android/internal/os/BatteryStatsHistory.java
+++ b/core/java/com/android/internal/os/BatteryStatsHistory.java
@@ -490,7 +490,7 @@ public class BatteryStatsHistory {
* Returns true if this instance only supports reading history.
*/
public boolean isReadOnly() {
- return mActiveFile == null || mHistoryDir == null;
+ return !mMutable || mActiveFile == null || mHistoryDir == null;
}
/**
@@ -508,6 +508,13 @@ public class BatteryStatsHistory {
* create next history file.
*/
public void startNextFile(long elapsedRealtimeMs) {
+ synchronized (this) {
+ startNextFileLocked(elapsedRealtimeMs);
+ }
+ }
+
+ @GuardedBy("this")
+ private void startNextFileLocked(long elapsedRealtimeMs) {
if (mMaxHistoryFiles == 0) {
Slog.wtf(TAG, "mMaxHistoryFiles should not be zero when writing history");
return;
@@ -548,10 +555,7 @@ public class BatteryStatsHistory {
}
mWrittenPowerStatsDescriptors.clear();
-
- synchronized (this) {
- cleanupLocked();
- }
+ cleanupLocked();
}
@GuardedBy("this")
@@ -599,27 +603,31 @@ public class BatteryStatsHistory {
* number 0 again.
*/
public void reset() {
- if (DEBUG) Slog.i(TAG, "********** CLEARING HISTORY!");
- for (BatteryHistoryFile file : mHistoryFiles) {
- file.atomicFile.delete();
- }
- mHistoryFiles.clear();
+ synchronized (this) {
+ if (DEBUG) Slog.i(TAG, "********** CLEARING HISTORY!");
+ for (BatteryHistoryFile file : mHistoryFiles) {
+ file.atomicFile.delete();
+ }
+ mHistoryFiles.clear();
- BatteryHistoryFile name = makeBatteryHistoryFile();
- mHistoryFiles.add(name);
- setActiveFile(name);
+ BatteryHistoryFile name = makeBatteryHistoryFile();
+ mHistoryFiles.add(name);
+ setActiveFile(name);
- initHistoryBuffer();
+ initHistoryBuffer();
+ }
}
/**
* Returns the monotonic clock time when the available battery history collection started.
*/
public long getStartTime() {
- if (!mHistoryFiles.isEmpty()) {
- return mHistoryFiles.get(0).monotonicTimeMs;
- } else {
- return mHistoryBufferStartTime;
+ synchronized (this) {
+ if (!mHistoryFiles.isEmpty()) {
+ return mHistoryFiles.get(0).monotonicTimeMs;
+ } else {
+ return mHistoryBufferStartTime;
+ }
}
}
@@ -633,11 +641,14 @@ public class BatteryStatsHistory {
*/
@NonNull
public BatteryStatsHistoryIterator iterate(long startTimeMs, long endTimeMs) {
+ if (mMutable) {
+ return copy().iterate(startTimeMs, endTimeMs);
+ }
+
mCurrentFileIndex = 0;
mCurrentParcel = null;
mCurrentParcelEnd = 0;
mParcelIndex = 0;
- mMutable = false;
if (mWritableHistory != null) {
synchronized (mWritableHistory) {
mWritableHistory.setCleanupEnabledLocked(false);
@@ -650,14 +661,11 @@ public class BatteryStatsHistory {
* Finish iterating history files and history buffer.
*/
void iteratorFinished() {
- // setDataPosition so mHistoryBuffer Parcel can be written.
mHistoryBuffer.setDataPosition(mHistoryBuffer.dataSize());
if (mWritableHistory != null) {
synchronized (mWritableHistory) {
mWritableHistory.setCleanupEnabledLocked(true);
}
- } else {
- mMutable = true;
}
}
@@ -671,6 +679,8 @@ public class BatteryStatsHistory {
*/
@Nullable
public Parcel getNextParcel(long startTimeMs, long endTimeMs) {
+ checkImmutable();
+
// First iterate through all records in current parcel.
if (mCurrentParcel != null) {
if (mCurrentParcel.dataPosition() < mCurrentParcelEnd) {
@@ -754,6 +764,12 @@ public class BatteryStatsHistory {
return mCurrentParcel;
}
+ private void checkImmutable() {
+ if (mMutable) {
+ throw new IllegalStateException("Iterating over a mutable battery history");
+ }
+ }
+
/**
* Read history file into a parcel.
*
@@ -863,8 +879,10 @@ public class BatteryStatsHistory {
* @param out the output parcel
*/
public void writeToParcel(Parcel out) {
- writeHistoryBuffer(out);
- writeToParcel(out, false /* useBlobs */);
+ synchronized (this) {
+ writeHistoryBuffer(out);
+ writeToParcel(out, false /* useBlobs */);
+ }
}
/**
@@ -874,8 +892,10 @@ public class BatteryStatsHistory {
* @param out the output parcel
*/
public void writeToBatteryUsageStatsParcel(Parcel out) {
- out.writeBlob(mHistoryBuffer.marshall());
- writeToParcel(out, true /* useBlobs */);
+ synchronized (this) {
+ out.writeBlob(mHistoryBuffer.marshall());
+ writeToParcel(out, true /* useBlobs */);
+ }
}
private void writeToParcel(Parcel out, boolean useBlobs) {
@@ -1022,14 +1042,18 @@ public class BatteryStatsHistory {
* Enables/disables recording of history. When disabled, all "record*" calls are a no-op.
*/
public void setHistoryRecordingEnabled(boolean enabled) {
- mRecordingHistory = enabled;
+ synchronized (this) {
+ mRecordingHistory = enabled;
+ }
}
/**
* Returns true if history recording is enabled.
*/
public boolean isRecordingHistory() {
- return mRecordingHistory;
+ synchronized (this) {
+ return mRecordingHistory;
+ }
}
/**
@@ -1037,8 +1061,10 @@ public class BatteryStatsHistory {
*/
@VisibleForTesting
public void forceRecordAllHistory() {
- mHaveBatteryLevel = true;
- mRecordingHistory = true;
+ synchronized (this) {
+ mHaveBatteryLevel = true;
+ mRecordingHistory = true;
+ }
}
/**
@@ -1046,37 +1072,43 @@ public class BatteryStatsHistory {
*/
public void startRecordingHistory(final long elapsedRealtimeMs, final long uptimeMs,
boolean reset) {
- mRecordingHistory = true;
- mHistoryCur.currentTime = mClock.currentTimeMillis();
- writeHistoryItem(elapsedRealtimeMs, uptimeMs, mHistoryCur,
- reset ? HistoryItem.CMD_RESET : HistoryItem.CMD_CURRENT_TIME);
- mHistoryCur.currentTime = 0;
+ synchronized (this) {
+ mRecordingHistory = true;
+ mHistoryCur.currentTime = mClock.currentTimeMillis();
+ writeHistoryItem(elapsedRealtimeMs, uptimeMs, mHistoryCur,
+ reset ? HistoryItem.CMD_RESET : HistoryItem.CMD_CURRENT_TIME);
+ mHistoryCur.currentTime = 0;
+ }
}
/**
* Prepares to continue recording after restoring previous history from persistent storage.
*/
public void continueRecordingHistory() {
- if (mHistoryBuffer.dataPosition() <= 0 && mHistoryFiles.size() <= 1) {
- return;
- }
+ synchronized (this) {
+ if (mHistoryBuffer.dataPosition() <= 0 && mHistoryFiles.size() <= 1) {
+ return;
+ }
- mRecordingHistory = true;
- final long elapsedRealtimeMs = mClock.elapsedRealtime();
- final long uptimeMs = mClock.uptimeMillis();
- writeHistoryItem(elapsedRealtimeMs, uptimeMs, mHistoryCur, HistoryItem.CMD_START);
- startRecordingHistory(elapsedRealtimeMs, uptimeMs, false);
+ mRecordingHistory = true;
+ final long elapsedRealtimeMs = mClock.elapsedRealtime();
+ final long uptimeMs = mClock.uptimeMillis();
+ writeHistoryItem(elapsedRealtimeMs, uptimeMs, mHistoryCur, HistoryItem.CMD_START);
+ startRecordingHistory(elapsedRealtimeMs, uptimeMs, false);
+ }
}
/**
* Notes the current battery state to be reflected in the next written history item.
*/
public void setBatteryState(boolean charging, int status, int level, int chargeUah) {
- mHaveBatteryLevel = true;
- setChargingState(charging);
- mHistoryCur.batteryStatus = (byte) status;
- mHistoryCur.batteryLevel = (byte) level;
- mHistoryCur.batteryChargeUah = chargeUah;
+ synchronized (this) {
+ mHaveBatteryLevel = true;
+ setChargingState(charging);
+ mHistoryCur.batteryStatus = (byte) status;
+ mHistoryCur.batteryLevel = (byte) level;
+ mHistoryCur.batteryChargeUah = chargeUah;
+ }
}
/**
@@ -1084,24 +1116,28 @@ public class BatteryStatsHistory {
*/
public void setBatteryState(int status, int level, int health, int plugType, int temperature,
int voltageMv, int chargeUah) {
- mHaveBatteryLevel = true;
- mHistoryCur.batteryStatus = (byte) status;
- mHistoryCur.batteryLevel = (byte) level;
- mHistoryCur.batteryHealth = (byte) health;
- mHistoryCur.batteryPlugType = (byte) plugType;
- mHistoryCur.batteryTemperature = (short) temperature;
- mHistoryCur.batteryVoltage = (char) voltageMv;
- mHistoryCur.batteryChargeUah = chargeUah;
+ synchronized (this) {
+ mHaveBatteryLevel = true;
+ mHistoryCur.batteryStatus = (byte) status;
+ mHistoryCur.batteryLevel = (byte) level;
+ mHistoryCur.batteryHealth = (byte) health;
+ mHistoryCur.batteryPlugType = (byte) plugType;
+ mHistoryCur.batteryTemperature = (short) temperature;
+ mHistoryCur.batteryVoltage = (char) voltageMv;
+ mHistoryCur.batteryChargeUah = chargeUah;
+ }
}
/**
* Notes the current power plugged-in state to be reflected in the next written history item.
*/
public void setPluggedInState(boolean pluggedIn) {
- if (pluggedIn) {
- mHistoryCur.states |= HistoryItem.STATE_BATTERY_PLUGGED_FLAG;
- } else {
- mHistoryCur.states &= ~HistoryItem.STATE_BATTERY_PLUGGED_FLAG;
+ synchronized (this) {
+ if (pluggedIn) {
+ mHistoryCur.states |= HistoryItem.STATE_BATTERY_PLUGGED_FLAG;
+ } else {
+ mHistoryCur.states &= ~HistoryItem.STATE_BATTERY_PLUGGED_FLAG;
+ }
}
}
@@ -1109,10 +1145,12 @@ public class BatteryStatsHistory {
* Notes the current battery charging state to be reflected in the next written history item.
*/
public void setChargingState(boolean charging) {
- if (charging) {
- mHistoryCur.states2 |= HistoryItem.STATE2_CHARGING_FLAG;
- } else {
- mHistoryCur.states2 &= ~HistoryItem.STATE2_CHARGING_FLAG;
+ synchronized (this) {
+ if (charging) {
+ mHistoryCur.states2 |= HistoryItem.STATE2_CHARGING_FLAG;
+ } else {
+ mHistoryCur.states2 &= ~HistoryItem.STATE2_CHARGING_FLAG;
+ }
}
}
@@ -1121,38 +1159,44 @@ public class BatteryStatsHistory {
*/
public void recordEvent(long elapsedRealtimeMs, long uptimeMs, int code, String name,
int uid) {
- mHistoryCur.eventCode = code;
- mHistoryCur.eventTag = mHistoryCur.localEventTag;
- mHistoryCur.eventTag.string = name;
- mHistoryCur.eventTag.uid = uid;
- writeHistoryItem(elapsedRealtimeMs, uptimeMs);
+ synchronized (this) {
+ mHistoryCur.eventCode = code;
+ mHistoryCur.eventTag = mHistoryCur.localEventTag;
+ mHistoryCur.eventTag.string = name;
+ mHistoryCur.eventTag.uid = uid;
+ writeHistoryItem(elapsedRealtimeMs, uptimeMs);
+ }
}
/**
* Records a time change event.
*/
public void recordCurrentTimeChange(long elapsedRealtimeMs, long uptimeMs, long currentTimeMs) {
- if (!mRecordingHistory) {
- return;
- }
+ synchronized (this) {
+ if (!mRecordingHistory) {
+ return;
+ }
- mHistoryCur.currentTime = currentTimeMs;
- writeHistoryItem(elapsedRealtimeMs, uptimeMs, mHistoryCur,
- HistoryItem.CMD_CURRENT_TIME);
- mHistoryCur.currentTime = 0;
+ mHistoryCur.currentTime = currentTimeMs;
+ writeHistoryItem(elapsedRealtimeMs, uptimeMs, mHistoryCur,
+ HistoryItem.CMD_CURRENT_TIME);
+ mHistoryCur.currentTime = 0;
+ }
}
/**
* Records a system shutdown event.
*/
public void recordShutdownEvent(long elapsedRealtimeMs, long uptimeMs, long currentTimeMs) {
- if (!mRecordingHistory) {
- return;
- }
+ synchronized (this) {
+ if (!mRecordingHistory) {
+ return;
+ }
- mHistoryCur.currentTime = currentTimeMs;
- writeHistoryItem(elapsedRealtimeMs, uptimeMs, mHistoryCur, HistoryItem.CMD_SHUTDOWN);
- mHistoryCur.currentTime = 0;
+ mHistoryCur.currentTime = currentTimeMs;
+ writeHistoryItem(elapsedRealtimeMs, uptimeMs, mHistoryCur, HistoryItem.CMD_SHUTDOWN);
+ mHistoryCur.currentTime = 0;
+ }
}
/**
@@ -1160,13 +1204,15 @@ public class BatteryStatsHistory {
*/
public void recordBatteryState(long elapsedRealtimeMs, long uptimeMs, int batteryLevel,
boolean isPlugged) {
- mHistoryCur.batteryLevel = (byte) batteryLevel;
- setPluggedInState(isPlugged);
- if (DEBUG) {
- Slog.v(TAG, "Battery unplugged to: "
- + Integer.toHexString(mHistoryCur.states));
+ synchronized (this) {
+ mHistoryCur.batteryLevel = (byte) batteryLevel;
+ setPluggedInState(isPlugged);
+ if (DEBUG) {
+ Slog.v(TAG, "Battery unplugged to: "
+ + Integer.toHexString(mHistoryCur.states));
+ }
+ writeHistoryItem(elapsedRealtimeMs, uptimeMs);
}
- writeHistoryItem(elapsedRealtimeMs, uptimeMs);
}
/**
@@ -1174,9 +1220,11 @@ public class BatteryStatsHistory {
*/
public void recordPowerStats(long elapsedRealtimeMs, long uptimeMs,
PowerStats powerStats) {
- mHistoryCur.powerStats = powerStats;
- mHistoryCur.states2 |= HistoryItem.STATE2_EXTENSIONS_FLAG;
- writeHistoryItem(elapsedRealtimeMs, uptimeMs);
+ synchronized (this) {
+ mHistoryCur.powerStats = powerStats;
+ mHistoryCur.states2 |= HistoryItem.STATE2_EXTENSIONS_FLAG;
+ writeHistoryItem(elapsedRealtimeMs, uptimeMs);
+ }
}
/**
@@ -1184,11 +1232,13 @@ public class BatteryStatsHistory {
*/
public void recordProcessStateChange(long elapsedRealtimeMs, long uptimeMs,
int uid, @BatteryConsumer.ProcessState int processState) {
- mHistoryCur.processStateChange = mHistoryCur.localProcessStateChange;
- mHistoryCur.processStateChange.uid = uid;
- mHistoryCur.processStateChange.processState = processState;
- mHistoryCur.states2 |= HistoryItem.STATE2_EXTENSIONS_FLAG;
- writeHistoryItem(elapsedRealtimeMs, uptimeMs);
+ synchronized (this) {
+ mHistoryCur.processStateChange = mHistoryCur.localProcessStateChange;
+ mHistoryCur.processStateChange.uid = uid;
+ mHistoryCur.processStateChange.processState = processState;
+ mHistoryCur.states2 |= HistoryItem.STATE2_EXTENSIONS_FLAG;
+ writeHistoryItem(elapsedRealtimeMs, uptimeMs);
+ }
}
/**
@@ -1197,8 +1247,10 @@ public class BatteryStatsHistory {
*/
public void recordWifiConsumedCharge(long elapsedRealtimeMs, long uptimeMs,
double monitoredRailChargeMah) {
- mHistoryCur.wifiRailChargeMah += monitoredRailChargeMah;
- writeHistoryItem(elapsedRealtimeMs, uptimeMs);
+ synchronized (this) {
+ mHistoryCur.wifiRailChargeMah += monitoredRailChargeMah;
+ writeHistoryItem(elapsedRealtimeMs, uptimeMs);
+ }
}
/**
@@ -1206,10 +1258,12 @@ public class BatteryStatsHistory {
*/
public void recordWakelockStartEvent(long elapsedRealtimeMs, long uptimeMs, String historyName,
int uid) {
- mHistoryCur.wakelockTag = mHistoryCur.localWakelockTag;
- mHistoryCur.wakelockTag.string = historyName;
- mHistoryCur.wakelockTag.uid = uid;
- recordStateStartEvent(elapsedRealtimeMs, uptimeMs, HistoryItem.STATE_WAKE_LOCK_FLAG);
+ synchronized (this) {
+ mHistoryCur.wakelockTag = mHistoryCur.localWakelockTag;
+ mHistoryCur.wakelockTag.string = historyName;
+ mHistoryCur.wakelockTag.uid = uid;
+ recordStateStartEvent(elapsedRealtimeMs, uptimeMs, HistoryItem.STATE_WAKE_LOCK_FLAG);
+ }
}
/**
@@ -1217,18 +1271,20 @@ public class BatteryStatsHistory {
*/
public boolean maybeUpdateWakelockTag(long elapsedRealtimeMs, long uptimeMs, String historyName,
int uid) {
- if (mHistoryLastWritten.cmd != HistoryItem.CMD_UPDATE) {
- return false;
- }
- if (mHistoryLastWritten.wakelockTag != null) {
- // We'll try to update the last tag.
- mHistoryLastWritten.wakelockTag = null;
- mHistoryCur.wakelockTag = mHistoryCur.localWakelockTag;
- mHistoryCur.wakelockTag.string = historyName;
- mHistoryCur.wakelockTag.uid = uid;
- writeHistoryItem(elapsedRealtimeMs, uptimeMs);
+ synchronized (this) {
+ if (mHistoryLastWritten.cmd != HistoryItem.CMD_UPDATE) {
+ return false;
+ }
+ if (mHistoryLastWritten.wakelockTag != null) {
+ // We'll try to update the last tag.
+ mHistoryLastWritten.wakelockTag = null;
+ mHistoryCur.wakelockTag = mHistoryCur.localWakelockTag;
+ mHistoryCur.wakelockTag.string = historyName;
+ mHistoryCur.wakelockTag.uid = uid;
+ writeHistoryItem(elapsedRealtimeMs, uptimeMs);
+ }
+ return true;
}
- return true;
}
/**
@@ -1236,26 +1292,32 @@ public class BatteryStatsHistory {
*/
public void recordWakelockStopEvent(long elapsedRealtimeMs, long uptimeMs, String historyName,
int uid) {
- mHistoryCur.wakelockTag = mHistoryCur.localWakelockTag;
- mHistoryCur.wakelockTag.string = historyName != null ? historyName : "";
- mHistoryCur.wakelockTag.uid = uid;
- recordStateStopEvent(elapsedRealtimeMs, uptimeMs, HistoryItem.STATE_WAKE_LOCK_FLAG);
+ synchronized (this) {
+ mHistoryCur.wakelockTag = mHistoryCur.localWakelockTag;
+ mHistoryCur.wakelockTag.string = historyName != null ? historyName : "";
+ mHistoryCur.wakelockTag.uid = uid;
+ recordStateStopEvent(elapsedRealtimeMs, uptimeMs, HistoryItem.STATE_WAKE_LOCK_FLAG);
+ }
}
/**
* Records an event when some state flag changes to true.
*/
public void recordStateStartEvent(long elapsedRealtimeMs, long uptimeMs, int stateFlags) {
- mHistoryCur.states |= stateFlags;
- writeHistoryItem(elapsedRealtimeMs, uptimeMs);
+ synchronized (this) {
+ mHistoryCur.states |= stateFlags;
+ writeHistoryItem(elapsedRealtimeMs, uptimeMs);
+ }
}
/**
* Records an event when some state flag changes to false.
*/
public void recordStateStopEvent(long elapsedRealtimeMs, long uptimeMs, int stateFlags) {
- mHistoryCur.states &= ~stateFlags;
- writeHistoryItem(elapsedRealtimeMs, uptimeMs);
+ synchronized (this) {
+ mHistoryCur.states &= ~stateFlags;
+ writeHistoryItem(elapsedRealtimeMs, uptimeMs);
+ }
}
/**
@@ -1263,34 +1325,42 @@ public class BatteryStatsHistory {
*/
public void recordStateChangeEvent(long elapsedRealtimeMs, long uptimeMs, int stateStartFlags,
int stateStopFlags) {
- mHistoryCur.states = (mHistoryCur.states | stateStartFlags) & ~stateStopFlags;
- writeHistoryItem(elapsedRealtimeMs, uptimeMs);
+ synchronized (this) {
+ mHistoryCur.states = (mHistoryCur.states | stateStartFlags) & ~stateStopFlags;
+ writeHistoryItem(elapsedRealtimeMs, uptimeMs);
+ }
}
/**
* Records an event when some state2 flag changes to true.
*/
public void recordState2StartEvent(long elapsedRealtimeMs, long uptimeMs, int stateFlags) {
- mHistoryCur.states2 |= stateFlags;
- writeHistoryItem(elapsedRealtimeMs, uptimeMs);
+ synchronized (this) {
+ mHistoryCur.states2 |= stateFlags;
+ writeHistoryItem(elapsedRealtimeMs, uptimeMs);
+ }
}
/**
* Records an event when some state2 flag changes to false.
*/
public void recordState2StopEvent(long elapsedRealtimeMs, long uptimeMs, int stateFlags) {
- mHistoryCur.states2 &= ~stateFlags;
- writeHistoryItem(elapsedRealtimeMs, uptimeMs);
+ synchronized (this) {
+ mHistoryCur.states2 &= ~stateFlags;
+ writeHistoryItem(elapsedRealtimeMs, uptimeMs);
+ }
}
/**
* Records an wakeup event.
*/
public void recordWakeupEvent(long elapsedRealtimeMs, long uptimeMs, String reason) {
- mHistoryCur.wakeReasonTag = mHistoryCur.localWakeReasonTag;
- mHistoryCur.wakeReasonTag.string = reason;
- mHistoryCur.wakeReasonTag.uid = 0;
- writeHistoryItem(elapsedRealtimeMs, uptimeMs);
+ synchronized (this) {
+ mHistoryCur.wakeReasonTag = mHistoryCur.localWakeReasonTag;
+ mHistoryCur.wakeReasonTag.string = reason;
+ mHistoryCur.wakeReasonTag.uid = 0;
+ writeHistoryItem(elapsedRealtimeMs, uptimeMs);
+ }
}
/**
@@ -1298,10 +1368,12 @@ public class BatteryStatsHistory {
*/
public void recordScreenBrightnessEvent(long elapsedRealtimeMs, long uptimeMs,
int brightnessBin) {
- mHistoryCur.states = setBitField(mHistoryCur.states, brightnessBin,
- HistoryItem.STATE_BRIGHTNESS_SHIFT,
- HistoryItem.STATE_BRIGHTNESS_MASK);
- writeHistoryItem(elapsedRealtimeMs, uptimeMs);
+ synchronized (this) {
+ mHistoryCur.states = setBitField(mHistoryCur.states, brightnessBin,
+ HistoryItem.STATE_BRIGHTNESS_SHIFT,
+ HistoryItem.STATE_BRIGHTNESS_MASK);
+ writeHistoryItem(elapsedRealtimeMs, uptimeMs);
+ }
}
/**
@@ -1309,20 +1381,24 @@ public class BatteryStatsHistory {
*/
public void recordGpsSignalQualityEvent(long elapsedRealtimeMs, long uptimeMs,
int signalLevel) {
- mHistoryCur.states2 = setBitField(mHistoryCur.states2, signalLevel,
- HistoryItem.STATE2_GPS_SIGNAL_QUALITY_SHIFT,
- HistoryItem.STATE2_GPS_SIGNAL_QUALITY_MASK);
- writeHistoryItem(elapsedRealtimeMs, uptimeMs);
+ synchronized (this) {
+ mHistoryCur.states2 = setBitField(mHistoryCur.states2, signalLevel,
+ HistoryItem.STATE2_GPS_SIGNAL_QUALITY_SHIFT,
+ HistoryItem.STATE2_GPS_SIGNAL_QUALITY_MASK);
+ writeHistoryItem(elapsedRealtimeMs, uptimeMs);
+ }
}
/**
* Records a device idle mode change event.
*/
public void recordDeviceIdleEvent(long elapsedRealtimeMs, long uptimeMs, int mode) {
- mHistoryCur.states2 = setBitField(mHistoryCur.states2, mode,
- HistoryItem.STATE2_DEVICE_IDLE_SHIFT,
- HistoryItem.STATE2_DEVICE_IDLE_MASK);
- writeHistoryItem(elapsedRealtimeMs, uptimeMs);
+ synchronized (this) {
+ mHistoryCur.states2 = setBitField(mHistoryCur.states2, mode,
+ HistoryItem.STATE2_DEVICE_IDLE_SHIFT,
+ HistoryItem.STATE2_DEVICE_IDLE_MASK);
+ writeHistoryItem(elapsedRealtimeMs, uptimeMs);
+ }
}
/**
@@ -1330,20 +1406,22 @@ public class BatteryStatsHistory {
*/
public void recordPhoneStateChangeEvent(long elapsedRealtimeMs, long uptimeMs, int addStateFlag,
int removeStateFlag, int state, int signalStrength) {
- mHistoryCur.states = (mHistoryCur.states | addStateFlag) & ~removeStateFlag;
- if (state != -1) {
- mHistoryCur.states =
- setBitField(mHistoryCur.states, state,
- HistoryItem.STATE_PHONE_STATE_SHIFT,
- HistoryItem.STATE_PHONE_STATE_MASK);
- }
- if (signalStrength != -1) {
- mHistoryCur.states =
- setBitField(mHistoryCur.states, signalStrength,
- HistoryItem.STATE_PHONE_SIGNAL_STRENGTH_SHIFT,
- HistoryItem.STATE_PHONE_SIGNAL_STRENGTH_MASK);
+ synchronized (this) {
+ mHistoryCur.states = (mHistoryCur.states | addStateFlag) & ~removeStateFlag;
+ if (state != -1) {
+ mHistoryCur.states =
+ setBitField(mHistoryCur.states, state,
+ HistoryItem.STATE_PHONE_STATE_SHIFT,
+ HistoryItem.STATE_PHONE_STATE_MASK);
+ }
+ if (signalStrength != -1) {
+ mHistoryCur.states =
+ setBitField(mHistoryCur.states, signalStrength,
+ HistoryItem.STATE_PHONE_SIGNAL_STRENGTH_SHIFT,
+ HistoryItem.STATE_PHONE_SIGNAL_STRENGTH_MASK);
+ }
+ writeHistoryItem(elapsedRealtimeMs, uptimeMs);
}
- writeHistoryItem(elapsedRealtimeMs, uptimeMs);
}
/**
@@ -1351,10 +1429,12 @@ public class BatteryStatsHistory {
*/
public void recordDataConnectionTypeChangeEvent(long elapsedRealtimeMs, long uptimeMs,
int dataConnectionType) {
- mHistoryCur.states = setBitField(mHistoryCur.states, dataConnectionType,
- HistoryItem.STATE_DATA_CONNECTION_SHIFT,
- HistoryItem.STATE_DATA_CONNECTION_MASK);
- writeHistoryItem(elapsedRealtimeMs, uptimeMs);
+ synchronized (this) {
+ mHistoryCur.states = setBitField(mHistoryCur.states, dataConnectionType,
+ HistoryItem.STATE_DATA_CONNECTION_SHIFT,
+ HistoryItem.STATE_DATA_CONNECTION_MASK);
+ writeHistoryItem(elapsedRealtimeMs, uptimeMs);
+ }
}
/**
@@ -1362,10 +1442,12 @@ public class BatteryStatsHistory {
*/
public void recordNrStateChangeEvent(long elapsedRealtimeMs, long uptimeMs,
int nrState) {
- mHistoryCur.states2 = setBitField(mHistoryCur.states2, nrState,
- HistoryItem.STATE2_NR_STATE_SHIFT,
- HistoryItem.STATE2_NR_STATE_MASK);
- writeHistoryItem(elapsedRealtimeMs, uptimeMs);
+ synchronized (this) {
+ mHistoryCur.states2 = setBitField(mHistoryCur.states2, nrState,
+ HistoryItem.STATE2_NR_STATE_SHIFT,
+ HistoryItem.STATE2_NR_STATE_MASK);
+ writeHistoryItem(elapsedRealtimeMs, uptimeMs);
+ }
}
/**
@@ -1373,11 +1455,13 @@ public class BatteryStatsHistory {
*/
public void recordWifiSupplicantStateChangeEvent(long elapsedRealtimeMs, long uptimeMs,
int supplState) {
- mHistoryCur.states2 =
- setBitField(mHistoryCur.states2, supplState,
- HistoryItem.STATE2_WIFI_SUPPL_STATE_SHIFT,
- HistoryItem.STATE2_WIFI_SUPPL_STATE_MASK);
- writeHistoryItem(elapsedRealtimeMs, uptimeMs);
+ synchronized (this) {
+ mHistoryCur.states2 =
+ setBitField(mHistoryCur.states2, supplState,
+ HistoryItem.STATE2_WIFI_SUPPL_STATE_SHIFT,
+ HistoryItem.STATE2_WIFI_SUPPL_STATE_MASK);
+ writeHistoryItem(elapsedRealtimeMs, uptimeMs);
+ }
}
/**
@@ -1385,11 +1469,13 @@ public class BatteryStatsHistory {
*/
public void recordWifiSignalStrengthChangeEvent(long elapsedRealtimeMs, long uptimeMs,
int strengthBin) {
- mHistoryCur.states2 =
- setBitField(mHistoryCur.states2, strengthBin,
- HistoryItem.STATE2_WIFI_SIGNAL_STRENGTH_SHIFT,
- HistoryItem.STATE2_WIFI_SIGNAL_STRENGTH_MASK);
- writeHistoryItem(elapsedRealtimeMs, uptimeMs);
+ synchronized (this) {
+ mHistoryCur.states2 =
+ setBitField(mHistoryCur.states2, strengthBin,
+ HistoryItem.STATE2_WIFI_SIGNAL_STRENGTH_SHIFT,
+ HistoryItem.STATE2_WIFI_SIGNAL_STRENGTH_MASK);
+ writeHistoryItem(elapsedRealtimeMs, uptimeMs);
+ }
}
/**
@@ -1446,25 +1532,30 @@ public class BatteryStatsHistory {
* Writes the current history item to history.
*/
public void writeHistoryItem(long elapsedRealtimeMs, long uptimeMs) {
- if (mTrackRunningHistoryElapsedRealtimeMs != 0) {
- final long diffElapsedMs = elapsedRealtimeMs - mTrackRunningHistoryElapsedRealtimeMs;
- final long diffUptimeMs = uptimeMs - mTrackRunningHistoryUptimeMs;
- if (diffUptimeMs < (diffElapsedMs - 20)) {
- final long wakeElapsedTimeMs = elapsedRealtimeMs - (diffElapsedMs - diffUptimeMs);
- mHistoryAddTmp.setTo(mHistoryLastWritten);
- mHistoryAddTmp.wakelockTag = null;
- mHistoryAddTmp.wakeReasonTag = null;
- mHistoryAddTmp.eventCode = HistoryItem.EVENT_NONE;
- mHistoryAddTmp.states &= ~HistoryItem.STATE_CPU_RUNNING_FLAG;
- writeHistoryItem(wakeElapsedTimeMs, uptimeMs, mHistoryAddTmp);
+ synchronized (this) {
+ if (mTrackRunningHistoryElapsedRealtimeMs != 0) {
+ final long diffElapsedMs =
+ elapsedRealtimeMs - mTrackRunningHistoryElapsedRealtimeMs;
+ final long diffUptimeMs = uptimeMs - mTrackRunningHistoryUptimeMs;
+ if (diffUptimeMs < (diffElapsedMs - 20)) {
+ final long wakeElapsedTimeMs =
+ elapsedRealtimeMs - (diffElapsedMs - diffUptimeMs);
+ mHistoryAddTmp.setTo(mHistoryLastWritten);
+ mHistoryAddTmp.wakelockTag = null;
+ mHistoryAddTmp.wakeReasonTag = null;
+ mHistoryAddTmp.eventCode = HistoryItem.EVENT_NONE;
+ mHistoryAddTmp.states &= ~HistoryItem.STATE_CPU_RUNNING_FLAG;
+ writeHistoryItem(wakeElapsedTimeMs, uptimeMs, mHistoryAddTmp);
+ }
}
+ mHistoryCur.states |= HistoryItem.STATE_CPU_RUNNING_FLAG;
+ mTrackRunningHistoryElapsedRealtimeMs = elapsedRealtimeMs;
+ mTrackRunningHistoryUptimeMs = uptimeMs;
+ writeHistoryItem(elapsedRealtimeMs, uptimeMs, mHistoryCur);
}
- mHistoryCur.states |= HistoryItem.STATE_CPU_RUNNING_FLAG;
- mTrackRunningHistoryElapsedRealtimeMs = elapsedRealtimeMs;
- mTrackRunningHistoryUptimeMs = uptimeMs;
- writeHistoryItem(elapsedRealtimeMs, uptimeMs, mHistoryCur);
}
+ @GuardedBy("this")
private void writeHistoryItem(long elapsedRealtimeMs, long uptimeMs, HistoryItem cur) {
if (mTracer != null && mTracer.tracingEnabled()) {
recordTraceEvents(cur.eventCode, cur.eventTag);
@@ -1591,6 +1682,7 @@ public class BatteryStatsHistory {
writeHistoryItem(elapsedRealtimeMs, uptimeMs, cur, HistoryItem.CMD_UPDATE);
}
+ @GuardedBy("this")
private void writeHistoryItem(long elapsedRealtimeMs,
@SuppressWarnings("UnusedVariable") long uptimeMs, HistoryItem cur, byte cmd) {
if (!mMutable) {
@@ -1701,7 +1793,8 @@ public class BatteryStatsHistory {
/**
* Writes the delta between the previous and current history items into history buffer.
*/
- public void writeHistoryDelta(Parcel dest, HistoryItem cur, HistoryItem last) {
+ @GuardedBy("this")
+ private void writeHistoryDelta(Parcel dest, HistoryItem cur, HistoryItem last) {
if (last == null || cur.cmd != HistoryItem.CMD_UPDATE) {
dest.writeInt(BatteryStatsHistory.DELTA_TIME_ABS);
cur.writeToParcel(dest, 0);
@@ -1921,6 +2014,7 @@ public class BatteryStatsHistory {
* while writing the current history buffer, the method returns
* <code>(index | TAG_FIRST_OCCURRENCE_FLAG)</code>
*/
+ @GuardedBy("this")
private int writeHistoryTag(HistoryTag tag) {
if (tag.string == null) {
Slog.wtfStack(TAG, "writeHistoryTag called with null name");
@@ -1964,33 +2058,37 @@ public class BatteryStatsHistory {
* Don't allow any more batching in to the current history event.
*/
public void commitCurrentHistoryBatchLocked() {
- mHistoryLastWritten.cmd = HistoryItem.CMD_NULL;
+ synchronized (this) {
+ mHistoryLastWritten.cmd = HistoryItem.CMD_NULL;
+ }
}
/**
* Saves the accumulated history buffer in the active file, see {@link #getActiveFile()} .
*/
public void writeHistory() {
- if (isReadOnly()) {
- Slog.w(TAG, "writeHistory: this instance instance is read-only");
- return;
- }
+ synchronized (this) {
+ if (isReadOnly()) {
+ Slog.w(TAG, "writeHistory: this instance instance is read-only");
+ return;
+ }
- // Save the monotonic time first, so that even if the history write below fails,
- // we still wouldn't end up with overlapping history timelines.
- mMonotonicClock.write();
+ // Save the monotonic time first, so that even if the history write below fails,
+ // we still wouldn't end up with overlapping history timelines.
+ mMonotonicClock.write();
- Parcel p = Parcel.obtain();
- try {
- final long start = SystemClock.uptimeMillis();
- writeHistoryBuffer(p);
- if (DEBUG) {
- Slog.d(TAG, "writeHistoryBuffer duration ms:"
- + (SystemClock.uptimeMillis() - start) + " bytes:" + p.dataSize());
+ Parcel p = Parcel.obtain();
+ try {
+ final long start = SystemClock.uptimeMillis();
+ writeHistoryBuffer(p);
+ if (DEBUG) {
+ Slog.d(TAG, "writeHistoryBuffer duration ms:"
+ + (SystemClock.uptimeMillis() - start) + " bytes:" + p.dataSize());
+ }
+ writeParcelToFileLocked(p, mActiveFile);
+ } finally {
+ p.recycle();
}
- writeParcelToFileLocked(p, mActiveFile);
- } finally {
- p.recycle();
}
}
@@ -1998,35 +2096,38 @@ public class BatteryStatsHistory {
* Reads history buffer from a persisted Parcel.
*/
public void readHistoryBuffer(Parcel in) throws ParcelFormatException {
- final int version = in.readInt();
- if (version != BatteryStatsHistory.VERSION) {
- Slog.w("BatteryStats", "readHistoryBuffer: version got " + version
- + ", expected " + BatteryStatsHistory.VERSION + "; erasing old stats");
- return;
- }
-
- mHistoryBufferStartTime = in.readLong();
- mHistoryBuffer.setDataSize(0);
- mHistoryBuffer.setDataPosition(0);
+ synchronized (this) {
+ final int version = in.readInt();
+ if (version != BatteryStatsHistory.VERSION) {
+ Slog.w("BatteryStats", "readHistoryBuffer: version got " + version
+ + ", expected " + BatteryStatsHistory.VERSION + "; erasing old stats");
+ return;
+ }
- int bufSize = in.readInt();
- int curPos = in.dataPosition();
- if (bufSize >= (mMaxHistoryBufferSize * 100)) {
- throw new ParcelFormatException(
- "File corrupt: history data buffer too large " + bufSize);
- } else if ((bufSize & ~3) != bufSize) {
- throw new ParcelFormatException(
- "File corrupt: history data buffer not aligned " + bufSize);
- } else {
- if (DEBUG) {
- Slog.i(TAG, "***************** READING NEW HISTORY: " + bufSize
- + " bytes at " + curPos);
+ mHistoryBufferStartTime = in.readLong();
+ mHistoryBuffer.setDataSize(0);
+ mHistoryBuffer.setDataPosition(0);
+
+ int bufSize = in.readInt();
+ int curPos = in.dataPosition();
+ if (bufSize >= (mMaxHistoryBufferSize * 100)) {
+ throw new ParcelFormatException(
+ "File corrupt: history data buffer too large " + bufSize);
+ } else if ((bufSize & ~3) != bufSize) {
+ throw new ParcelFormatException(
+ "File corrupt: history data buffer not aligned " + bufSize);
+ } else {
+ if (DEBUG) {
+ Slog.i(TAG, "***************** READING NEW HISTORY: " + bufSize
+ + " bytes at " + curPos);
+ }
+ mHistoryBuffer.appendFrom(in, curPos, bufSize);
+ in.setDataPosition(curPos + bufSize);
}
- mHistoryBuffer.appendFrom(in, curPos, bufSize);
- in.setDataPosition(curPos + bufSize);
}
}
+ @GuardedBy("this")
private void writeHistoryBuffer(Parcel out) {
out.writeInt(BatteryStatsHistory.VERSION);
out.writeLong(mHistoryBufferStartTime);
@@ -2038,6 +2139,7 @@ public class BatteryStatsHistory {
out.appendFrom(mHistoryBuffer, 0, mHistoryBuffer.dataSize());
}
+ @GuardedBy("this")
private void writeParcelToFileLocked(Parcel p, AtomicFile file) {
FileOutputStream fos = null;
mWriteLock.lock();
@@ -2066,34 +2168,43 @@ public class BatteryStatsHistory {
* Returns the total number of history tags in the tag pool.
*/
public int getHistoryStringPoolSize() {
- return mHistoryTagPool.size();
+ synchronized (this) {
+ return mHistoryTagPool.size();
+ }
}
/**
* Returns the total number of bytes occupied by the history tag pool.
*/
public int getHistoryStringPoolBytes() {
- return mNumHistoryTagChars;
+ synchronized (this) {
+ return mNumHistoryTagChars;
+ }
}
/**
* Returns the string held by the requested history tag.
*/
public String getHistoryTagPoolString(int index) {
- ensureHistoryTagArray();
- HistoryTag historyTag = mHistoryTags.get(index);
- return historyTag != null ? historyTag.string : null;
+ synchronized (this) {
+ ensureHistoryTagArray();
+ HistoryTag historyTag = mHistoryTags.get(index);
+ return historyTag != null ? historyTag.string : null;
+ }
}
/**
* Returns the UID held by the requested history tag.
*/
public int getHistoryTagPoolUid(int index) {
- ensureHistoryTagArray();
- HistoryTag historyTag = mHistoryTags.get(index);
- return historyTag != null ? historyTag.uid : Process.INVALID_UID;
+ synchronized (this) {
+ ensureHistoryTagArray();
+ HistoryTag historyTag = mHistoryTags.get(index);
+ return historyTag != null ? historyTag.uid : Process.INVALID_UID;
+ }
}
+ @GuardedBy("this")
private void ensureHistoryTagArray() {
if (mHistoryTags != null) {
return;
diff --git a/core/res/AndroidManifest.xml b/core/res/AndroidManifest.xml
index c4b5d8187845..0171f584a838 100644
--- a/core/res/AndroidManifest.xml
+++ b/core/res/AndroidManifest.xml
@@ -3751,6 +3751,13 @@
<permission android:name="android.permission.MANAGE_DEVICE_POLICY_DEVICE_IDENTIFIERS"
android:protectionLevel="internal|role" />
+ <!-- Allows an application to manage policy related to content protection.
+ <p>Protection level: internal|role
+ @FlaggedApi("android.view.contentprotection.flags.manage_device_policy_enabled")
+ -->
+ <permission android:name="android.permission.MANAGE_DEVICE_POLICY_CONTENT_PROTECTION"
+ android:protectionLevel="internal|role" />
+
<!-- Allows an application to set device policies outside the current user
that are critical for securing data within the current user.
<p>Holding this permission allows the use of other held MANAGE_DEVICE_POLICY_*
diff --git a/core/res/res/values/config.xml b/core/res/res/values/config.xml
index 23c78fdf108e..ebb0d344d7eb 100644
--- a/core/res/res/values/config.xml
+++ b/core/res/res/values/config.xml
@@ -6908,4 +6908,7 @@
<!-- Defines the minimum interval (in ms) between two input-based user-activity poke events. -->
<integer name="config_minMillisBetweenInputUserActivityEvents">100</integer>
+
+ <!-- Name of the starting activity for DisplayCompat host. specific to automotive.-->
+ <string name="config_defaultDisplayCompatHostActivity" translatable="false"></string>
</resources>
diff --git a/core/tests/coretests/src/android/os/BundleTest.java b/core/tests/coretests/src/android/os/BundleTest.java
index e7b5dff60110..93c2e0e40593 100644
--- a/core/tests/coretests/src/android/os/BundleTest.java
+++ b/core/tests/coretests/src/android/os/BundleTest.java
@@ -20,6 +20,7 @@ import static com.google.common.truth.Truth.assertThat;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertThrows;
import static org.junit.Assert.assertTrue;
@@ -121,6 +122,14 @@ public class BundleTest {
}
@Test
+ public void testEmpty() throws Exception {
+ assertNotNull(Bundle.EMPTY);
+ assertEquals(0, Bundle.EMPTY.size());
+
+ new Bundle(Bundle.EMPTY);
+ }
+
+ @Test
@IgnoreUnderRavenwood(blockedBy = ParcelFileDescriptor.class)
public void testCreateFromParcel() throws Exception {
boolean withFd;
diff --git a/core/tests/coretests/src/android/os/TestLooperManagerTest.java b/core/tests/coretests/src/android/os/TestLooperManagerTest.java
new file mode 100644
index 000000000000..5959444e49cc
--- /dev/null
+++ b/core/tests/coretests/src/android/os/TestLooperManagerTest.java
@@ -0,0 +1,91 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.os;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertNull;
+import static org.junit.Assert.assertTrue;
+
+import android.platform.test.ravenwood.RavenwoodRule;
+
+import androidx.test.platform.app.InstrumentationRegistry;
+import androidx.test.runner.AndroidJUnit4;
+
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import java.util.concurrent.CountDownLatch;
+import java.util.concurrent.TimeUnit;
+
+@RunWith(AndroidJUnit4.class)
+public class TestLooperManagerTest {
+ private static final String TAG = "TestLooperManagerTest";
+
+ @Rule
+ public final RavenwoodRule mRavenwood = new RavenwoodRule.Builder()
+ .setProvideMainThread(true)
+ .build();
+
+ @Test
+ public void testMainThread() throws Exception {
+ doTest(Looper.getMainLooper());
+ }
+
+ @Test
+ public void testCustomThread() throws Exception {
+ final HandlerThread thread = new HandlerThread(TAG);
+ thread.start();
+ doTest(thread.getLooper());
+ }
+
+ private void doTest(Looper looper) throws Exception {
+ final TestLooperManager tlm =
+ InstrumentationRegistry.getInstrumentation().acquireLooperManager(looper);
+
+ final Handler handler = new Handler(looper);
+ final CountDownLatch latch = new CountDownLatch(1);
+
+ assertFalse(tlm.hasMessages(handler, null, 42));
+
+ handler.sendEmptyMessage(42);
+ handler.post(() -> {
+ latch.countDown();
+ });
+ assertTrue(tlm.hasMessages(handler, null, 42));
+ assertFalse(latch.await(100, TimeUnit.MILLISECONDS));
+
+ final Message first = tlm.next();
+ assertEquals(42, first.what);
+ assertNull(first.callback);
+ tlm.execute(first);
+ assertFalse(tlm.hasMessages(handler, null, 42));
+ assertFalse(latch.await(100, TimeUnit.MILLISECONDS));
+ tlm.recycle(first);
+
+ final Message second = tlm.next();
+ assertNotNull(second.callback);
+ tlm.execute(second);
+ assertFalse(tlm.hasMessages(handler, null, 42));
+ assertTrue(latch.await(100, TimeUnit.MILLISECONDS));
+ tlm.recycle(second);
+
+ tlm.release();
+ }
+}
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopModeVisualIndicator.java b/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopModeVisualIndicator.java
index da1ca8d57940..6250fc5820aa 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopModeVisualIndicator.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopModeVisualIndicator.java
@@ -17,6 +17,8 @@
package com.android.wm.shell.desktopmode;
import static android.app.WindowConfiguration.WINDOWING_MODE_FREEFORM;
+import static android.view.WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE;
+import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION;
import static com.android.wm.shell.desktopmode.EnterDesktopTaskTransitionHandler.FINAL_FREEFORM_SCALE;
@@ -86,7 +88,6 @@ public class DesktopModeVisualIndicator {
mTaskSurface = taskSurface;
mRootTdaOrganizer = taskDisplayAreaOrganizer;
mCurrentType = IndicatorType.NO_INDICATOR;
- createView();
}
/**
@@ -127,34 +128,15 @@ public class DesktopModeVisualIndicator {
mView = new View(mContext);
final SurfaceControl.Builder builder = new SurfaceControl.Builder();
mRootTdaOrganizer.attachToDisplayArea(mTaskInfo.displayId, builder);
- String description;
- switch (mCurrentType) {
- case TO_DESKTOP_INDICATOR:
- description = "Desktop indicator";
- break;
- case TO_FULLSCREEN_INDICATOR:
- description = "Fullscreen indicator";
- break;
- case TO_SPLIT_LEFT_INDICATOR:
- description = "Split Left indicator";
- break;
- case TO_SPLIT_RIGHT_INDICATOR:
- description = "Split Right indicator";
- break;
- default:
- description = "Invalid indicator";
- break;
- }
mLeash = builder
- .setName(description)
+ .setName("Desktop Mode Visual Indicator")
.setContainerLayer()
.build();
t.show(mLeash);
final WindowManager.LayoutParams lp =
- new WindowManager.LayoutParams(screenWidth, screenHeight,
- WindowManager.LayoutParams.TYPE_APPLICATION,
- WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE, PixelFormat.TRANSPARENT);
- lp.setTitle(description + " for Task=" + mTaskInfo.taskId);
+ new WindowManager.LayoutParams(screenWidth, screenHeight, TYPE_APPLICATION,
+ FLAG_NOT_FOCUSABLE, PixelFormat.TRANSPARENT);
+ lp.setTitle("Desktop Mode Visual Indicator");
lp.setTrustedOverlay();
final WindowlessWindowManager windowManager = new WindowlessWindowManager(
mTaskInfo.configuration, mLeash,
@@ -201,6 +183,9 @@ public class DesktopModeVisualIndicator {
*/
private void transitionIndicator(IndicatorType newType) {
if (mCurrentType == newType) return;
+ if (mView == null) {
+ createView();
+ }
if (mCurrentType == IndicatorType.NO_INDICATOR) {
fadeInIndicator(newType);
} else if (newType == IndicatorType.NO_INDICATOR) {
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopTasksController.kt b/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopTasksController.kt
index 4f5c39a60120..28c06a46c516 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopTasksController.kt
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopTasksController.kt
@@ -919,22 +919,27 @@ class DesktopTasksController(
}
if (taskBounds.top <= transitionAreaHeight) {
moveToFullscreenWithAnimation(taskInfo, position)
+ return
}
if (inputCoordinate.x <= transitionAreaWidth) {
releaseVisualIndicator()
- var wct = WindowContainerTransaction()
+ val wct = WindowContainerTransaction()
addMoveToSplitChanges(wct, taskInfo)
splitScreenController.requestEnterSplitSelect(taskInfo, wct,
SPLIT_POSITION_TOP_OR_LEFT, taskBounds)
+ return
}
if (inputCoordinate.x >= (displayController.getDisplayLayout(taskInfo.displayId)?.width()
?.minus(transitionAreaWidth) ?: return)) {
releaseVisualIndicator()
- var wct = WindowContainerTransaction()
+ val wct = WindowContainerTransaction()
addMoveToSplitChanges(wct, taskInfo)
splitScreenController.requestEnterSplitSelect(taskInfo, wct,
SPLIT_POSITION_BOTTOM_OR_RIGHT, taskBounds)
+ return
}
+ // A freeform drag-move ended, remove the indicator immediately.
+ releaseVisualIndicator()
}
/**
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 e6faa6391cca..96eaa1edbae4 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
@@ -287,7 +287,7 @@ public class CaptionWindowDecoration extends WindowDecoration<WindowDecorLinearL
}
boolean isHandlingDragResize() {
- return mDragResizeListener.isHandlingDragResize();
+ return mDragResizeListener != null && mDragResizeListener.isHandlingDragResize();
}
private void closeDragResizeListener() {
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/DesktopModeWindowDecorViewModel.java b/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/DesktopModeWindowDecorViewModel.java
index 4ba05ce8aef1..1f7cc5a18019 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/DesktopModeWindowDecorViewModel.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/DesktopModeWindowDecorViewModel.java
@@ -345,7 +345,7 @@ public class DesktopModeWindowDecorViewModel implements WindowDecorViewModel {
mTaskOperations.injectBackKey();
} else if (id == R.id.caption_handle || id == R.id.open_menu_button) {
if (!decoration.isHandleMenuActive()) {
- moveTaskToFront(mTaskOrganizer.getRunningTaskInfo(mTaskId));
+ moveTaskToFront(decoration.mTaskInfo);
decoration.createHandleMenu();
} else {
decoration.closeHandleMenu();
@@ -419,10 +419,10 @@ public class DesktopModeWindowDecorViewModel implements WindowDecorViewModel {
&& id != R.id.maximize_window) {
return false;
}
- moveTaskToFront(mTaskOrganizer.getRunningTaskInfo(mTaskId));
+ final DesktopModeWindowDecoration decoration = mWindowDecorByTaskId.get(mTaskId);
+ moveTaskToFront(decoration.mTaskInfo);
if (!mHasLongClicked && id != R.id.maximize_window) {
- final DesktopModeWindowDecoration decoration = mWindowDecorByTaskId.get(mTaskId);
decoration.closeMaximizeMenuIfNeeded(e);
}
@@ -466,7 +466,8 @@ public class DesktopModeWindowDecorViewModel implements WindowDecorViewModel {
*/
@Override
public boolean handleMotionEvent(@Nullable View v, MotionEvent e) {
- final RunningTaskInfo taskInfo = mTaskOrganizer.getRunningTaskInfo(mTaskId);
+ final DesktopModeWindowDecoration decoration = mWindowDecorByTaskId.get(mTaskId);
+ final RunningTaskInfo taskInfo = decoration.mTaskInfo;
if (DesktopModeStatus.isEnabled()
&& taskInfo.getWindowingMode() == WINDOWING_MODE_FULLSCREEN) {
return false;
@@ -492,8 +493,6 @@ public class DesktopModeWindowDecorViewModel implements WindowDecorViewModel {
}
case MotionEvent.ACTION_MOVE: {
mShouldClick = false;
- final DesktopModeWindowDecoration decoration =
- mWindowDecorByTaskId.get(mTaskId);
// If a decor's resize drag zone is active, don't also try to reposition it.
if (decoration.isHandlingDragResize()) break;
decoration.closeMaximizeMenu();
@@ -557,9 +556,10 @@ public class DesktopModeWindowDecorViewModel implements WindowDecorViewModel {
&& action != MotionEvent.ACTION_CANCEL)) {
return false;
}
- final RunningTaskInfo taskInfo = mTaskOrganizer.getRunningTaskInfo(mTaskId);
- mDesktopTasksController.ifPresent(c -> c.toggleDesktopTaskSize(taskInfo,
- mWindowDecorByTaskId.get(taskInfo.taskId)));
+ mDesktopTasksController.ifPresent(c -> {
+ final DesktopModeWindowDecoration decoration = mWindowDecorByTaskId.get(mTaskId);
+ c.toggleDesktopTaskSize(decoration.mTaskInfo, decoration);
+ });
return true;
}
}
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 71e1582d2937..3f0a28118597 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
@@ -387,7 +387,7 @@ public class DesktopModeWindowDecoration extends WindowDecoration<WindowDecorLin
}
boolean isHandlingDragResize() {
- return mDragResizeListener.isHandlingDragResize();
+ return mDragResizeListener != null && mDragResizeListener.isHandlingDragResize();
}
private void loadAppInfo() {
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/DragResizeInputListener.java b/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/DragResizeInputListener.java
index 8b38f991a2db..d902621180d8 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/DragResizeInputListener.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/DragResizeInputListener.java
@@ -353,6 +353,7 @@ class DragResizeInputListener implements AutoCloseable {
private boolean mShouldHandleEvents;
private int mLastCursorType = PointerIcon.TYPE_DEFAULT;
private Rect mDragStartTaskBounds;
+ private final Rect mTmpRect = new Rect();
private TaskResizeInputEventReceiver(
InputChannel inputChannel, Handler handler, Choreographer choreographer) {
@@ -477,14 +478,15 @@ class DragResizeInputListener implements AutoCloseable {
}
private void updateInputSinkRegionForDrag(Rect taskBounds) {
+ mTmpRect.set(taskBounds);
final DisplayLayout layout = mDisplayController.getDisplayLayout(mDisplayId);
final Region dragTouchRegion = new Region(-taskBounds.left,
-taskBounds.top,
-taskBounds.left + layout.width(),
-taskBounds.top + layout.height());
// Remove the localized task bounds from the touch region.
- taskBounds.offsetTo(0, 0);
- dragTouchRegion.op(taskBounds, Region.Op.DIFFERENCE);
+ mTmpRect.offsetTo(0, 0);
+ dragTouchRegion.op(mTmpRect, Region.Op.DIFFERENCE);
updateSinkInputChannel(dragTouchRegion);
}
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/ResizeVeil.java b/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/ResizeVeil.java
index 368231e2d7f0..b0d3b5090ef0 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/ResizeVeil.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/ResizeVeil.java
@@ -125,6 +125,7 @@ public class ResizeVeil {
relayout(taskBounds, t);
if (fadeIn) {
+ cancelAnimation();
mVeilAnimator = new ValueAnimator();
mVeilAnimator.setFloatValues(0f, 1f);
mVeilAnimator.setDuration(RESIZE_ALPHA_DURATION);
@@ -210,15 +211,16 @@ public class ResizeVeil {
* Animate veil's alpha to 0, fading it out.
*/
public void hideVeil() {
- final ValueAnimator animator = new ValueAnimator();
- animator.setFloatValues(1, 0);
- animator.setDuration(RESIZE_ALPHA_DURATION);
- animator.addUpdateListener(animation -> {
+ cancelAnimation();
+ mVeilAnimator = new ValueAnimator();
+ mVeilAnimator.setFloatValues(1, 0);
+ mVeilAnimator.setDuration(RESIZE_ALPHA_DURATION);
+ mVeilAnimator.addUpdateListener(animation -> {
SurfaceControl.Transaction t = mSurfaceControlTransactionSupplier.get();
- t.setAlpha(mVeilSurface, 1 - animator.getAnimatedFraction());
+ t.setAlpha(mVeilSurface, 1 - mVeilAnimator.getAnimatedFraction());
t.apply();
});
- animator.addListener(new AnimatorListenerAdapter() {
+ mVeilAnimator.addListener(new AnimatorListenerAdapter() {
@Override
public void onAnimationEnd(Animator animation) {
SurfaceControl.Transaction t = mSurfaceControlTransactionSupplier.get();
@@ -226,7 +228,7 @@ public class ResizeVeil {
t.apply();
}
});
- animator.start();
+ mVeilAnimator.start();
}
@ColorRes
@@ -240,10 +242,20 @@ public class ResizeVeil {
}
}
+ private void cancelAnimation() {
+ if (mVeilAnimator != null) {
+ mVeilAnimator.removeAllUpdateListeners();
+ mVeilAnimator.cancel();
+ }
+ }
+
/**
* Dispose of veil when it is no longer needed, likely on close of its container decor.
*/
void dispose() {
+ cancelAnimation();
+ mVeilAnimator = null;
+
if (mViewHost != null) {
mViewHost.release();
mViewHost = null;
diff --git a/media/java/android/media/MediaRecorder.java b/media/java/android/media/MediaRecorder.java
index aa307485c32e..bdfa63010adc 100644
--- a/media/java/android/media/MediaRecorder.java
+++ b/media/java/android/media/MediaRecorder.java
@@ -65,7 +65,8 @@ import java.util.concurrent.Executor;
*
* <p>A common case of using MediaRecorder to record audio works as follows:
*
- * <pre>MediaRecorder recorder = new MediaRecorder();
+ * <pre>
+ * MediaRecorder recorder = new MediaRecorder(context);
* recorder.setAudioSource(MediaRecorder.AudioSource.MIC);
* recorder.setOutputFormat(MediaRecorder.OutputFormat.THREE_GPP);
* recorder.setAudioEncoder(MediaRecorder.AudioEncoder.AMR_NB);
diff --git a/media/java/android/media/projection/IMediaProjection.aidl b/media/java/android/media/projection/IMediaProjection.aidl
index 388b2c5ca6fe..2fb0af5557b5 100644
--- a/media/java/android/media/projection/IMediaProjection.aidl
+++ b/media/java/android/media/projection/IMediaProjection.aidl
@@ -18,6 +18,7 @@ package android.media.projection;
import android.media.projection.IMediaProjectionCallback;
import android.os.IBinder;
+import android.app.ActivityOptions.LaunchCookie;
/** {@hide} */
interface IMediaProjection {
@@ -38,22 +39,22 @@ interface IMediaProjection {
void unregisterCallback(IMediaProjectionCallback callback);
/**
- * Returns the {@link android.os.IBinder} identifying the task to record, or {@code null} if
+ * Returns the {@link LaunchCookie} identifying the task to record, or {@code null} if
* there is none.
*/
@EnforcePermission("MANAGE_MEDIA_PROJECTION")
@JavaPassthrough(annotation = "@android.annotation.RequiresPermission(android.Manifest"
+ ".permission.MANAGE_MEDIA_PROJECTION)")
- IBinder getLaunchCookie();
+ LaunchCookie getLaunchCookie();
/**
- * Updates the {@link android.os.IBinder} identifying the task to record, or {@code null} if
+ * Updates the {@link LaunchCookie} identifying the task to record, or {@code null} if
* there is none.
*/
@EnforcePermission("MANAGE_MEDIA_PROJECTION")
@JavaPassthrough(annotation = "@android.annotation.RequiresPermission(android.Manifest"
+ ".permission.MANAGE_MEDIA_PROJECTION)")
- void setLaunchCookie(in IBinder launchCookie);
+ void setLaunchCookie(in LaunchCookie launchCookie);
/**
* Returns {@code true} if this token is still valid. A token is valid as long as the token
diff --git a/media/java/android/media/projection/MediaProjectionInfo.java b/media/java/android/media/projection/MediaProjectionInfo.java
index c82039297d6e..cd0763d4d459 100644
--- a/media/java/android/media/projection/MediaProjectionInfo.java
+++ b/media/java/android/media/projection/MediaProjectionInfo.java
@@ -16,7 +16,7 @@
package android.media.projection;
-import android.os.IBinder;
+import android.app.ActivityOptions.LaunchCookie;
import android.os.Parcel;
import android.os.Parcelable;
import android.os.UserHandle;
@@ -27,9 +27,9 @@ import java.util.Objects;
public final class MediaProjectionInfo implements Parcelable {
private final String mPackageName;
private final UserHandle mUserHandle;
- private final IBinder mLaunchCookie;
+ private final LaunchCookie mLaunchCookie;
- public MediaProjectionInfo(String packageName, UserHandle handle, IBinder launchCookie) {
+ public MediaProjectionInfo(String packageName, UserHandle handle, LaunchCookie launchCookie) {
mPackageName = packageName;
mUserHandle = handle;
mLaunchCookie = launchCookie;
@@ -38,7 +38,7 @@ public final class MediaProjectionInfo implements Parcelable {
public MediaProjectionInfo(Parcel in) {
mPackageName = in.readString();
mUserHandle = UserHandle.readFromParcel(in);
- mLaunchCookie = in.readStrongBinder();
+ mLaunchCookie = LaunchCookie.readFromParcel(in);
}
public String getPackageName() {
@@ -49,7 +49,7 @@ public final class MediaProjectionInfo implements Parcelable {
return mUserHandle;
}
- public IBinder getLaunchCookie() {
+ public LaunchCookie getLaunchCookie() {
return mLaunchCookie;
}
@@ -72,7 +72,7 @@ public final class MediaProjectionInfo implements Parcelable {
public String toString() {
return "MediaProjectionInfo{mPackageName="
+ mPackageName + ", mUserHandle="
- + mUserHandle + ", mLaunchCookie"
+ + mUserHandle + ", mLaunchCookie="
+ mLaunchCookie + "}";
}
@@ -85,7 +85,7 @@ public final class MediaProjectionInfo implements Parcelable {
public void writeToParcel(Parcel out, int flags) {
out.writeString(mPackageName);
UserHandle.writeToParcel(mUserHandle, out);
- out.writeStrongBinder(mLaunchCookie);
+ LaunchCookie.writeToParcel(mLaunchCookie, out);
}
public static final @android.annotation.NonNull Parcelable.Creator<MediaProjectionInfo> CREATOR =
diff --git a/media/java/android/media/projection/MediaProjectionManager.java b/media/java/android/media/projection/MediaProjectionManager.java
index 9790d02025b7..e3290d604794 100644
--- a/media/java/android/media/projection/MediaProjectionManager.java
+++ b/media/java/android/media/projection/MediaProjectionManager.java
@@ -18,8 +18,11 @@ package android.media.projection;
import android.annotation.NonNull;
import android.annotation.Nullable;
+import android.annotation.SuppressLint;
import android.annotation.SystemService;
+import android.annotation.TestApi;
import android.app.Activity;
+import android.app.ActivityOptions.LaunchCookie;
import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
@@ -73,6 +76,9 @@ public final class MediaProjectionManager {
/** @hide */
public static final String EXTRA_MEDIA_PROJECTION =
"android.media.projection.extra.EXTRA_MEDIA_PROJECTION";
+ /** @hide */
+ public static final String EXTRA_LAUNCH_COOKIE =
+ "android.media.projection.extra.EXTRA_LAUNCH_COOKIE";
/** @hide */
public static final int TYPE_SCREEN_CAPTURE = 0;
@@ -158,17 +164,29 @@ public final class MediaProjectionManager {
*/
@NonNull
public Intent createScreenCaptureIntent(@NonNull MediaProjectionConfig config) {
- Intent i = new Intent();
- final ComponentName mediaProjectionPermissionDialogComponent =
- ComponentName.unflattenFromString(mContext.getResources()
- .getString(com.android.internal.R.string
- .config_mediaProjectionPermissionDialogComponent));
- i.setComponent(mediaProjectionPermissionDialogComponent);
+ Intent i = createScreenCaptureIntent();
i.putExtra(EXTRA_MEDIA_PROJECTION_CONFIG, config);
return i;
}
/**
+ * Returns an intent similar to {@link #createScreenCaptureIntent()} that will enable screen
+ * recording of the task with the specified launch cookie. This method should only be used for
+ * testing.
+ *
+ * @param launchCookie the launch cookie corresponding to the task to record.
+ * @hide
+ */
+ @SuppressLint("UnflaggedApi")
+ @TestApi
+ @NonNull
+ public Intent createScreenCaptureIntent(@Nullable LaunchCookie launchCookie) {
+ Intent i = createScreenCaptureIntent();
+ i.putExtra(EXTRA_LAUNCH_COOKIE, launchCookie);
+ return i;
+ }
+
+ /**
* Retrieves the {@link MediaProjection} obtained from a successful screen
* capture request. The result code and data from the request are provided by overriding
* {@link Activity#onActivityResult(int, int, Intent) onActivityResult(int, int, Intent)},
diff --git a/media/java/android/media/tv/SignalingDataRequest.aidl b/media/java/android/media/tv/SignalingDataRequest.aidl
new file mode 100644
index 000000000000..29e89fe4142b
--- /dev/null
+++ b/media/java/android/media/tv/SignalingDataRequest.aidl
@@ -0,0 +1,3 @@
+package android.media.tv;
+
+parcelable SignalingDataRequest;
diff --git a/media/java/android/media/tv/SignalingDataRequest.java b/media/java/android/media/tv/SignalingDataRequest.java
new file mode 100644
index 000000000000..dcf1d48aaf3a
--- /dev/null
+++ b/media/java/android/media/tv/SignalingDataRequest.java
@@ -0,0 +1,170 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.media.tv;
+
+import android.annotation.NonNull;
+import android.os.Parcelable;
+
+/**
+ * Request to retrieve the Low-level Signalling Tables (LLS) and Service-layer Signalling (SLS)
+ * metadata.
+ *
+ * <p>For more details on each type of metadata that can be requested, refer to the ATSC standard
+ * A/344:2023-5 9.2.10 - Query Signaling Data API.
+ *
+ * @hide
+ */
+public class SignalingDataRequest extends BroadcastInfoRequest implements Parcelable {
+ private static final @TvInputManager.BroadcastInfoType int REQUEST_TYPE =
+ TvInputManager.BROADCAST_INFO_TYPE_SIGNALING_DATA;
+
+ public static final @NonNull Parcelable.Creator<SignalingDataRequest> CREATOR =
+ new Parcelable.Creator<SignalingDataRequest>() {
+ @Override
+ public SignalingDataRequest[] newArray(int size) {
+ return new SignalingDataRequest[size];
+ }
+
+ @Override
+ public SignalingDataRequest createFromParcel(@NonNull android.os.Parcel in) {
+ return new SignalingDataRequest(in);
+ }
+ };
+
+ /** SLS Metadata: All metadata objects for the requested service(s) */
+ public static final int SLS_METADATA_ALL = 0x7FFFFFF;
+
+ /** SLS Metadata: APD for the requested service(s) */
+ public static final int SLS_METADATA_APD = 1;
+
+ /** SLS Metadata: USBD for the requested service(s) */
+ public static final int SLS_METADATA_USBD = 1 << 1;
+
+ /** SLS Metadata: S-TSID for the requested service(s) */
+ public static final int SLS_METADATA_STSID = 1 << 2;
+
+ /** SLS Metadata: DASH MPD for the requested service(s) */
+ public static final int SLS_METADATA_MPD = 1 << 3;
+
+ /** SLS Metadata: User Service Description for MMTP */
+ public static final int SLS_METADATA_USD = 1 << 4;
+
+ /** SLS Metadata: MMT Package Access Table for the requested service(s) */
+ public static final int SLS_METADATA_PAT = 1 << 5;
+
+ /** SLS Metadata: MMT Package Table for the requested service(s) */
+ public static final int SLS_METADATA_MPT = 1 << 6;
+
+ /** SLS Metadata: MMT Media Presentation Information Table for the requested service(s) */
+ public static final int SLS_METADATA_MPIT = 1 << 7;
+
+ /** SLS Metadata: MMT Clock Relation Information for the requested service(s) */
+ public static final int SLS_METADATA_CRIT = 1 << 8;
+
+ /** SLS Metadata: MMT Device Capabilities Information Table for the requested service(s) */
+ public static final int SLS_METADATA_DCIT = 1 << 9;
+
+ /** SLS Metadata: HTML Entry Pages Location Description for the requested service(s) */
+ public static final int SLS_METADATA_HELD = 1 << 10;
+
+ /** SLS Metadata: Distribution Window Desciription for the requested service(s) */
+ public static final int SLS_METADATA_DWD = 1 << 11;
+
+ /** SLS Metadata: MMT Application Event Information for the requested service(s) */
+ public static final int SLS_METADATA_AEI = 1 << 12;
+
+ /** SLS Metadata: Video Stream Properties Descriptor */
+ public static final int SLS_METADATA_VSPD = 1 << 13;
+
+ /** SLS Metadata: ATSC Staggercast Descriptor */
+ public static final int SLS_METADATA_ASD = 1 << 14;
+
+ /** SLS Metadata: Inband Event Descriptor */
+ public static final int SLS_METADATA_IED = 1 << 15;
+
+ /** SLS Metadata: Caption Asset Descriptor */
+ public static final int SLS_METADATA_CAD = 1 << 16;
+
+ /** SLS Metadata: Audio Stream Properties Descriptor */
+ public static final int SLS_METADATA_ASPD = 1 << 17;
+
+ /** SLS Metadata: Security Properties Descriptor */
+ public static final int SLS_METADATA_SSD = 1 << 18;
+
+ /** SLS Metadata: ROUTE/DASH Application Dynamic Event for the requested service(s) */
+ public static final int SLS_METADATA_EMSG = 1 << 19;
+
+ /** SLS Metadata: MMT Application Dynamic Event for the requested service(s) */
+ public static final int SLS_METADATA_EVTI = 1 << 20;
+
+ /** Regional Service Availability Table for the requested service(s) */
+ public static final int SLS_METADATA_RSAT = 1 << 21;
+
+ private final int mGroup;
+ private @NonNull final int[] mLlsTableIds;
+ private final int mSlsMetadataTypes;
+
+ SignalingDataRequest(
+ int requestId,
+ int option,
+ int group,
+ @NonNull int[] llsTableIds,
+ int slsMetadataTypes) {
+ super(REQUEST_TYPE, requestId, option);
+ mGroup = group;
+ mLlsTableIds = llsTableIds;
+ mSlsMetadataTypes = slsMetadataTypes;
+ }
+
+ SignalingDataRequest(@NonNull android.os.Parcel in) {
+ super(REQUEST_TYPE, in);
+
+ int group = in.readInt();
+ int[] llsTableIds = in.createIntArray();
+ int slsMetadataTypes = in.readInt();
+
+ this.mGroup = group;
+ this.mLlsTableIds = llsTableIds;
+ com.android.internal.util.AnnotationValidations.validate(NonNull.class, null, mLlsTableIds);
+ this.mSlsMetadataTypes = slsMetadataTypes;
+ }
+
+ public int getGroup() {
+ return mGroup;
+ }
+
+ public @NonNull int[] getLlsTableIds() {
+ return mLlsTableIds;
+ }
+
+ public int getSlsMetadataTypes() {
+ return mSlsMetadataTypes;
+ }
+
+ @Override
+ public void writeToParcel(@NonNull android.os.Parcel dest, int flags) {
+ super.writeToParcel(dest, flags);
+ dest.writeInt(mGroup);
+ dest.writeIntArray(mLlsTableIds);
+ dest.writeInt(mSlsMetadataTypes);
+ }
+
+ @Override
+ public int describeContents() {
+ return 0;
+ }
+}
diff --git a/media/java/android/media/tv/TvInputManager.java b/media/java/android/media/tv/TvInputManager.java
index 2b31bfef412e..be1b67547103 100644
--- a/media/java/android/media/tv/TvInputManager.java
+++ b/media/java/android/media/tv/TvInputManager.java
@@ -489,10 +489,19 @@ public final class TvInputManager {
/** @hide */
@Retention(RetentionPolicy.SOURCE)
- @IntDef(prefix = "BROADCAST_INFO_TYPE_", value =
- {BROADCAST_INFO_TYPE_TS, BROADCAST_INFO_TYPE_TABLE, BROADCAST_INFO_TYPE_SECTION,
- BROADCAST_INFO_TYPE_PES, BROADCAST_INFO_STREAM_EVENT, BROADCAST_INFO_TYPE_DSMCC,
- BROADCAST_INFO_TYPE_COMMAND, BROADCAST_INFO_TYPE_TIMELINE})
+ @IntDef(
+ prefix = "BROADCAST_INFO_TYPE_",
+ value = {
+ BROADCAST_INFO_TYPE_TS,
+ BROADCAST_INFO_TYPE_TABLE,
+ BROADCAST_INFO_TYPE_SECTION,
+ BROADCAST_INFO_TYPE_PES,
+ BROADCAST_INFO_STREAM_EVENT,
+ BROADCAST_INFO_TYPE_DSMCC,
+ BROADCAST_INFO_TYPE_COMMAND,
+ BROADCAST_INFO_TYPE_TIMELINE,
+ BROADCAST_INFO_TYPE_SIGNALING_DATA
+ })
public @interface BroadcastInfoType {}
public static final int BROADCAST_INFO_TYPE_TS = 1;
@@ -505,6 +514,9 @@ public final class TvInputManager {
public static final int BROADCAST_INFO_TYPE_TIMELINE = 8;
/** @hide */
+ public static final int BROADCAST_INFO_TYPE_SIGNALING_DATA = 9;
+
+ /** @hide */
@Retention(RetentionPolicy.SOURCE)
@IntDef(prefix = "SIGNAL_STRENGTH_",
value = {SIGNAL_STRENGTH_LOST, SIGNAL_STRENGTH_WEAK, SIGNAL_STRENGTH_STRONG})
diff --git a/media/java/android/media/tv/interactive/ITvInteractiveAppClient.aidl b/media/java/android/media/tv/interactive/ITvInteractiveAppClient.aidl
index 7b5853169923..1404d7c9841c 100644
--- a/media/java/android/media/tv/interactive/ITvInteractiveAppClient.aidl
+++ b/media/java/android/media/tv/interactive/ITvInteractiveAppClient.aidl
@@ -63,6 +63,8 @@ oneway interface ITvInteractiveAppClient {
void onRequestTvRecordingInfoList(in int type, int seq);
void onRequestSigning(in String id, in String algorithm, in String alias, in byte[] data,
int seq);
+ void onRequestSigning2(in String id, in String algorithm, in String host,
+ int port, in byte[] data, int seq);
void onRequestCertificate(in String host, int port, int seq);
void onAdRequest(in AdRequest request, int Seq);
}
diff --git a/media/java/android/media/tv/interactive/ITvInteractiveAppSessionCallback.aidl b/media/java/android/media/tv/interactive/ITvInteractiveAppSessionCallback.aidl
index cb89181fd714..3c91a3eeb1dc 100644
--- a/media/java/android/media/tv/interactive/ITvInteractiveAppSessionCallback.aidl
+++ b/media/java/android/media/tv/interactive/ITvInteractiveAppSessionCallback.aidl
@@ -61,6 +61,7 @@ oneway interface ITvInteractiveAppSessionCallback {
void onRequestTvRecordingInfo(in String recordingId);
void onRequestTvRecordingInfoList(in int type);
void onRequestSigning(in String id, in String algorithm, in String alias, in byte[] data);
+ void onRequestSigning2(in String id, in String algorithm, in String host, int port, in byte[] data);
void onRequestCertificate(in String host, int port);
void onAdRequest(in AdRequest request);
}
diff --git a/media/java/android/media/tv/interactive/TvInteractiveAppManager.java b/media/java/android/media/tv/interactive/TvInteractiveAppManager.java
index 011744f94edb..498eec604b9c 100755
--- a/media/java/android/media/tv/interactive/TvInteractiveAppManager.java
+++ b/media/java/android/media/tv/interactive/TvInteractiveAppManager.java
@@ -657,6 +657,19 @@ public final class TvInteractiveAppManager {
}
@Override
+ public void onRequestSigning2(
+ String id, String algorithm, String host, int port, byte[] data, int seq) {
+ synchronized (mSessionCallbackRecordMap) {
+ SessionCallbackRecord record = mSessionCallbackRecordMap.get(seq);
+ if (record == null) {
+ Log.e(TAG, "Callback not found for seq " + seq);
+ return;
+ }
+ record.postRequestSigning(id, algorithm, host, port, data);
+ }
+ }
+
+ @Override
public void onRequestCertificate(String host, int port, int seq) {
synchronized (mSessionCallbackRecordMap) {
SessionCallbackRecord record = mSessionCallbackRecordMap.get(seq);
@@ -2258,6 +2271,17 @@ public final class TvInteractiveAppManager {
});
}
+ void postRequestSigning(String id, String algorithm, String host, int port,
+ byte[] data) {
+ mHandler.post(new Runnable() {
+ @Override
+ public void run() {
+ mSessionCallback.onRequestSigning(mSession, id, algorithm, host,
+ port, data);
+ }
+ });
+ }
+
void postRequestCertificate(String host, int port) {
mHandler.post(new Runnable() {
@Override
@@ -2609,6 +2633,25 @@ public final class TvInteractiveAppManager {
}
/**
+ * This is called when
+ * {@link TvInteractiveAppService.Session#requestSigning(String, String, String, int, byte[])} is
+ * called.
+ *
+ * @param session A {@link TvInteractiveAppService.Session} associated with this callback.
+ * @param signingId the ID to identify the request.
+ * @param algorithm the standard name of the signature algorithm requested, such as
+ * MD5withRSA, SHA256withDSA, etc.
+ * @param host The host of the SSL CLient Authentication Server
+ * @param port The port of the SSL Client Authentication Server
+ * @param data the original bytes to be signed.
+ * @hide
+ */
+ public void onRequestSigning(
+ Session session, String signingId, String algorithm, String host,
+ int port, byte[] data) {
+ }
+
+ /**
* This is called when the service requests a SSL certificate for client validation.
*
* @param session A {@link TvInteractiveAppService.Session} associated with this callback.
diff --git a/media/java/android/media/tv/interactive/TvInteractiveAppService.java b/media/java/android/media/tv/interactive/TvInteractiveAppService.java
index 054b272d820f..7b6dc38fe22c 100755
--- a/media/java/android/media/tv/interactive/TvInteractiveAppService.java
+++ b/media/java/android/media/tv/interactive/TvInteractiveAppService.java
@@ -1645,6 +1645,50 @@ public abstract class TvInteractiveAppService extends Service {
}
/**
+ * Requests signing of the given data.
+ *
+ * <p>This is used when the corresponding server of the broadcast-independent interactive
+ * app requires signing during handshaking, and the interactive app service doesn't have
+ * the built-in private key. The private key is provided by the content providers and
+ * pre-built in the related app, such as TV app.
+ *
+ * @param signingId the ID to identify the request. When a result is received, this ID can
+ * be used to correlate the result with the request.
+ * @param algorithm the standard name of the signature algorithm requested, such as
+ * MD5withRSA, SHA256withDSA, etc. The name is from standards like
+ * FIPS PUB 186-4 and PKCS #1.
+ * @param host the host of the SSL client authentication server.
+ * @param port the port of the SSL client authentication server.
+ * @param data the original bytes to be signed.
+ *
+ * @see #onSigningResult(String, byte[])
+ * @see TvInteractiveAppView#createBiInteractiveApp(Uri, Bundle)
+ * @see TvInteractiveAppView#BI_INTERACTIVE_APP_KEY_ALIAS
+ * @hide
+ */
+ @CallSuper
+ public void requestSigning(@NonNull String signingId, @NonNull String algorithm,
+ @NonNull String host, int port, @NonNull byte[] data) {
+ executeOrPostRunnableOnMainThread(new Runnable() {
+ @MainThread
+ @Override
+ public void run() {
+ try {
+ if (DEBUG) {
+ Log.d(TAG, "requestSigning");
+ }
+ if (mSessionCallback != null) {
+ mSessionCallback.onRequestSigning2(signingId, algorithm,
+ host, port, data);
+ }
+ } catch (RemoteException e) {
+ Log.w(TAG, "error in requestSigning", e);
+ }
+ }
+ });
+ }
+
+ /**
* Requests a SSL certificate for client validation.
*
* @param host the host name of the SSL authentication server.
diff --git a/media/jni/soundpool/SoundDecoder.cpp b/media/jni/soundpool/SoundDecoder.cpp
index 5ed10b0d785f..ae576342c6cc 100644
--- a/media/jni/soundpool/SoundDecoder.cpp
+++ b/media/jni/soundpool/SoundDecoder.cpp
@@ -29,14 +29,15 @@ static constexpr size_t kMaxQueueSize = 128;
// before the SoundDecoder thread closes.
static constexpr int32_t kWaitTimeBeforeCloseMs = 1000;
-SoundDecoder::SoundDecoder(SoundManager* soundManager, size_t threads)
+SoundDecoder::SoundDecoder(SoundManager* soundManager, size_t threads, int32_t threadPriority)
: mSoundManager(soundManager)
{
ALOGV("%s(%p, %zu)", __func__, soundManager, threads);
// ThreadPool is created, but we don't launch any threads.
mThreadPool = std::make_unique<ThreadPool>(
std::min(threads, (size_t)std::thread::hardware_concurrency()),
- "SoundDecoder_");
+ "SoundDecoder_",
+ threadPriority);
}
SoundDecoder::~SoundDecoder()
diff --git a/media/jni/soundpool/SoundDecoder.h b/media/jni/soundpool/SoundDecoder.h
index 7b62114483cf..3f44a0d977e1 100644
--- a/media/jni/soundpool/SoundDecoder.h
+++ b/media/jni/soundpool/SoundDecoder.h
@@ -28,7 +28,7 @@ namespace android::soundpool {
*/
class SoundDecoder {
public:
- SoundDecoder(SoundManager* soundManager, size_t threads);
+ SoundDecoder(SoundManager* soundManager, size_t threads, int32_t threadPriority);
~SoundDecoder();
void loadSound(int32_t soundID) NO_THREAD_SAFETY_ANALYSIS; // uses unique_lock
void quit();
diff --git a/media/jni/soundpool/SoundManager.cpp b/media/jni/soundpool/SoundManager.cpp
index 5b16174eef2b..fa35813391a6 100644
--- a/media/jni/soundpool/SoundManager.cpp
+++ b/media/jni/soundpool/SoundManager.cpp
@@ -29,7 +29,7 @@ namespace android::soundpool {
static const size_t kDecoderThreads = std::thread::hardware_concurrency() >= 4 ? 2 : 1;
SoundManager::SoundManager()
- : mDecoder{std::make_unique<SoundDecoder>(this, kDecoderThreads)}
+ : mDecoder{std::make_unique<SoundDecoder>(this, kDecoderThreads, ANDROID_PRIORITY_NORMAL)}
{
ALOGV("%s()", __func__);
}
diff --git a/media/jni/soundpool/StreamManager.cpp b/media/jni/soundpool/StreamManager.cpp
index 66fec1c528e7..e11ccbc0448b 100644
--- a/media/jni/soundpool/StreamManager.cpp
+++ b/media/jni/soundpool/StreamManager.cpp
@@ -126,7 +126,8 @@ StreamManager::StreamManager(
mThreadPool = std::make_unique<ThreadPool>(
std::min((size_t)streams, // do not make more threads than streams to play
std::min(threads, (size_t)std::thread::hardware_concurrency())),
- "SoundPool_");
+ "SoundPool_",
+ ANDROID_PRIORITY_AUDIO);
}
#pragma clang diagnostic pop
diff --git a/media/jni/soundpool/StreamManager.h b/media/jni/soundpool/StreamManager.h
index 340b49bc6d6c..a4cb28663bda 100644
--- a/media/jni/soundpool/StreamManager.h
+++ b/media/jni/soundpool/StreamManager.h
@@ -46,9 +46,9 @@ namespace android::soundpool {
*/
class JavaThread {
public:
- JavaThread(std::function<void()> f, const char *name)
+ JavaThread(std::function<void()> f, const char *name, int32_t threadPriority)
: mF{std::move(f)} {
- createThreadEtc(staticFunction, this, name, ANDROID_PRIORITY_AUDIO);
+ createThreadEtc(staticFunction, this, name, threadPriority);
}
JavaThread(JavaThread &&) = delete; // uses "this" ptr, not moveable.
@@ -109,9 +109,11 @@ private:
*/
class ThreadPool {
public:
- ThreadPool(size_t maxThreadCount, std::string name)
+ ThreadPool(size_t maxThreadCount, std::string name,
+ int32_t threadPriority = ANDROID_PRIORITY_NORMAL)
: mMaxThreadCount(maxThreadCount)
- , mName{std::move(name)} { }
+ , mName{std::move(name)}
+ , mThreadPriority(threadPriority) {}
~ThreadPool() { quit(); }
@@ -159,7 +161,8 @@ public:
const int32_t id = mNextThreadId;
mThreads.emplace_back(std::make_unique<JavaThread>(
[this, id, mf = std::move(f)] { mf(id); --mActiveThreadCount; },
- (mName + std::to_string(id)).c_str()));
+ (mName + std::to_string(id)).c_str(),
+ mThreadPriority));
++mActiveThreadCount;
return id;
}
@@ -180,6 +183,7 @@ public:
private:
const size_t mMaxThreadCount;
const std::string mName;
+ const int32_t mThreadPriority;
std::atomic_size_t mActiveThreadCount = 0;
diff --git a/media/tests/projection/src/android/media/projection/FakeIMediaProjection.java b/media/tests/projection/src/android/media/projection/FakeIMediaProjection.java
index 774de5fbbe3e..0df36afddf25 100644
--- a/media/tests/projection/src/android/media/projection/FakeIMediaProjection.java
+++ b/media/tests/projection/src/android/media/projection/FakeIMediaProjection.java
@@ -19,7 +19,7 @@ package android.media.projection;
import static android.Manifest.permission.MANAGE_MEDIA_PROJECTION;
import android.annotation.EnforcePermission;
-import android.os.IBinder;
+import android.app.ActivityOptions.LaunchCookie;
import android.os.PermissionEnforcer;
import android.os.RemoteException;
@@ -29,7 +29,7 @@ import android.os.RemoteException;
*/
public final class FakeIMediaProjection extends IMediaProjection.Stub {
boolean mIsStarted = false;
- IBinder mLaunchCookie = null;
+ LaunchCookie mLaunchCookie = null;
IMediaProjectionCallback mIMediaProjectionCallback = null;
FakeIMediaProjection(PermissionEnforcer enforcer) {
@@ -80,14 +80,14 @@ public final class FakeIMediaProjection extends IMediaProjection.Stub {
@Override
@EnforcePermission(MANAGE_MEDIA_PROJECTION)
- public IBinder getLaunchCookie() throws RemoteException {
+ public LaunchCookie getLaunchCookie() throws RemoteException {
getLaunchCookie_enforcePermission();
return mLaunchCookie;
}
@Override
@EnforcePermission(MANAGE_MEDIA_PROJECTION)
- public void setLaunchCookie(IBinder launchCookie) throws RemoteException {
+ public void setLaunchCookie(LaunchCookie launchCookie) throws RemoteException {
setLaunchCookie_enforcePermission();
mLaunchCookie = launchCookie;
}
diff --git a/media/tests/projection/src/android/media/projection/MediaProjectionTest.java b/media/tests/projection/src/android/media/projection/MediaProjectionTest.java
index 2e0396fc6119..1323e89202ee 100644
--- a/media/tests/projection/src/android/media/projection/MediaProjectionTest.java
+++ b/media/tests/projection/src/android/media/projection/MediaProjectionTest.java
@@ -31,15 +31,14 @@ import static org.junit.Assert.assertThrows;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.nullable;
import static org.mockito.Mockito.doReturn;
-import static org.mockito.Mockito.mock;
import android.annotation.Nullable;
+import android.app.ActivityOptions.LaunchCookie;
import android.compat.testing.PlatformCompatChangeRule;
import android.hardware.display.DisplayManager;
import android.hardware.display.VirtualDisplay;
import android.hardware.display.VirtualDisplayConfig;
import android.os.Handler;
-import android.os.IBinder;
import android.os.Looper;
import android.os.RemoteException;
import android.os.test.FakePermissionEnforcer;
@@ -117,7 +116,7 @@ public class MediaProjectionTest {
permissionEnforcer.grant(MANAGE_MEDIA_PROJECTION);
// Support the MediaProjection instance.
mFakeIMediaProjection = new FakeIMediaProjection(permissionEnforcer);
- mFakeIMediaProjection.setLaunchCookie(mock(IBinder.class));
+ mFakeIMediaProjection.setLaunchCookie(new LaunchCookie());
mMediaProjection = new MediaProjection(mTestableContext, mFakeIMediaProjection,
mDisplayManager);
diff --git a/packages/SystemUI/aconfig/systemui.aconfig b/packages/SystemUI/aconfig/systemui.aconfig
index a2530d59e2e6..375fe131b4b7 100644
--- a/packages/SystemUI/aconfig/systemui.aconfig
+++ b/packages/SystemUI/aconfig/systemui.aconfig
@@ -371,3 +371,10 @@ flag {
description: "Enables refactored logic for SysUI+WM unlock/occlusion code paths"
bug: "278086361"
}
+
+flag {
+ name: "enable_keyguard_compose"
+ namespace: "systemui"
+ description: "Enables the compose version of keyguard."
+ bug: "301968149"
+}
diff --git a/packages/SystemUI/compose/features/src/com/android/systemui/shade/ui/composable/ShadeHeader.kt b/packages/SystemUI/compose/features/src/com/android/systemui/shade/ui/composable/ShadeHeader.kt
index e2beaeea6402..b11edf7b47b7 100644
--- a/packages/SystemUI/compose/features/src/com/android/systemui/shade/ui/composable/ShadeHeader.kt
+++ b/packages/SystemUI/compose/features/src/com/android/systemui/shade/ui/composable/ShadeHeader.kt
@@ -58,6 +58,8 @@ import com.android.systemui.battery.BatteryMeterViewController
import com.android.systemui.common.ui.compose.windowinsets.CutoutLocation
import com.android.systemui.common.ui.compose.windowinsets.LocalDisplayCutout
import com.android.systemui.res.R
+import com.android.systemui.scene.ui.composable.QuickSettings
+import com.android.systemui.scene.ui.composable.Shade as ShadeKey
import com.android.systemui.shade.ui.viewmodel.ShadeHeaderViewModel
import com.android.systemui.statusbar.phone.StatusBarIconController
import com.android.systemui.statusbar.phone.StatusBarIconController.TintedIconManager
@@ -348,7 +350,7 @@ private fun ShadeCarrierGroup(
}
@Composable
-private fun StatusIcons(
+private fun SceneScope.StatusIcons(
viewModel: ShadeHeaderViewModel,
createTintedIconManager: (ViewGroup, StatusBarLocation) -> TintedIconManager,
statusBarIconController: StatusBarIconController,
@@ -358,7 +360,6 @@ private fun StatusIcons(
val carrierIconSlots =
listOf(stringResource(id = com.android.internal.R.string.status_bar_mobile))
val isSingleCarrier by viewModel.isSingleCarrier.collectAsState()
- val isTransitioning by viewModel.isTransitioning.collectAsState()
AndroidView(
factory = { context ->
@@ -373,7 +374,9 @@ private fun StatusIcons(
iconContainer
},
update = { iconContainer ->
- iconContainer.setQsExpansionTransitioning(isTransitioning)
+ iconContainer.setQsExpansionTransitioning(
+ layoutState.isTransitioningBetween(ShadeKey, QuickSettings)
+ )
if (isSingleCarrier || !useExpandedFormat) {
iconContainer.removeIgnoredSlots(carrierIconSlots)
} else {
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/domain/interactor/KeyguardQuickAffordanceInteractorTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/domain/interactor/KeyguardQuickAffordanceInteractorTest.kt
index 34f703bc0ca7..db414b724b63 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/domain/interactor/KeyguardQuickAffordanceInteractorTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/domain/interactor/KeyguardQuickAffordanceInteractorTest.kt
@@ -27,6 +27,7 @@ import com.android.systemui.animation.DialogLaunchAnimator
import com.android.systemui.common.shared.model.ContentDescription
import com.android.systemui.common.shared.model.Icon
import com.android.systemui.coroutines.collectLastValue
+import com.android.systemui.coroutines.collectValues
import com.android.systemui.dock.DockManager
import com.android.systemui.dock.DockManagerFake
import com.android.systemui.flags.FakeFeatureFlags
@@ -49,16 +50,17 @@ import com.android.systemui.plugins.ActivityStarter
import com.android.systemui.res.R
import com.android.systemui.settings.UserFileManager
import com.android.systemui.settings.UserTracker
+import com.android.systemui.shade.domain.interactor.ShadeInteractor
import com.android.systemui.shade.domain.interactor.shadeInteractor
import com.android.systemui.shared.keyguard.shared.model.KeyguardQuickAffordanceSlots
import com.android.systemui.statusbar.policy.KeyguardStateController
-import com.android.systemui.testKosmos
import com.android.systemui.util.FakeSharedPreferences
import com.android.systemui.util.mockito.mock
import com.android.systemui.util.mockito.whenever
import com.android.systemui.util.settings.FakeSettings
import com.google.common.truth.Truth.assertThat
import kotlinx.coroutines.ExperimentalCoroutinesApi
+import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.test.StandardTestDispatcher
import kotlinx.coroutines.test.TestScope
import kotlinx.coroutines.test.runCurrent
@@ -82,6 +84,7 @@ class KeyguardQuickAffordanceInteractorTest : SysuiTestCase() {
@Mock private lateinit var activityStarter: ActivityStarter
@Mock private lateinit var launchAnimator: DialogLaunchAnimator
@Mock private lateinit var devicePolicyManager: DevicePolicyManager
+ @Mock private lateinit var shadeInteractor: ShadeInteractor
@Mock private lateinit var logger: KeyguardQuickAffordancesMetricsLogger
private lateinit var underTest: KeyguardQuickAffordanceInteractor
@@ -95,8 +98,6 @@ class KeyguardQuickAffordanceInteractorTest : SysuiTestCase() {
private lateinit var dockManager: DockManagerFake
private lateinit var biometricSettingsRepository: FakeBiometricSettingsRepository
- private val kosmos = testKosmos()
-
@Before
fun setUp() {
MockitoAnnotations.initMocks(this)
@@ -183,7 +184,7 @@ class KeyguardQuickAffordanceInteractorTest : SysuiTestCase() {
underTest =
KeyguardQuickAffordanceInteractor(
keyguardInteractor = withDeps.keyguardInteractor,
- shadeInteractor = kosmos.shadeInteractor,
+ shadeInteractor = shadeInteractor,
lockPatternUtils = lockPatternUtils,
keyguardStateController = keyguardStateController,
userTracker = userTracker,
@@ -198,6 +199,8 @@ class KeyguardQuickAffordanceInteractorTest : SysuiTestCase() {
backgroundDispatcher = testDispatcher,
appContext = context,
)
+
+ whenever(shadeInteractor.anyExpansion).thenReturn(MutableStateFlow(0f))
}
@Test
@@ -344,6 +347,25 @@ class KeyguardQuickAffordanceInteractorTest : SysuiTestCase() {
}
@Test
+ fun quickAffordance_updateOncePerShadeExpansion() =
+ testScope.runTest {
+ val shadeExpansion = MutableStateFlow(0f)
+ whenever(shadeInteractor.anyExpansion).thenReturn(shadeExpansion)
+
+ val collectedValue by
+ collectValues(
+ underTest.quickAffordance(KeyguardQuickAffordancePosition.BOTTOM_START)
+ )
+
+ val initialSize = collectedValue.size
+ for (i in 0..10) {
+ shadeExpansion.value = i / 10f
+ }
+
+ assertThat(collectedValue.size).isEqualTo(initialSize + 1)
+ }
+
+ @Test
fun quickAffordanceAlwaysVisible_notVisible_restrictedByPolicyManager() =
testScope.runTest {
whenever(devicePolicyManager.getKeyguardDisabledFeatures(null, userTracker.userId))
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/scene/domain/interactor/SceneInteractorTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/scene/domain/interactor/SceneInteractorTest.kt
index bf99a8687aa4..942fbc229e8a 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/scene/domain/interactor/SceneInteractorTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/scene/domain/interactor/SceneInteractorTest.kt
@@ -174,105 +174,6 @@ class SceneInteractorTest : SysuiTestCase() {
}
@Test
- fun transitioning_idle_false() =
- testScope.runTest {
- val transitionState =
- MutableStateFlow<ObservableTransitionState>(
- ObservableTransitionState.Idle(SceneKey.Shade)
- )
- val transitioning by
- collectLastValue(underTest.transitioning(SceneKey.Shade, SceneKey.Lockscreen))
- underTest.setTransitionState(transitionState)
-
- assertThat(transitioning).isFalse()
- }
-
- @Test
- fun transitioning_wrongFromScene_false() =
- testScope.runTest {
- val transitionState =
- MutableStateFlow<ObservableTransitionState>(
- ObservableTransitionState.Transition(
- fromScene = SceneKey.Gone,
- toScene = SceneKey.Lockscreen,
- progress = flowOf(0.5f),
- isInitiatedByUserInput = false,
- isUserInputOngoing = flowOf(false),
- )
- )
- val transitioning by
- collectLastValue(underTest.transitioning(SceneKey.Shade, SceneKey.Lockscreen))
- underTest.setTransitionState(transitionState)
-
- assertThat(transitioning).isFalse()
- }
-
- @Test
- fun transitioning_wrongToScene_false() =
- testScope.runTest {
- val transitionState =
- MutableStateFlow<ObservableTransitionState>(
- ObservableTransitionState.Transition(
- fromScene = SceneKey.Shade,
- toScene = SceneKey.QuickSettings,
- progress = flowOf(0.5f),
- isInitiatedByUserInput = false,
- isUserInputOngoing = flowOf(false),
- )
- )
- underTest.setTransitionState(transitionState)
-
- assertThat(underTest.transitioning(SceneKey.Shade, SceneKey.Lockscreen).value).isFalse()
- }
-
- @Test
- fun transitioning_correctFromAndToScenes_true() =
- testScope.runTest {
- val transitionState =
- MutableStateFlow<ObservableTransitionState>(
- ObservableTransitionState.Transition(
- fromScene = SceneKey.Shade,
- toScene = SceneKey.Lockscreen,
- progress = flowOf(0.5f),
- isInitiatedByUserInput = false,
- isUserInputOngoing = flowOf(false),
- )
- )
- val transitioning by
- collectLastValue(underTest.transitioning(SceneKey.Shade, SceneKey.Lockscreen))
- underTest.setTransitionState(transitionState)
-
- assertThat(transitioning).isTrue()
- }
-
- @Test
- fun transitioning_updates() =
- testScope.runTest {
- val transitionState =
- MutableStateFlow<ObservableTransitionState>(
- ObservableTransitionState.Idle(SceneKey.Shade)
- )
- val transitioning by
- collectLastValue(underTest.transitioning(SceneKey.Shade, SceneKey.Lockscreen))
- underTest.setTransitionState(transitionState)
-
- assertThat(transitioning).isFalse()
-
- transitionState.value =
- ObservableTransitionState.Transition(
- fromScene = SceneKey.Shade,
- toScene = SceneKey.Lockscreen,
- progress = flowOf(0.5f),
- isInitiatedByUserInput = false,
- isUserInputOngoing = flowOf(false),
- )
- assertThat(transitioning).isTrue()
-
- transitionState.value = ObservableTransitionState.Idle(SceneKey.Lockscreen)
- assertThat(transitioning).isFalse()
- }
-
- @Test
fun isTransitionUserInputOngoing_idle_false() =
testScope.runTest {
val transitionState =
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/shade/ui/viewmodel/ShadeHeaderViewModelTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/shade/ui/viewmodel/ShadeHeaderViewModelTest.kt
index e9a2a3befb03..c0aaab3ad6e1 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/shade/ui/viewmodel/ShadeHeaderViewModelTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/shade/ui/viewmodel/ShadeHeaderViewModelTest.kt
@@ -9,8 +9,6 @@ import com.android.systemui.flags.FakeFeatureFlagsClassic
import com.android.systemui.flags.Flags
import com.android.systemui.kosmos.testScope
import com.android.systemui.scene.domain.interactor.sceneInteractor
-import com.android.systemui.scene.shared.model.ObservableTransitionState
-import com.android.systemui.scene.shared.model.SceneKey
import com.android.systemui.statusbar.pipeline.airplane.data.repository.FakeAirplaneModeRepository
import com.android.systemui.statusbar.pipeline.airplane.domain.interactor.AirplaneModeInteractor
import com.android.systemui.statusbar.pipeline.mobile.data.model.SubscriptionModel
@@ -22,8 +20,6 @@ import com.android.systemui.statusbar.pipeline.shared.data.repository.FakeConnec
import com.android.systemui.testKosmos
import com.android.systemui.util.mockito.mock
import com.google.common.truth.Truth.assertThat
-import kotlinx.coroutines.flow.MutableStateFlow
-import kotlinx.coroutines.flow.flowOf
import kotlinx.coroutines.test.runTest
import org.junit.Before
import org.junit.Test
@@ -74,74 +70,6 @@ class ShadeHeaderViewModelTest : SysuiTestCase() {
}
@Test
- fun isTransitioning_idle_false() =
- testScope.runTest {
- val isTransitioning by collectLastValue(underTest.isTransitioning)
- sceneInteractor.setTransitionState(
- MutableStateFlow(ObservableTransitionState.Idle(SceneKey.Shade))
- )
-
- assertThat(isTransitioning).isFalse()
- }
-
- @Test
- fun isTransitioning_shadeToQs_true() =
- testScope.runTest {
- val isTransitioning by collectLastValue(underTest.isTransitioning)
- sceneInteractor.setTransitionState(
- MutableStateFlow(
- ObservableTransitionState.Transition(
- fromScene = SceneKey.Shade,
- toScene = SceneKey.QuickSettings,
- progress = MutableStateFlow(0.5f),
- isInitiatedByUserInput = false,
- isUserInputOngoing = flowOf(false),
- )
- )
- )
-
- assertThat(isTransitioning).isTrue()
- }
-
- @Test
- fun isTransitioning_qsToShade_true() =
- testScope.runTest {
- val isTransitioning by collectLastValue(underTest.isTransitioning)
- sceneInteractor.setTransitionState(
- MutableStateFlow(
- ObservableTransitionState.Transition(
- fromScene = SceneKey.QuickSettings,
- toScene = SceneKey.Shade,
- progress = MutableStateFlow(0.5f),
- isInitiatedByUserInput = false,
- isUserInputOngoing = flowOf(false),
- )
- )
- )
-
- assertThat(isTransitioning).isTrue()
- }
-
- @Test
- fun isTransitioning_otherTransition_false() =
- testScope.runTest {
- val isTransitioning by collectLastValue(underTest.isTransitioning)
- sceneInteractor.setTransitionState(
- MutableStateFlow(
- ObservableTransitionState.Transition(
- fromScene = SceneKey.Gone,
- toScene = SceneKey.Shade,
- progress = MutableStateFlow(0.5f),
- isInitiatedByUserInput = false,
- isUserInputOngoing = flowOf(false),
- )
- )
- )
-
- assertThat(isTransitioning).isFalse()
- }
-
- @Test
fun mobileSubIds_update() =
testScope.runTest {
val mobileSubIds by collectLastValue(underTest.mobileSubIds)
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/KeyguardQuickAffordanceInteractor.kt b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/KeyguardQuickAffordanceInteractor.kt
index 388834597f60..a1f94250e149 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/KeyguardQuickAffordanceInteractor.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/KeyguardQuickAffordanceInteractor.kt
@@ -56,6 +56,7 @@ import kotlinx.coroutines.CoroutineDispatcher
import kotlinx.coroutines.ExperimentalCoroutinesApi
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.combine
+import kotlinx.coroutines.flow.distinctUntilChanged
import kotlinx.coroutines.flow.flatMapLatest
import kotlinx.coroutines.flow.flowOf
import kotlinx.coroutines.flow.map
@@ -102,10 +103,10 @@ constructor(
quickAffordanceAlwaysVisible(position),
keyguardInteractor.isDozing,
keyguardInteractor.isKeyguardShowing,
- shadeInteractor.anyExpansion,
+ shadeInteractor.anyExpansion.map { it < 1.0f }.distinctUntilChanged(),
biometricSettingsRepository.isCurrentUserInLockdown,
- ) { affordance, isDozing, isKeyguardShowing, qsExpansion, isUserInLockdown ->
- if (!isDozing && isKeyguardShowing && (qsExpansion < 1.0f) && !isUserInLockdown) {
+ ) { affordance, isDozing, isKeyguardShowing, isQuickSettingsVisible, isUserInLockdown ->
+ if (!isDozing && isKeyguardShowing && isQuickSettingsVisible && !isUserInLockdown) {
affordance
} else {
KeyguardQuickAffordanceModel.Hidden
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/ui/binder/PreviewKeyguardBlueprintViewBinder.kt b/packages/SystemUI/src/com/android/systemui/keyguard/ui/binder/PreviewKeyguardBlueprintViewBinder.kt
deleted file mode 100644
index 2feaa2e81c0f..000000000000
--- a/packages/SystemUI/src/com/android/systemui/keyguard/ui/binder/PreviewKeyguardBlueprintViewBinder.kt
+++ /dev/null
@@ -1,82 +0,0 @@
-/*
- * Copyright (C) 2023 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- *
- */
-
-package com.android.systemui.keyguard.ui.binder
-
-import android.os.Trace
-import androidx.constraintlayout.widget.ConstraintLayout
-import androidx.constraintlayout.widget.ConstraintSet
-import androidx.lifecycle.Lifecycle
-import androidx.lifecycle.repeatOnLifecycle
-import com.android.systemui.keyguard.ui.viewmodel.KeyguardBlueprintViewModel
-import com.android.systemui.lifecycle.repeatWhenAttached
-import kotlinx.coroutines.DisposableHandle
-import kotlinx.coroutines.launch
-
-/**
- * Binds the existing blueprint to the constraint layout that previews keyguard.
- *
- * This view binder should only inflate and add relevant views and apply the constraints. Actual
- * data binding should be done in {@link KeyguardPreviewRenderer}
- */
-class PreviewKeyguardBlueprintViewBinder {
- companion object {
-
- /**
- * Binds the existing blueprint to the constraint layout that previews keyguard.
- *
- * @param constraintLayout The root view to bind to
- * @param viewModel The instance of the view model that contains flows we collect on.
- * @param finishedAddViewCallback Called when we have finished inflating the views.
- */
- fun bind(
- constraintLayout: ConstraintLayout,
- viewModel: KeyguardBlueprintViewModel,
- finishedAddViewCallback: () -> Unit
- ): DisposableHandle {
- return constraintLayout.repeatWhenAttached {
- repeatOnLifecycle(Lifecycle.State.CREATED) {
- launch {
- viewModel.blueprint.collect { blueprint ->
- val prevBluePrint = viewModel.currentBluePrint
- Trace.beginSection("PreviewKeyguardBlueprint#applyBlueprint")
-
- ConstraintSet().apply {
- clone(constraintLayout)
- val emptyLayout = ConstraintSet.Layout()
- knownIds.forEach { getConstraint(it).layout.copyFrom(emptyLayout) }
- blueprint.applyConstraints(this)
- // Add and remove views of sections that are not contained by the
- // other.
- blueprint.replaceViews(
- prevBluePrint,
- constraintLayout,
- bindData = false
- )
- applyTo(constraintLayout)
- }
-
- viewModel.currentBluePrint = blueprint
- finishedAddViewCallback.invoke()
- Trace.endSection()
- }
- }
- }
- }
- }
- }
-}
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/ui/preview/KeyguardPreviewRenderer.kt b/packages/SystemUI/src/com/android/systemui/keyguard/ui/preview/KeyguardPreviewRenderer.kt
index 841bad4c15cc..a0c0095b34a2 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/ui/preview/KeyguardPreviewRenderer.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/ui/preview/KeyguardPreviewRenderer.kt
@@ -41,6 +41,7 @@ import android.view.WindowManager
import android.widget.FrameLayout
import android.widget.TextView
import androidx.constraintlayout.widget.ConstraintLayout
+import androidx.constraintlayout.widget.ConstraintSet
import androidx.core.view.isInvisible
import com.android.keyguard.ClockEventController
import com.android.keyguard.KeyguardClockSwitch
@@ -54,15 +55,12 @@ import com.android.systemui.communal.ui.viewmodel.CommunalTutorialIndicatorViewM
import com.android.systemui.dagger.qualifiers.Application
import com.android.systemui.dagger.qualifiers.Background
import com.android.systemui.dagger.qualifiers.Main
-import com.android.systemui.flags.FeatureFlagsClassic
-import com.android.systemui.keyguard.shared.KeyguardShadeMigrationNssl
import com.android.systemui.keyguard.ui.binder.KeyguardPreviewClockViewBinder
import com.android.systemui.keyguard.ui.binder.KeyguardPreviewSmartspaceViewBinder
import com.android.systemui.keyguard.ui.binder.KeyguardQuickAffordanceViewBinder
import com.android.systemui.keyguard.ui.binder.KeyguardRootViewBinder
-import com.android.systemui.keyguard.ui.binder.PreviewKeyguardBlueprintViewBinder
import com.android.systemui.keyguard.ui.view.KeyguardRootView
-import com.android.systemui.keyguard.ui.viewmodel.KeyguardBlueprintViewModel
+import com.android.systemui.keyguard.ui.view.layout.sections.DefaultShortcutsSection
import com.android.systemui.keyguard.ui.viewmodel.KeyguardBottomAreaViewModel
import com.android.systemui.keyguard.ui.viewmodel.KeyguardPreviewClockViewModel
import com.android.systemui.keyguard.ui.viewmodel.KeyguardPreviewSmartspaceViewModel
@@ -124,19 +122,18 @@ constructor(
private val broadcastDispatcher: BroadcastDispatcher,
private val lockscreenSmartspaceController: LockscreenSmartspaceController,
private val udfpsOverlayInteractor: UdfpsOverlayInteractor,
- private val featureFlags: FeatureFlagsClassic,
private val falsingManager: FalsingManager,
private val vibratorHelper: VibratorHelper,
private val indicationController: KeyguardIndicationController,
private val keyguardRootViewModel: KeyguardRootViewModel,
@Assisted bundle: Bundle,
- private val keyguardBlueprintViewModel: KeyguardBlueprintViewModel,
private val occludingAppDeviceEntryMessageViewModel: OccludingAppDeviceEntryMessageViewModel,
private val chipbarCoordinator: ChipbarCoordinator,
private val screenOffAnimationController: ScreenOffAnimationController,
private val shadeInteractor: ShadeInteractor,
private val secureSettings: SecureSettings,
private val communalTutorialViewModel: CommunalTutorialIndicatorViewModel,
+ private val defaultShortcutsSection: DefaultShortcutsSection,
) {
val hostToken: IBinder? = bundle.getBinder(KEY_HOST_TOKEN)
private val width: Int = bundle.getInt(KEY_VIEW_WIDTH)
@@ -393,32 +390,32 @@ constructor(
setUpUdfps(previewContext, rootView)
- disposables.add(
- PreviewKeyguardBlueprintViewBinder.bind(keyguardRootView, keyguardBlueprintViewModel) {
- if (keyguardBottomAreaRefactor()) {
- setupShortcuts(keyguardRootView)
- }
-
- if (!shouldHideClock) {
- setUpClock(previewContext, rootView)
- KeyguardPreviewClockViewBinder.bind(
- largeClockHostView,
- smallClockHostView,
- clockViewModel,
- )
- }
+ if (keyguardBottomAreaRefactor()) {
+ setupShortcuts(keyguardRootView)
+ }
- setUpSmartspace(previewContext, rootView)
- smartSpaceView?.let {
- KeyguardPreviewSmartspaceViewBinder.bind(it, smartspaceViewModel)
- }
+ if (!shouldHideClock) {
+ setUpClock(previewContext, rootView)
+ KeyguardPreviewClockViewBinder.bind(
+ largeClockHostView,
+ smallClockHostView,
+ clockViewModel,
+ )
+ }
- setupCommunalTutorialIndicator(keyguardRootView)
- }
- )
+ setUpSmartspace(previewContext, rootView)
+ smartSpaceView?.let { KeyguardPreviewSmartspaceViewBinder.bind(it, smartspaceViewModel) }
+ setupCommunalTutorialIndicator(keyguardRootView)
}
private fun setupShortcuts(keyguardRootView: ConstraintLayout) {
+ // Add shortcuts
+ val cs = ConstraintSet()
+ cs.clone(keyguardRootView)
+ defaultShortcutsSection.addViews(keyguardRootView)
+ defaultShortcutsSection.applyConstraints(cs)
+ cs.applyTo(keyguardRootView)
+
keyguardRootView.findViewById<LaunchableImageView?>(R.id.start_button)?.let { imageView ->
shortcutsBindings.add(
KeyguardQuickAffordanceViewBinder.bind(
@@ -476,53 +473,40 @@ constructor(
}
private fun setUpClock(previewContext: Context, parentView: ViewGroup) {
- largeClockHostView =
- if (KeyguardShadeMigrationNssl.isEnabled) {
- parentView.requireViewById<FrameLayout>(R.id.lockscreen_clock_view_large)
- } else {
- val hostView = FrameLayout(previewContext)
- hostView.layoutParams =
- FrameLayout.LayoutParams(
- FrameLayout.LayoutParams.MATCH_PARENT,
- FrameLayout.LayoutParams.MATCH_PARENT,
- )
- parentView.addView(hostView)
- hostView
- }
+ val resources = parentView.resources
+ largeClockHostView = FrameLayout(previewContext)
+ largeClockHostView.layoutParams =
+ FrameLayout.LayoutParams(
+ FrameLayout.LayoutParams.MATCH_PARENT,
+ FrameLayout.LayoutParams.MATCH_PARENT,
+ )
+ parentView.addView(largeClockHostView)
largeClockHostView.isInvisible = true
- smallClockHostView =
- if (KeyguardShadeMigrationNssl.isEnabled) {
- parentView.requireViewById<FrameLayout>(R.id.lockscreen_clock_view)
- } else {
- val resources = parentView.resources
- val hostView = FrameLayout(previewContext)
- val layoutParams =
- FrameLayout.LayoutParams(
- FrameLayout.LayoutParams.WRAP_CONTENT,
- resources.getDimensionPixelSize(
- com.android.systemui.customization.R.dimen.small_clock_height
- )
- )
- layoutParams.topMargin =
- KeyguardPreviewSmartspaceViewModel.getStatusBarHeight(resources) +
- resources.getDimensionPixelSize(
- com.android.systemui.customization.R.dimen.small_clock_padding_top
- )
- hostView.layoutParams = layoutParams
-
- hostView.setPaddingRelative(
- resources.getDimensionPixelSize(
- com.android.systemui.customization.R.dimen.clock_padding_start
- ),
- 0,
- 0,
- 0
+ smallClockHostView = FrameLayout(previewContext)
+ val layoutParams =
+ FrameLayout.LayoutParams(
+ FrameLayout.LayoutParams.WRAP_CONTENT,
+ resources.getDimensionPixelSize(
+ com.android.systemui.customization.R.dimen.small_clock_height
)
- hostView.clipChildren = false
- parentView.addView(hostView)
- hostView
- }
+ )
+ layoutParams.topMargin =
+ KeyguardPreviewSmartspaceViewModel.getStatusBarHeight(resources) +
+ resources.getDimensionPixelSize(
+ com.android.systemui.customization.R.dimen.small_clock_padding_top
+ )
+ smallClockHostView.layoutParams = layoutParams
+ smallClockHostView.setPaddingRelative(
+ resources.getDimensionPixelSize(
+ com.android.systemui.customization.R.dimen.clock_padding_start
+ ),
+ 0,
+ 0,
+ 0
+ )
+ smallClockHostView.clipChildren = false
+ parentView.addView(smallClockHostView)
smallClockHostView.isInvisible = true
// TODO (b/283465254): Move the listeners to KeyguardClockRepository
diff --git a/packages/SystemUI/src/com/android/systemui/mediaprojection/MediaProjectionCaptureTarget.kt b/packages/SystemUI/src/com/android/systemui/mediaprojection/MediaProjectionCaptureTarget.kt
index 11d0be5fc8bf..a618490c1b53 100644
--- a/packages/SystemUI/src/com/android/systemui/mediaprojection/MediaProjectionCaptureTarget.kt
+++ b/packages/SystemUI/src/com/android/systemui/mediaprojection/MediaProjectionCaptureTarget.kt
@@ -16,7 +16,7 @@
package com.android.systemui.mediaprojection
-import android.os.IBinder
+import android.app.ActivityOptions.LaunchCookie
import android.os.Parcel
import android.os.Parcelable
@@ -24,12 +24,12 @@ import android.os.Parcelable
* Class that represents an area that should be captured. Currently it has only a launch cookie that
* represents a task but we potentially could add more identifiers e.g. for a pair of tasks.
*/
-data class MediaProjectionCaptureTarget(val launchCookie: IBinder?) : Parcelable {
+data class MediaProjectionCaptureTarget(val launchCookie: LaunchCookie?) : Parcelable {
- constructor(parcel: Parcel) : this(parcel.readStrongBinder())
+ constructor(parcel: Parcel) : this(LaunchCookie.readFromParcel(parcel))
override fun writeToParcel(dest: Parcel, flags: Int) {
- dest.writeStrongBinder(launchCookie)
+ LaunchCookie.writeToParcel(launchCookie, dest)
}
override fun describeContents(): Int = 0
diff --git a/packages/SystemUI/src/com/android/systemui/mediaprojection/appselector/MediaProjectionAppSelectorActivity.kt b/packages/SystemUI/src/com/android/systemui/mediaprojection/appselector/MediaProjectionAppSelectorActivity.kt
index 50e9e7517a0f..4685c5a0cb21 100644
--- a/packages/SystemUI/src/com/android/systemui/mediaprojection/appselector/MediaProjectionAppSelectorActivity.kt
+++ b/packages/SystemUI/src/com/android/systemui/mediaprojection/appselector/MediaProjectionAppSelectorActivity.kt
@@ -16,6 +16,7 @@
package com.android.systemui.mediaprojection.appselector
import android.app.ActivityOptions
+import android.app.ActivityOptions.LaunchCookie
import android.content.Intent
import android.content.res.Configuration
import android.content.res.Resources
@@ -24,9 +25,7 @@ import android.media.projection.IMediaProjectionManager.EXTRA_USER_REVIEW_GRANTE
import android.media.projection.MediaProjectionManager.EXTRA_MEDIA_PROJECTION
import android.media.projection.ReviewGrantedConsentResult.RECORD_CANCEL
import android.media.projection.ReviewGrantedConsentResult.RECORD_CONTENT_TASK
-import android.os.Binder
import android.os.Bundle
-import android.os.IBinder
import android.os.ResultReceiver
import android.os.UserHandle
import android.util.Log
@@ -163,9 +162,9 @@ class MediaProjectionAppSelectorActivity(
val intent = createIntent(targetInfo)
- val launchToken: IBinder = Binder("media_projection_launch_token")
+ val launchCookie = LaunchCookie("media_projection_launch_token")
val activityOptions = ActivityOptions.makeBasic()
- activityOptions.launchCookie = launchToken
+ activityOptions.setLaunchCookie(launchCookie)
val userHandle = mMultiProfilePagerAdapter.activeListAdapter.userHandle
@@ -175,7 +174,7 @@ class MediaProjectionAppSelectorActivity(
// is created and ready to be captured.
val activityStarted =
activityLauncher.startActivityAsUser(intent, userHandle, activityOptions.toBundle()) {
- returnSelectedApp(launchToken)
+ returnSelectedApp(launchCookie)
}
// Rely on the ActivityManager to pop up a dialog regarding app suspension
@@ -233,7 +232,7 @@ class MediaProjectionAppSelectorActivity(
}
}
- override fun returnSelectedApp(launchCookie: IBinder) {
+ override fun returnSelectedApp(launchCookie: LaunchCookie) {
taskSelected = true
if (intent.hasExtra(EXTRA_CAPTURE_REGION_RESULT_RECEIVER)) {
// The client requested to return the result in the result receiver instead of
@@ -255,7 +254,7 @@ class MediaProjectionAppSelectorActivity(
val mediaProjectionBinder = intent.getIBinderExtra(EXTRA_MEDIA_PROJECTION)
val projection = IMediaProjection.Stub.asInterface(mediaProjectionBinder)
- projection.launchCookie = launchCookie
+ projection.setLaunchCookie(launchCookie)
val intent = Intent()
intent.putExtra(EXTRA_MEDIA_PROJECTION, projection.asBinder())
diff --git a/packages/SystemUI/src/com/android/systemui/mediaprojection/appselector/MediaProjectionAppSelectorResultHandler.kt b/packages/SystemUI/src/com/android/systemui/mediaprojection/appselector/MediaProjectionAppSelectorResultHandler.kt
index 93c3bce87ad3..f204b3e74f4b 100644
--- a/packages/SystemUI/src/com/android/systemui/mediaprojection/appselector/MediaProjectionAppSelectorResultHandler.kt
+++ b/packages/SystemUI/src/com/android/systemui/mediaprojection/appselector/MediaProjectionAppSelectorResultHandler.kt
@@ -1,6 +1,6 @@
package com.android.systemui.mediaprojection.appselector
-import android.os.IBinder
+import android.app.ActivityOptions.LaunchCookie
/**
* Interface that allows to continue the media projection flow and return the selected app
@@ -11,5 +11,5 @@ interface MediaProjectionAppSelectorResultHandler {
* Return selected app to the original caller of the media projection app picker.
* @param launchCookie launch cookie of the launched activity of the target app
*/
- fun returnSelectedApp(launchCookie: IBinder)
+ fun returnSelectedApp(launchCookie: LaunchCookie)
}
diff --git a/packages/SystemUI/src/com/android/systemui/mediaprojection/appselector/view/MediaProjectionRecentsViewController.kt b/packages/SystemUI/src/com/android/systemui/mediaprojection/appselector/view/MediaProjectionRecentsViewController.kt
index ba837dba5354..a811065fdc65 100644
--- a/packages/SystemUI/src/com/android/systemui/mediaprojection/appselector/view/MediaProjectionRecentsViewController.kt
+++ b/packages/SystemUI/src/com/android/systemui/mediaprojection/appselector/view/MediaProjectionRecentsViewController.kt
@@ -17,10 +17,10 @@
package com.android.systemui.mediaprojection.appselector.view
import android.app.ActivityOptions
+import android.app.ActivityOptions.LaunchCookie
import android.app.ComponentOptions.MODE_BACKGROUND_ACTIVITY_START_ALLOWED
import android.app.IActivityTaskManager
import android.graphics.Rect
-import android.os.Binder
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
@@ -121,7 +121,7 @@ constructor(
}
override fun onRecentAppClicked(task: RecentTask, view: View) {
- val launchCookie = Binder()
+ val launchCookie = LaunchCookie()
val activityOptions =
ActivityOptions.makeScaleUpAnimation(
view,
@@ -132,7 +132,7 @@ constructor(
)
activityOptions.pendingIntentBackgroundActivityStartMode =
MODE_BACKGROUND_ACTIVITY_START_ALLOWED
- activityOptions.launchCookie = launchCookie
+ activityOptions.setLaunchCookie(launchCookie)
activityOptions.launchDisplayId = task.displayId
activityTaskManager.startActivityFromRecents(task.taskId, activityOptions.toBundle())
diff --git a/packages/SystemUI/src/com/android/systemui/mediaprojection/permission/MediaProjectionPermissionActivity.java b/packages/SystemUI/src/com/android/systemui/mediaprojection/permission/MediaProjectionPermissionActivity.java
index 039372d87835..8b034b293dcb 100644
--- a/packages/SystemUI/src/com/android/systemui/mediaprojection/permission/MediaProjectionPermissionActivity.java
+++ b/packages/SystemUI/src/com/android/systemui/mediaprojection/permission/MediaProjectionPermissionActivity.java
@@ -28,6 +28,7 @@ import static com.android.systemui.mediaprojection.permission.ScreenShareOptionK
import android.annotation.Nullable;
import android.app.Activity;
import android.app.ActivityManager;
+import android.app.ActivityOptions.LaunchCookie;
import android.app.AlertDialog;
import android.app.StatusBarManager;
import android.content.Context;
@@ -146,6 +147,13 @@ public class MediaProjectionPermissionActivity extends Activity
final IMediaProjection projection =
MediaProjectionServiceHelper.createOrReuseProjection(mUid, mPackageName,
mReviewGrantedConsentRequired);
+
+ LaunchCookie launchCookie = launchingIntent.getParcelableExtra(
+ MediaProjectionManager.EXTRA_LAUNCH_COOKIE, LaunchCookie.class);
+ if (launchCookie != null) {
+ projection.setLaunchCookie(launchCookie);
+ }
+
// Automatically grant consent if a system-privileged component is recording.
final Intent intent = new Intent();
intent.putExtra(MediaProjectionManager.EXTRA_MEDIA_PROJECTION,
diff --git a/packages/SystemUI/src/com/android/systemui/scene/domain/interactor/SceneInteractor.kt b/packages/SystemUI/src/com/android/systemui/scene/domain/interactor/SceneInteractor.kt
index b3d2e0918db6..b9e9fe7684e9 100644
--- a/packages/SystemUI/src/com/android/systemui/scene/domain/interactor/SceneInteractor.kt
+++ b/packages/SystemUI/src/com/android/systemui/scene/domain/interactor/SceneInteractor.kt
@@ -171,28 +171,6 @@ constructor(
return repository.setVisible(isVisible)
}
- /** True if there is a transition happening from and to the specified scenes. */
- fun transitioning(from: SceneKey, to: SceneKey): StateFlow<Boolean> {
- fun transitioning(
- state: ObservableTransitionState,
- from: SceneKey,
- to: SceneKey,
- ): Boolean {
- return (state as? ObservableTransitionState.Transition)?.let {
- it.fromScene == from && it.toScene == to
- }
- ?: false
- }
-
- return transitionState
- .map { state -> transitioning(state, from, to) }
- .stateIn(
- scope = applicationScope,
- started = SharingStarted.WhileSubscribed(),
- initialValue = transitioning(transitionState.value, from, to),
- )
- }
-
/**
* Binds the given flow so the system remembers it.
*
diff --git a/packages/SystemUI/src/com/android/systemui/shade/ui/viewmodel/ShadeHeaderViewModel.kt b/packages/SystemUI/src/com/android/systemui/shade/ui/viewmodel/ShadeHeaderViewModel.kt
index 51276c6560a4..314637e4b27e 100644
--- a/packages/SystemUI/src/com/android/systemui/shade/ui/viewmodel/ShadeHeaderViewModel.kt
+++ b/packages/SystemUI/src/com/android/systemui/shade/ui/viewmodel/ShadeHeaderViewModel.kt
@@ -22,12 +22,11 @@ import android.content.IntentFilter
import android.icu.text.DateFormat
import android.icu.text.DisplayContext
import android.os.UserHandle
-import com.android.systemui.res.R
import com.android.systemui.broadcast.BroadcastDispatcher
import com.android.systemui.dagger.SysUISingleton
import com.android.systemui.dagger.qualifiers.Application
+import com.android.systemui.res.R
import com.android.systemui.scene.domain.interactor.SceneInteractor
-import com.android.systemui.scene.shared.model.SceneKey
import com.android.systemui.statusbar.pipeline.mobile.domain.interactor.MobileIconsInteractor
import com.android.systemui.statusbar.pipeline.mobile.ui.viewmodel.MobileIconsViewModel
import java.util.Date
@@ -38,7 +37,6 @@ import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.SharingStarted
import kotlinx.coroutines.flow.StateFlow
import kotlinx.coroutines.flow.asStateFlow
-import kotlinx.coroutines.flow.combine
import kotlinx.coroutines.flow.launchIn
import kotlinx.coroutines.flow.map
import kotlinx.coroutines.flow.onEach
@@ -57,16 +55,6 @@ constructor(
val mobileIconsViewModel: MobileIconsViewModel,
broadcastDispatcher: BroadcastDispatcher,
) {
- /** True if we are transitioning between Shade and QuickSettings scenes, in either direction. */
- val isTransitioning =
- combine(
- sceneInteractor.transitioning(from = SceneKey.Shade, to = SceneKey.QuickSettings),
- sceneInteractor.transitioning(from = SceneKey.QuickSettings, to = SceneKey.Shade)
- ) { shadeToQuickSettings, quickSettingsToShade ->
- shadeToQuickSettings || quickSettingsToShade
- }
- .stateIn(applicationScope, SharingStarted.WhileSubscribed(), false)
-
/** True if there is exactly one mobile connection. */
val isSingleCarrier: StateFlow<Boolean> = mobileIconsInteractor.isSingleCarrier
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/CentralSurfacesImpl.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/CentralSurfacesImpl.java
index ade417d7bf5c..64fcef51755d 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/CentralSurfacesImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/CentralSurfacesImpl.java
@@ -125,6 +125,7 @@ import com.android.systemui.charging.WiredChargingRippleController;
import com.android.systemui.charging.WirelessChargingAnimation;
import com.android.systemui.classifier.FalsingCollector;
import com.android.systemui.colorextraction.SysuiColorExtractor;
+import com.android.systemui.communal.domain.interactor.CommunalInteractor;
import com.android.systemui.dagger.SysUISingleton;
import com.android.systemui.dagger.qualifiers.Main;
import com.android.systemui.dagger.qualifiers.UiBackground;
@@ -245,6 +246,7 @@ import java.util.List;
import java.util.Map;
import java.util.Optional;
import java.util.concurrent.Executor;
+import java.util.function.Consumer;
import javax.inject.Inject;
import javax.inject.Named;
@@ -551,6 +553,25 @@ public class CentralSurfacesImpl implements CoreStartable, CentralSurfaces {
private final WakefulnessLifecycle mWakefulnessLifecycle;
protected final PowerInteractor mPowerInteractor;
+ private final CommunalInteractor mCommunalInteractor;
+
+ /**
+ * True if the device is showing the glanceable hub. See
+ * {@link CommunalInteractor#isIdleOnCommunal()} for more details.
+ */
+ private boolean mIsIdleOnCommunal = false;
+ private final Consumer<Boolean> mIdleOnCommunalConsumer = (Boolean idleOnCommunal) -> {
+ if (idleOnCommunal == mIsIdleOnCommunal) {
+ // Ignore initial value coming through the flow.
+ return;
+ }
+
+ mIsIdleOnCommunal = idleOnCommunal;
+ // Trigger an update for the scrim state when we enter or exit glanceable hub, so that we
+ // can transition to/from ScrimState.GLANCEABLE_HUB if needed.
+ updateScrimController();
+ };
+
private boolean mNoAnimationOnNextBarModeChange;
private final SysuiStatusBarStateController mStatusBarStateController;
@@ -618,6 +639,7 @@ public class CentralSurfacesImpl implements CoreStartable, CentralSurfaces {
ScreenLifecycle screenLifecycle,
WakefulnessLifecycle wakefulnessLifecycle,
PowerInteractor powerInteractor,
+ CommunalInteractor communalInteractor,
SysuiStatusBarStateController statusBarStateController,
Optional<Bubbles> bubblesOptional,
Lazy<NoteTaskController> noteTaskControllerLazy,
@@ -722,6 +744,7 @@ public class CentralSurfacesImpl implements CoreStartable, CentralSurfaces {
mScreenLifecycle = screenLifecycle;
mWakefulnessLifecycle = wakefulnessLifecycle;
mPowerInteractor = powerInteractor;
+ mCommunalInteractor = communalInteractor;
mStatusBarStateController = statusBarStateController;
mBubblesOptional = bubblesOptional;
mNoteTaskControllerLazy = noteTaskControllerLazy;
@@ -1051,6 +1074,10 @@ public class CentralSurfacesImpl implements CoreStartable, CentralSurfaces {
//TODO(b/264502026) move the rest of the listeners here.
mDeviceStateManager.registerCallback(mMainExecutor,
new FoldStateListener(mContext, this::onFoldedStateChanged));
+
+ mJavaAdapter.alwaysCollectFlow(
+ mCommunalInteractor.isIdleOnCommunal(),
+ mIdleOnCommunalConsumer);
}
/**
@@ -2795,6 +2822,8 @@ public class CentralSurfacesImpl implements CoreStartable, CentralSurfaces {
// This will cancel the keyguardFadingAway animation if it is running. We need to do
// this as otherwise it can remain pending and leave keyguard in a weird state.
mUnlockScrimCallback.onCancelled();
+ } else if (mIsIdleOnCommunal) {
+ mScrimController.transitionTo(ScrimState.GLANCEABLE_HUB);
} else if (mKeyguardStateController.isShowing()
&& !mKeyguardStateController.isOccluded()
&& !unlocking) {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/ScrimController.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/ScrimController.java
index 3f20eaf45260..6f78604e996f 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/ScrimController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/ScrimController.java
@@ -17,7 +17,9 @@
package com.android.systemui.statusbar.phone;
import static com.android.systemui.keyguard.shared.model.KeyguardState.ALTERNATE_BOUNCER;
+import static com.android.systemui.keyguard.shared.model.KeyguardState.GLANCEABLE_HUB;
import static com.android.systemui.keyguard.shared.model.KeyguardState.GONE;
+import static com.android.systemui.keyguard.shared.model.KeyguardState.LOCKSCREEN;
import static com.android.systemui.keyguard.shared.model.KeyguardState.PRIMARY_BOUNCER;
import static com.android.systemui.util.kotlin.JavaAdapterKt.collectFlow;
@@ -62,6 +64,7 @@ import com.android.systemui.dock.DockManager;
import com.android.systemui.keyguard.KeyguardUnlockAnimationController;
import com.android.systemui.keyguard.domain.interactor.KeyguardInteractor;
import com.android.systemui.keyguard.domain.interactor.KeyguardTransitionInteractor;
+import com.android.systemui.keyguard.shared.model.KeyguardState;
import com.android.systemui.keyguard.shared.model.ScrimAlpha;
import com.android.systemui.keyguard.shared.model.TransitionState;
import com.android.systemui.keyguard.shared.model.TransitionStep;
@@ -292,6 +295,30 @@ public class ScrimController implements ViewTreeObserver.OnPreDrawListener, Dump
mScrimBehind.setViewAlpha(mBehindAlpha);
};
+ /**
+ * Consumer that fades the behind scrim in and out during the transition between the lock screen
+ * and the glanceable hub.
+ *
+ * While the lock screen is showing, the behind scrim is used to slightly darken the lock screen
+ * wallpaper underneath. Since the glanceable hub is under all of the scrims, we want to fade
+ * out the scrim so that the glanceable hub isn't darkened when it opens.
+ *
+ * {@link #applyState()} handles the scrim alphas once on the glanceable hub, this is only
+ * responsible for setting the behind alpha during the transition.
+ */
+ private final Consumer<TransitionStep> mGlanceableHubConsumer = (TransitionStep step) -> {
+ final float baseAlpha = ScrimState.KEYGUARD.getBehindAlpha();
+ final float transitionProgress = step.getValue();
+ if (step.getTo() == KeyguardState.LOCKSCREEN) {
+ // Transitioning back to lock screen, fade in behind scrim again.
+ mBehindAlpha = baseAlpha * transitionProgress;
+ } else if (step.getTo() == GLANCEABLE_HUB) {
+ // Transitioning to glanceable hub, fade out behind scrim.
+ mBehindAlpha = baseAlpha * (1 - transitionProgress);
+ }
+ mScrimBehind.setViewAlpha(mBehindAlpha);
+ };
+
Consumer<TransitionStep> mBouncerToGoneTransition;
@Inject
@@ -444,6 +471,14 @@ public class ScrimController implements ViewTreeObserver.OnPreDrawListener, Dump
mBouncerToGoneTransition, mMainDispatcher);
collectFlow(behindScrim, mAlternateBouncerToGoneTransitionViewModel.getScrimAlpha(),
mScrimAlphaConsumer, mMainDispatcher);
+
+ // LOCKSCREEN<->GLANCEABLE_HUB
+ collectFlow(behindScrim,
+ mKeyguardTransitionInteractor.transition(LOCKSCREEN, GLANCEABLE_HUB),
+ mGlanceableHubConsumer, mMainDispatcher);
+ collectFlow(behindScrim,
+ mKeyguardTransitionInteractor.transition(GLANCEABLE_HUB, LOCKSCREEN),
+ mGlanceableHubConsumer, mMainDispatcher);
}
// TODO(b/270984686) recompute scrim height accurately, based on shade contents.
@@ -815,9 +850,9 @@ public class ScrimController implements ViewTreeObserver.OnPreDrawListener, Dump
return;
}
mBouncerHiddenFraction = bouncerHiddenAmount;
- if (mState == ScrimState.DREAMING) {
- // Only the dreaming state requires this for the scrim calculation, so we should
- // only trigger an update if dreaming.
+ if (mState == ScrimState.DREAMING || mState == ScrimState.GLANCEABLE_HUB) {
+ // The dreaming and glanceable hub states requires this for the scrim calculation, so we
+ // should only trigger an update in those states.
applyAndDispatchState();
}
}
@@ -939,7 +974,7 @@ public class ScrimController implements ViewTreeObserver.OnPreDrawListener, Dump
} else if (mState == ScrimState.AUTH_SCRIMMED_SHADE) {
mNotificationsAlpha = (float) Math.pow(getInterpolatedFraction(), 0.8f);
} else if (mState == ScrimState.KEYGUARD || mState == ScrimState.SHADE_LOCKED
- || mState == ScrimState.PULSING) {
+ || mState == ScrimState.PULSING || mState == ScrimState.GLANCEABLE_HUB) {
Pair<Integer, Float> result = calculateBackStateForState(mState);
int behindTint = result.first;
float behindAlpha = result.second;
@@ -950,6 +985,11 @@ public class ScrimController implements ViewTreeObserver.OnPreDrawListener, Dump
mTransitionToFullShadeProgress);
behindTint = ColorUtils.blendARGB(behindTint, shadeResult.first,
mTransitionToFullShadeProgress);
+ } else if (mState == ScrimState.GLANCEABLE_HUB && mTransitionToFullShadeProgress == 0.0f
+ && mBouncerHiddenFraction == KeyguardBouncerConstants.EXPANSION_HIDDEN) {
+ // Behind scrim should not be visible when idle on the glanceable hub and neither
+ // bouncer nor shade are showing.
+ behindAlpha = 0f;
}
mInFrontAlpha = mState.getFrontAlpha();
if (mClipsQsScrim) {
@@ -965,6 +1005,13 @@ public class ScrimController implements ViewTreeObserver.OnPreDrawListener, Dump
} else if (mState == ScrimState.SHADE_LOCKED) {
// going from KEYGUARD to SHADE_LOCKED state
mNotificationsAlpha = getInterpolatedFraction();
+ } else if (mState == ScrimState.GLANCEABLE_HUB
+ && mTransitionToFullShadeProgress == 0.0f) {
+ // Notification scrim should not be visible on the glanceable hub unless the
+ // shade is showing or transitioning in. Otherwise the notification scrim will
+ // be visible as the bouncer transitions in or after the notification shade
+ // closes.
+ mNotificationsAlpha = 0;
} else {
mNotificationsAlpha = Math.max(1.0f - getInterpolatedFraction(), mQsExpansion);
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/ScrimState.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/ScrimState.java
index 61bd112121bc..f2a649ba2e32 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/ScrimState.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/ScrimState.java
@@ -296,6 +296,21 @@ public enum ScrimState {
updateScrimColor(mScrimBehind, 1f /* alpha */, mBackgroundColor);
}
}
+ },
+
+ /**
+ * Device is locked or on dream and user has swiped from the right edge to enter the glanceable
+ * hub UI. From this state, the user can swipe from the left edge to go back to the lock screen
+ * or dream, as well as swipe down for the notifications and up for the bouncer.
+ */
+ GLANCEABLE_HUB {
+ @Override
+ public void prepare(ScrimState previousState) {
+ // No scrims should be visible by default in this state.
+ mBehindAlpha = 0;
+ mNotifAlpha = 0;
+ mFrontAlpha = 0;
+ }
};
boolean mBlankScreen = false;
diff --git a/packages/SystemUI/tests/src/com/android/systemui/screenrecord/RecordingServiceTest.java b/packages/SystemUI/tests/src/com/android/systemui/screenrecord/RecordingServiceTest.java
index a2aed988a423..9ce77e58a5f2 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/screenrecord/RecordingServiceTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/screenrecord/RecordingServiceTest.java
@@ -28,10 +28,10 @@ import static org.mockito.Mockito.never;
import static org.mockito.Mockito.times;
import static org.mockito.Mockito.verify;
+import android.app.ActivityOptions.LaunchCookie;
import android.app.Notification;
import android.app.NotificationManager;
import android.content.Intent;
-import android.os.Binder;
import android.os.Handler;
import android.os.RemoteException;
import android.os.UserHandle;
@@ -146,7 +146,7 @@ public class RecordingServiceTest extends SysuiTestCase {
@Test
public void testLogStartPartialRecording() {
- MediaProjectionCaptureTarget target = new MediaProjectionCaptureTarget(new Binder());
+ MediaProjectionCaptureTarget target = new MediaProjectionCaptureTarget(new LaunchCookie());
Intent startIntent = RecordingService.getStartIntent(mContext, 0, 0, false, target);
mRecordingService.onStartCommand(startIntent, 0, 0);
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/CentralSurfacesImplTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/CentralSurfacesImplTest.java
index 9c4984ee4769..849a13be58ff 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/CentralSurfacesImplTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/CentralSurfacesImplTest.java
@@ -41,6 +41,8 @@ import static org.mockito.Mockito.when;
import static java.util.Collections.emptySet;
+import static kotlinx.coroutines.flow.FlowKt.flowOf;
+
import android.app.ActivityManager;
import android.app.IWallpaperManager;
import android.app.WallpaperManager;
@@ -77,7 +79,6 @@ import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
import com.android.internal.logging.testing.FakeMetricsLogger;
import com.android.internal.statusbar.IStatusBarService;
import com.android.keyguard.KeyguardUpdateMonitor;
-import com.android.keyguard.TestScopeProvider;
import com.android.keyguard.ViewMediatorCallback;
import com.android.systemui.InitController;
import com.android.systemui.SysuiTestCase;
@@ -92,6 +93,10 @@ import com.android.systemui.charging.WiredChargingRippleController;
import com.android.systemui.classifier.FalsingCollectorFake;
import com.android.systemui.classifier.FalsingManagerFake;
import com.android.systemui.colorextraction.SysuiColorExtractor;
+import com.android.systemui.communal.data.repository.CommunalRepository;
+import com.android.systemui.communal.domain.interactor.CommunalInteractor;
+import com.android.systemui.communal.shared.model.CommunalSceneKey;
+import com.android.systemui.communal.shared.model.ObservableCommunalTransitionState;
import com.android.systemui.demomode.DemoModeController;
import com.android.systemui.dump.DumpManager;
import com.android.systemui.flags.FakeFeatureFlags;
@@ -102,6 +107,7 @@ import com.android.systemui.keyguard.KeyguardViewMediator;
import com.android.systemui.keyguard.ScreenLifecycle;
import com.android.systemui.keyguard.WakefulnessLifecycle;
import com.android.systemui.keyguard.ui.viewmodel.LightRevealScrimViewModel;
+import com.android.systemui.kosmos.KosmosJavaAdapter;
import com.android.systemui.log.LogBuffer;
import com.android.systemui.navigationbar.NavigationBarController;
import com.android.systemui.notetask.NoteTaskController;
@@ -195,6 +201,8 @@ import java.util.Optional;
import javax.inject.Provider;
+import kotlinx.coroutines.test.TestScope;
+
@SmallTest
@RunWith(AndroidTestingRunner.class)
@RunWithLooper(setAsMainLooper = true)
@@ -203,11 +211,17 @@ public class CentralSurfacesImplTest extends SysuiTestCase {
private static final int FOLD_STATE_FOLDED = 0;
private static final int FOLD_STATE_UNFOLDED = 1;
+ private final KosmosJavaAdapter mKosmos = new KosmosJavaAdapter(this);
+
private CentralSurfacesImpl mCentralSurfaces;
private FakeMetricsLogger mMetricsLogger;
private PowerManager mPowerManager;
private VisualInterruptionDecisionProvider mVisualInterruptionDecisionProvider;
+
+ private final TestScope mTestScope = mKosmos.getTestScope();
+ private final CommunalInteractor mCommunalInteractor = mKosmos.getCommunalInteractor();
+ private final CommunalRepository mCommunalRepository = mKosmos.getCommunalRepository();
@Mock private NotificationsController mNotificationsController;
@Mock private LightBarController mLightBarController;
@Mock private StatusBarKeyguardViewManager mStatusBarKeyguardViewManager;
@@ -461,7 +475,7 @@ public class CentralSurfacesImplTest extends SysuiTestCase {
new DisplayMetrics(),
mMetricsLogger,
mShadeLogger,
- new JavaAdapter(TestScopeProvider.getTestScope()),
+ new JavaAdapter(mTestScope),
mUiBgExecutor,
mNotificationPanelViewController,
mNotificationMediaManager,
@@ -473,6 +487,7 @@ public class CentralSurfacesImplTest extends SysuiTestCase {
mScreenLifecycle,
mWakefulnessLifecycle,
mPowerInteractor,
+ mCommunalInteractor,
mStatusBarStateController,
Optional.of(mBubbles),
() -> mNoteTaskController,
@@ -821,6 +836,25 @@ public class CentralSurfacesImplTest extends SysuiTestCase {
}
@Test
+ public void testEnteringGlanceableHub_updatesScrim() {
+ // Transition to the glanceable hub.
+ mCommunalRepository.setTransitionState(flowOf(new ObservableCommunalTransitionState.Idle(
+ CommunalSceneKey.Communal.INSTANCE)));
+ mTestScope.getTestScheduler().runCurrent();
+
+ // ScrimState also transitions.
+ verify(mScrimController).transitionTo(ScrimState.GLANCEABLE_HUB);
+
+ // Transition away from the glanceable hub.
+ mCommunalRepository.setTransitionState(flowOf(new ObservableCommunalTransitionState.Idle(
+ CommunalSceneKey.Blank.INSTANCE)));
+ mTestScope.getTestScheduler().runCurrent();
+
+ // ScrimState goes back to UNLOCKED.
+ verify(mScrimController).transitionTo(eq(ScrimState.UNLOCKED), any());
+ }
+
+ @Test
public void testShowKeyguardImplementation_setsState() {
when(mLockscreenUserManager.getCurrentProfiles()).thenReturn(new SparseArray<>());
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/ScrimControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/ScrimControllerTest.java
index 423cc8478dda..3bde6e36a51f 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/ScrimControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/ScrimControllerTest.java
@@ -51,6 +51,7 @@ import android.content.res.TypedArray;
import android.graphics.Color;
import android.testing.AndroidTestingRunner;
import android.testing.TestableLooper;
+import android.testing.ViewUtils;
import android.util.MathUtils;
import android.view.View;
@@ -59,13 +60,13 @@ import androidx.test.filters.SmallTest;
import com.android.internal.colorextraction.ColorExtractor.GradientColors;
import com.android.keyguard.BouncerPanelExpansionCalculator;
import com.android.keyguard.KeyguardUpdateMonitor;
-import com.android.keyguard.TestScopeProvider;
import com.android.systemui.DejankUtils;
import com.android.systemui.SysuiTestCase;
import com.android.systemui.animation.ShadeInterpolation;
import com.android.systemui.bouncer.shared.constants.KeyguardBouncerConstants;
import com.android.systemui.dock.DockManager;
import com.android.systemui.keyguard.KeyguardUnlockAnimationController;
+import com.android.systemui.keyguard.data.repository.FakeKeyguardTransitionRepository;
import com.android.systemui.keyguard.domain.interactor.KeyguardInteractor;
import com.android.systemui.keyguard.domain.interactor.KeyguardTransitionInteractor;
import com.android.systemui.keyguard.shared.model.KeyguardState;
@@ -73,6 +74,7 @@ import com.android.systemui.keyguard.shared.model.TransitionState;
import com.android.systemui.keyguard.shared.model.TransitionStep;
import com.android.systemui.keyguard.ui.viewmodel.AlternateBouncerToGoneTransitionViewModel;
import com.android.systemui.keyguard.ui.viewmodel.PrimaryBouncerToGoneTransitionViewModel;
+import com.android.systemui.kosmos.KosmosJavaAdapter;
import com.android.systemui.scrim.ScrimView;
import com.android.systemui.shade.transition.LargeScreenShadeInterpolator;
import com.android.systemui.shade.transition.LinearLargeScreenShadeInterpolator;
@@ -103,7 +105,6 @@ import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;
-import kotlinx.coroutines.CoroutineDispatcher;
import kotlinx.coroutines.test.TestScope;
@RunWith(AndroidTestingRunner.class)
@@ -112,13 +113,14 @@ import kotlinx.coroutines.test.TestScope;
public class ScrimControllerTest extends SysuiTestCase {
@Rule public Expect mExpect = Expect.create();
+ private final KosmosJavaAdapter mKosmos = new KosmosJavaAdapter(this);
private final FakeConfigurationController mConfigurationController =
new FakeConfigurationController();
private final LargeScreenShadeInterpolator
mLinearLargeScreenShadeInterpolator = new LinearLargeScreenShadeInterpolator();
- private final TestScope mTestScope = TestScopeProvider.getTestScope();
+ private final TestScope mTestScope = mKosmos.getTestScope();
private final JavaAdapter mJavaAdapter = new JavaAdapter(mTestScope.getBackgroundScope());
private ScrimController mScrimController;
@@ -145,10 +147,12 @@ public class ScrimControllerTest extends SysuiTestCase {
@Mock private PrimaryBouncerToGoneTransitionViewModel mPrimaryBouncerToGoneTransitionViewModel;
@Mock private AlternateBouncerToGoneTransitionViewModel
mAlternateBouncerToGoneTransitionViewModel;
- @Mock private KeyguardTransitionInteractor mKeyguardTransitionInteractor;
+ private final KeyguardTransitionInteractor mKeyguardTransitionInteractor =
+ mKosmos.getKeyguardTransitionInteractor();
+ private final FakeKeyguardTransitionRepository mKeyguardTransitionRepository =
+ mKosmos.getKeyguardTransitionRepository();
@Mock private KeyguardInteractor mKeyguardInteractor;
private final FakeWallpaperRepository mWallpaperRepository = new FakeWallpaperRepository();
- @Mock private CoroutineDispatcher mMainDispatcher;
@Mock private TypedArray mMockTypedArray;
// TODO(b/204991468): Use a real PanelExpansionStateManager object once this bug is fixed. (The
@@ -265,8 +269,6 @@ public class ScrimControllerTest extends SysuiTestCase {
when(mDelayedWakeLockFactory.create(any(String.class))).thenReturn(mWakeLock);
when(mDockManager.isDocked()).thenReturn(false);
- when(mKeyguardTransitionInteractor.transition(any(), any()))
- .thenReturn(emptyFlow());
when(mPrimaryBouncerToGoneTransitionViewModel.getScrimAlpha())
.thenReturn(emptyFlow());
when(mAlternateBouncerToGoneTransitionViewModel.getScrimAlpha())
@@ -292,13 +294,16 @@ public class ScrimControllerTest extends SysuiTestCase {
mKeyguardTransitionInteractor,
mKeyguardInteractor,
mWallpaperRepository,
- mMainDispatcher,
+ mKosmos.getTestDispatcher(),
mLinearLargeScreenShadeInterpolator);
mScrimController.start();
mScrimController.setScrimVisibleListener(visible -> mScrimVisibility = visible);
mScrimController.attachViews(mScrimBehind, mNotificationsScrim, mScrimInFront);
mScrimController.setAnimatorListener(mAnimatorListener);
+ // Attach behind scrim so flows that are collecting on it start running.
+ ViewUtils.attachView(mScrimBehind);
+
mScrimController.setHasBackdrop(false);
mWallpaperRepository.getWallpaperSupportsAmbientMode().setValue(false);
@@ -629,6 +634,164 @@ public class ScrimControllerTest extends SysuiTestCase {
}
@Test
+ public void lockscreenToHubTransition_setsBehindScrimAlpha() {
+ // Start on lockscreen.
+ mScrimController.transitionTo(ScrimState.KEYGUARD);
+ finishAnimationsImmediately();
+
+ // Behind scrim starts at default alpha.
+ final float transitionProgress = 0f;
+ float expectedAlpha = ScrimState.KEYGUARD.getBehindAlpha();
+ mKeyguardTransitionRepository.sendTransitionStepJava(mKosmos.getTestScope(),
+ new TransitionStep(
+ KeyguardState.LOCKSCREEN,
+ KeyguardState.GLANCEABLE_HUB,
+ transitionProgress,
+ TransitionState.STARTED
+ ), true);
+ mTestScope.getTestScheduler().runCurrent();
+ assertThat(mScrimBehind.getViewAlpha()).isEqualTo(expectedAlpha);
+
+ // Scrim fades out as transition runs.
+ final float runningProgress = 0.2f;
+ expectedAlpha = (1 - runningProgress) * ScrimState.KEYGUARD.getBehindAlpha();
+ mKeyguardTransitionRepository.sendTransitionStepJava(mKosmos.getTestScope(),
+ new TransitionStep(
+ KeyguardState.LOCKSCREEN,
+ KeyguardState.GLANCEABLE_HUB,
+ runningProgress,
+ TransitionState.RUNNING
+ ), true);
+ mTestScope.getTestScheduler().runCurrent();
+ assertThat(mScrimBehind.getViewAlpha()).isEqualTo(expectedAlpha);
+
+ // Scrim invisible at end of transition.
+ final float finishedProgress = 1f;
+ expectedAlpha = 0f;
+ mKeyguardTransitionRepository.sendTransitionStepJava(mKosmos.getTestScope(),
+ new TransitionStep(
+ KeyguardState.LOCKSCREEN,
+ KeyguardState.GLANCEABLE_HUB,
+ finishedProgress,
+ TransitionState.FINISHED
+ ), true);
+ mTestScope.getTestScheduler().runCurrent();
+ assertThat(mScrimBehind.getViewAlpha()).isEqualTo(expectedAlpha);
+ }
+
+ @Test
+ public void hubToLockscreenTransition_setsViewAlpha() {
+ // Start on glanceable hub.
+ mScrimController.transitionTo(ScrimState.GLANCEABLE_HUB);
+ finishAnimationsImmediately();
+
+ // Behind scrim starts at 0 alpha.
+ final float transitionProgress = 0f;
+ float expectedAlpha = 0f;
+ mKeyguardTransitionRepository.sendTransitionStepJava(mKosmos.getTestScope(),
+ new TransitionStep(
+ KeyguardState.GLANCEABLE_HUB,
+ KeyguardState.LOCKSCREEN,
+ transitionProgress,
+ TransitionState.STARTED
+ ), true);
+ mTestScope.getTestScheduler().runCurrent();
+ assertThat(mScrimBehind.getViewAlpha()).isEqualTo(expectedAlpha);
+
+ // Scrim fades in as transition runs.
+ final float runningProgress = 0.2f;
+ expectedAlpha = runningProgress * ScrimState.KEYGUARD.getBehindAlpha();
+ mKeyguardTransitionRepository.sendTransitionStepJava(mKosmos.getTestScope(),
+ new TransitionStep(
+ KeyguardState.GLANCEABLE_HUB,
+ KeyguardState.LOCKSCREEN,
+ runningProgress,
+ TransitionState.RUNNING
+ ), true);
+ mTestScope.getTestScheduler().runCurrent();
+ assertThat(mScrimBehind.getViewAlpha()).isEqualTo(expectedAlpha);
+
+ // Scrim at default visibility at end of transition.
+ final float finishedProgress = 1f;
+ expectedAlpha = finishedProgress * ScrimState.KEYGUARD.getBehindAlpha();
+ mKeyguardTransitionRepository.sendTransitionStepJava(mKosmos.getTestScope(),
+ new TransitionStep(
+ KeyguardState.GLANCEABLE_HUB,
+ KeyguardState.LOCKSCREEN,
+ finishedProgress,
+ TransitionState.FINISHED
+ ), true);
+ mTestScope.getTestScheduler().runCurrent();
+ assertThat(mScrimBehind.getViewAlpha()).isEqualTo(expectedAlpha);
+ }
+
+ @Test
+ public void transitionToHub() {
+ mScrimController.setRawPanelExpansionFraction(0f);
+ mScrimController.setBouncerHiddenFraction(KeyguardBouncerConstants.EXPANSION_HIDDEN);
+ mScrimController.transitionTo(ScrimState.GLANCEABLE_HUB);
+ finishAnimationsImmediately();
+
+ // All scrims transparent on the hub.
+ assertScrimAlpha(Map.of(
+ mScrimInFront, TRANSPARENT,
+ mNotificationsScrim, TRANSPARENT,
+ mScrimBehind, TRANSPARENT));
+ }
+
+ @Test
+ public void openBouncerOnHub() {
+ mScrimController.transitionTo(ScrimState.GLANCEABLE_HUB);
+
+ // Open the bouncer.
+ mScrimController.setRawPanelExpansionFraction(0f);
+ mScrimController.setBouncerHiddenFraction(KeyguardBouncerConstants.EXPANSION_VISIBLE);
+ finishAnimationsImmediately();
+
+ // Only behind widget is visible.
+ assertScrimAlpha(Map.of(
+ mScrimInFront, TRANSPARENT,
+ mNotificationsScrim, TRANSPARENT,
+ mScrimBehind, OPAQUE));
+
+ // Bouncer is closed.
+ mScrimController.setBouncerHiddenFraction(KeyguardBouncerConstants.EXPANSION_HIDDEN);
+ mScrimController.transitionTo(ScrimState.GLANCEABLE_HUB);
+ finishAnimationsImmediately();
+
+ // All scrims are transparent.
+ assertScrimAlpha(Map.of(
+ mScrimInFront, TRANSPARENT,
+ mNotificationsScrim, TRANSPARENT,
+ mScrimBehind, TRANSPARENT));
+ }
+
+ @Test
+ public void openShadeOnHub() {
+ mScrimController.transitionTo(ScrimState.GLANCEABLE_HUB);
+
+ // Open the shade.
+ mScrimController.transitionTo(SHADE_LOCKED);
+ mScrimController.setQsPosition(1f, 0);
+ finishAnimationsImmediately();
+
+ // Shade scrims are visible.
+ assertScrimAlpha(Map.of(
+ mNotificationsScrim, OPAQUE,
+ mScrimInFront, TRANSPARENT,
+ mScrimBehind, OPAQUE));
+
+ mScrimController.transitionTo(ScrimState.GLANCEABLE_HUB);
+ finishAnimationsImmediately();
+
+ // All scrims are transparent.
+ assertScrimAlpha(Map.of(
+ mScrimInFront, TRANSPARENT,
+ mNotificationsScrim, TRANSPARENT,
+ mScrimBehind, TRANSPARENT));
+ }
+
+ @Test
public void onThemeChange_bouncerBehindTint_isUpdatedToSurfaceColor() {
assertEquals(BOUNCER.getBehindTint(), 0x112233);
mSurfaceColor = 0x223344;
@@ -1001,7 +1164,7 @@ public class ScrimControllerTest extends SysuiTestCase {
mKeyguardTransitionInteractor,
mKeyguardInteractor,
mWallpaperRepository,
- mMainDispatcher,
+ mKosmos.getTestDispatcher(),
mLinearLargeScreenShadeInterpolator);
mScrimController.start();
mScrimController.setScrimVisibleListener(visible -> mScrimVisibility = visible);
@@ -1267,7 +1430,7 @@ public class ScrimControllerTest extends SysuiTestCase {
ScrimState.UNINITIALIZED, ScrimState.KEYGUARD, BOUNCER,
ScrimState.DREAMING, ScrimState.BOUNCER_SCRIMMED, ScrimState.BRIGHTNESS_MIRROR,
ScrimState.UNLOCKED, SHADE_LOCKED, ScrimState.AUTH_SCRIMMED,
- ScrimState.AUTH_SCRIMMED_SHADE));
+ ScrimState.AUTH_SCRIMMED_SHADE, ScrimState.GLANCEABLE_HUB));
for (ScrimState state : ScrimState.values()) {
if (!lowPowerModeStates.contains(state) && !regularStates.contains(state)) {
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/data/repository/FakeKeyguardTransitionRepository.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/data/repository/FakeKeyguardTransitionRepository.kt
index 0c1dbfebfb34..e20a0ab4190e 100644
--- a/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/data/repository/FakeKeyguardTransitionRepository.kt
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/data/repository/FakeKeyguardTransitionRepository.kt
@@ -28,9 +28,12 @@ import dagger.Module
import java.util.UUID
import javax.inject.Inject
import junit.framework.Assert.fail
+import kotlinx.coroutines.CoroutineScope
+import kotlinx.coroutines.Job
import kotlinx.coroutines.channels.BufferOverflow
import kotlinx.coroutines.flow.MutableSharedFlow
import kotlinx.coroutines.flow.SharedFlow
+import kotlinx.coroutines.launch
import kotlinx.coroutines.test.TestCoroutineScheduler
import kotlinx.coroutines.test.TestScope
import kotlinx.coroutines.test.runCurrent
@@ -150,6 +153,15 @@ class FakeKeyguardTransitionRepository @Inject constructor() : KeyguardTransitio
_transitions.emit(step)
}
+ /** Version of [sendTransitionStep] that's usable from Java tests. */
+ fun sendTransitionStepJava(
+ coroutineScope: CoroutineScope,
+ step: TransitionStep,
+ validateStep: Boolean = true
+ ): Job {
+ return coroutineScope.launch { sendTransitionStep(step, validateStep) }
+ }
+
suspend fun sendTransitionSteps(
steps: List<TransitionStep>,
testScope: TestScope,
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/kosmos/KosmosJavaAdapter.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/kosmos/KosmosJavaAdapter.kt
index 11f2938141b4..083de107c971 100644
--- a/packages/SystemUI/tests/utils/src/com/android/systemui/kosmos/KosmosJavaAdapter.kt
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/kosmos/KosmosJavaAdapter.kt
@@ -32,6 +32,8 @@ import com.android.systemui.deviceentry.domain.interactor.deviceUnlockedInteract
import com.android.systemui.flags.fakeFeatureFlagsClassic
import com.android.systemui.jank.interactionJankMonitor
import com.android.systemui.keyguard.data.repository.fakeKeyguardRepository
+import com.android.systemui.keyguard.data.repository.fakeKeyguardTransitionRepository
+import com.android.systemui.keyguard.domain.interactor.keyguardTransitionInteractor
import com.android.systemui.model.sceneContainerPlugin
import com.android.systemui.plugins.statusbar.statusBarStateController
import com.android.systemui.power.data.repository.fakePowerRepository
@@ -61,6 +63,8 @@ class KosmosJavaAdapter(
val bouncerRepository by lazy { kosmos.bouncerRepository }
val communalRepository by lazy { kosmos.fakeCommunalRepository }
val keyguardRepository by lazy { kosmos.fakeKeyguardRepository }
+ val keyguardTransitionRepository by lazy { kosmos.fakeKeyguardTransitionRepository }
+ val keyguardTransitionInteractor by lazy { kosmos.keyguardTransitionInteractor }
val powerRepository by lazy { kosmos.fakePowerRepository }
val clock by lazy { kosmos.systemClock }
val mobileConnectionsRepository by lazy { kosmos.fakeMobileConnectionsRepository }
diff --git a/packages/services/CameraExtensionsProxy/src/com/android/cameraextensions/CameraExtensionsProxyService.java b/packages/services/CameraExtensionsProxy/src/com/android/cameraextensions/CameraExtensionsProxyService.java
index 3aa9cc84e9f6..155c523a96a7 100644
--- a/packages/services/CameraExtensionsProxy/src/com/android/cameraextensions/CameraExtensionsProxyService.java
+++ b/packages/services/CameraExtensionsProxy/src/com/android/cameraextensions/CameraExtensionsProxyService.java
@@ -132,7 +132,7 @@ public class CameraExtensionsProxyService extends Service {
private static final String CAMERA_EXTENSION_VERSION_NAME =
"androidx.camera.extensions.impl.ExtensionVersionImpl";
- private static final String LATEST_VERSION = "1.4.0";
+ private static final String LATEST_VERSION = "1.5.0";
// No support for the init sequence
private static final String NON_INIT_VERSION_PREFIX = "1.0";
// Support advanced API and latency queries
@@ -1693,6 +1693,7 @@ public class CameraExtensionsProxyService extends Service {
private final Size mSize;
private final int mImageFormat;
private final int mDataspace;
+ private final long mUsage;
public OutputSurfaceImplStub(OutputSurface outputSurface) {
mSurface = outputSurface.surface;
@@ -1700,8 +1701,10 @@ public class CameraExtensionsProxyService extends Service {
mImageFormat = outputSurface.imageFormat;
if (mSurface != null) {
mDataspace = SurfaceUtils.getSurfaceDataspace(mSurface);
+ mUsage = SurfaceUtils.getSurfaceUsage(mSurface);
} else {
mDataspace = -1;
+ mUsage = 0;
}
}
@@ -1724,6 +1727,11 @@ public class CameraExtensionsProxyService extends Service {
public int getDataspace() {
return mDataspace;
}
+
+ @Override
+ public long getUsage() {
+ return mUsage;
+ }
}
private class PreviewExtenderImplStub extends IPreviewExtenderImpl.Stub implements
@@ -2471,6 +2479,11 @@ public class CameraExtensionsProxyService extends Service {
ret.size.height = imageReaderOutputConfig.getSize().getHeight();
ret.imageFormat = imageReaderOutputConfig.getImageFormat();
ret.capacity = imageReaderOutputConfig.getMaxImages();
+ if (EFV_SUPPORTED) {
+ ret.usage = imageReaderOutputConfig.getUsage();
+ } else {
+ ret.usage = 0;
+ }
} else if (output instanceof MultiResolutionImageReaderOutputConfigImpl) {
MultiResolutionImageReaderOutputConfigImpl multiResReaderConfig =
(MultiResolutionImageReaderOutputConfigImpl) output;
diff --git a/ravenwood/Android.bp b/ravenwood/Android.bp
index e013a3e41896..1ac69f6c4fc8 100644
--- a/ravenwood/Android.bp
+++ b/ravenwood/Android.bp
@@ -30,6 +30,9 @@ java_library {
"junit-src/**/*.java",
"junit-impl-src/**/*.java",
],
+ static_libs: [
+ "androidx.test.monitor-for-device",
+ ],
libs: [
"framework-minus-apex.ravenwood",
"junit",
@@ -61,3 +64,17 @@ java_host_for_device {
"core-xml-for-host",
],
}
+
+java_host_for_device {
+ name: "androidx.test.monitor-for-device",
+ libs: [
+ "androidx.test.monitor-for-host",
+ ],
+}
+
+java_device_for_host {
+ name: "androidx.test.monitor-for-host",
+ libs: [
+ "androidx.test.monitor",
+ ],
+}
diff --git a/ravenwood/junit-impl-src/android/platform/test/ravenwood/RavenwoodRuleImpl.java b/ravenwood/junit-impl-src/android/platform/test/ravenwood/RavenwoodRuleImpl.java
index b3dbcde9d324..a797b1d61b2a 100644
--- a/ravenwood/junit-impl-src/android/platform/test/ravenwood/RavenwoodRuleImpl.java
+++ b/ravenwood/junit-impl-src/android/platform/test/ravenwood/RavenwoodRuleImpl.java
@@ -16,12 +16,35 @@
package android.platform.test.ravenwood;
+import android.app.Instrumentation;
+import android.os.Bundle;
import android.os.HandlerThread;
import android.os.Looper;
+import androidx.test.platform.app.InstrumentationRegistry;
+
+import java.io.PrintStream;
+import java.util.Map;
+import java.util.concurrent.Executors;
+import java.util.concurrent.ScheduledExecutorService;
+import java.util.concurrent.ScheduledFuture;
+import java.util.concurrent.TimeUnit;
+
public class RavenwoodRuleImpl {
private static final String MAIN_THREAD_NAME = "RavenwoodMain";
+ /**
+ * When enabled, attempt to dump all thread stacks just before we hit the
+ * overall Tradefed timeout, to aid in debugging deadlocks.
+ */
+ private static final boolean ENABLE_TIMEOUT_STACKS = false;
+ private static final int TIMEOUT_MILLIS = 9_000;
+
+ private static final ScheduledExecutorService sTimeoutExecutor =
+ Executors.newScheduledThreadPool(1);
+
+ private static ScheduledFuture<?> sPendingTimeout;
+
public static boolean isOnRavenwood() {
return true;
}
@@ -41,9 +64,22 @@ public class RavenwoodRuleImpl {
main.start();
Looper.setMainLooperForTest(main.getLooper());
}
+
+ InstrumentationRegistry.registerInstance(new Instrumentation(), Bundle.EMPTY);
+
+ if (ENABLE_TIMEOUT_STACKS) {
+ sPendingTimeout = sTimeoutExecutor.schedule(RavenwoodRuleImpl::dumpStacks,
+ TIMEOUT_MILLIS, TimeUnit.MILLISECONDS);
+ }
}
public static void reset(RavenwoodRule rule) {
+ if (ENABLE_TIMEOUT_STACKS) {
+ sPendingTimeout.cancel(false);
+ }
+
+ InstrumentationRegistry.registerInstance(null, Bundle.EMPTY);
+
if (rule.mProvideMainThread) {
Looper.getMainLooper().quit();
Looper.clearMainLooperForTest();
@@ -55,4 +91,19 @@ public class RavenwoodRuleImpl {
android.os.Binder.reset$ravenwood();
android.os.Process.reset$ravenwood();
}
+
+ private static void dumpStacks() {
+ final PrintStream out = System.err;
+ out.println("-----BEGIN ALL THREAD STACKS-----");
+ final Map<Thread, StackTraceElement[]> stacks = Thread.getAllStackTraces();
+ for (Map.Entry<Thread, StackTraceElement[]> stack : stacks.entrySet()) {
+ out.println();
+ Thread t = stack.getKey();
+ out.println(t.toString() + " ID=" + t.getId());
+ for (StackTraceElement e : stack.getValue()) {
+ out.println("\tat " + e);
+ }
+ }
+ out.println("-----END ALL THREAD STACKS-----");
+ }
}
diff --git a/ravenwood/junit-src/android/platform/test/ravenwood/RavenwoodClassRule.java b/ravenwood/junit-src/android/platform/test/ravenwood/RavenwoodClassRule.java
index 68b163ede89c..8d76970f9ad4 100644
--- a/ravenwood/junit-src/android/platform/test/ravenwood/RavenwoodClassRule.java
+++ b/ravenwood/junit-src/android/platform/test/ravenwood/RavenwoodClassRule.java
@@ -19,6 +19,7 @@ package android.platform.test.ravenwood;
import static android.platform.test.ravenwood.RavenwoodRule.ENABLE_PROBE_IGNORED;
import static android.platform.test.ravenwood.RavenwoodRule.IS_ON_RAVENWOOD;
import static android.platform.test.ravenwood.RavenwoodRule.shouldEnableOnRavenwood;
+import static android.platform.test.ravenwood.RavenwoodRule.shouldStillIgnoreInProbeIgnoreMode;
import android.platform.test.annotations.DisabledOnRavenwood;
import android.platform.test.annotations.EnabledOnRavenwood;
@@ -45,6 +46,7 @@ public class RavenwoodClassRule implements TestRule {
}
if (ENABLE_PROBE_IGNORED) {
+ Assume.assumeFalse(shouldStillIgnoreInProbeIgnoreMode(description));
// Pass through to possible underlying RavenwoodRule for both environment
// configuration and handling method-level annotations
return base;
diff --git a/ravenwood/junit-src/android/platform/test/ravenwood/RavenwoodRule.java b/ravenwood/junit-src/android/platform/test/ravenwood/RavenwoodRule.java
index 952ee0e184b1..1e7cbf6d802d 100644
--- a/ravenwood/junit-src/android/platform/test/ravenwood/RavenwoodRule.java
+++ b/ravenwood/junit-src/android/platform/test/ravenwood/RavenwoodRule.java
@@ -27,7 +27,9 @@ import org.junit.rules.TestRule;
import org.junit.runner.Description;
import org.junit.runners.model.Statement;
+import java.util.Objects;
import java.util.concurrent.atomic.AtomicInteger;
+import java.util.regex.Pattern;
/**
* {@code @Rule} that configures the Ravenwood test environment. This rule has no effect when
@@ -55,6 +57,43 @@ public class RavenwoodRule implements TestRule {
static final boolean ENABLE_PROBE_IGNORED = "1".equals(
System.getenv("RAVENWOOD_RUN_DISABLED_TESTS"));
+ /**
+ * When using ENABLE_PROBE_IGNORED, you may still want to skip certain tests,
+ * for example because the test would crash the JVM.
+ *
+ * This regex defines the tests that should still be disabled even if ENABLE_PROBE_IGNORED
+ * is set.
+ *
+ * Before running each test class and method, we check if this pattern can be found in
+ * the full test name (either [class full name], or [class full name] + "#" + [method name]),
+ * and if so, we skip it.
+ *
+ * For example, if you want to skip an entire test class, use:
+ * RAVENWOOD_REALLY_DISABLE='\.CustomTileDefaultsRepositoryTest$'
+ *
+ * For example, if you want to skip an entire test class, use:
+ * RAVENWOOD_REALLY_DISABLE='\.CustomTileDefaultsRepositoryTest#testSimple$'
+ *
+ * To ignore multiple classes, use (...|...), for example:
+ * RAVENWOOD_REALLY_DISABLE='\.(ClassA|ClassB)$'
+ *
+ * Because we use a regex-find, setting "." would disable all tests.
+ */
+ private static final Pattern REALLY_DISABLE_PATTERN = Pattern.compile(
+ Objects.requireNonNullElse(System.getenv("RAVENWOOD_REALLY_DISABLE"), ""));
+
+ private static final boolean ENABLE_REALLY_DISABLE_PATTERN =
+ !REALLY_DISABLE_PATTERN.pattern().isEmpty();
+
+ static {
+ if (ENABLE_PROBE_IGNORED) {
+ System.out.println("$RAVENWOOD_RUN_DISABLED_TESTS enabled: force running all tests");
+ if (ENABLE_REALLY_DISABLE_PATTERN) {
+ System.out.println("$RAVENWOOD_REALLY_DISABLE=" + REALLY_DISABLE_PATTERN.pattern());
+ }
+ }
+ }
+
private static final int SYSTEM_UID = 1000;
private static final int NOBODY_UID = 9999;
private static final int FIRST_APPLICATION_UID = 10000;
@@ -203,6 +242,21 @@ public class RavenwoodRule implements TestRule {
return true;
}
+ static boolean shouldStillIgnoreInProbeIgnoreMode(Description description) {
+ if (!ENABLE_REALLY_DISABLE_PATTERN) {
+ return false;
+ }
+
+ final var fullname = description.getTestClass().getName()
+ + (description.isTest() ? "#" + description.getMethodName() : "");
+
+ if (REALLY_DISABLE_PATTERN.matcher(fullname).find()) {
+ System.out.println("Still ignoring " + fullname);
+ return true;
+ }
+ return false;
+ }
+
@Override
public Statement apply(Statement base, Description description) {
// No special treatment when running outside Ravenwood; run tests as-is
@@ -245,6 +299,7 @@ public class RavenwoodRule implements TestRule {
return new Statement() {
@Override
public void evaluate() throws Throwable {
+ Assume.assumeFalse(shouldStillIgnoreInProbeIgnoreMode(description));
RavenwoodRuleImpl.init(RavenwoodRule.this);
try {
base.evaluate();
diff --git a/ravenwood/ravenwood-annotation-allowed-classes.txt b/ravenwood/ravenwood-annotation-allowed-classes.txt
index eaf01a32592e..b775f9ad47ad 100644
--- a/ravenwood/ravenwood-annotation-allowed-classes.txt
+++ b/ravenwood/ravenwood-annotation-allowed-classes.txt
@@ -72,6 +72,7 @@ android.os.Process
android.os.ServiceSpecificException
android.os.SystemClock
android.os.SystemProperties
+android.os.TestLooperManager
android.os.ThreadLocalWorkSource
android.os.TimestampedValue
android.os.Trace
@@ -141,6 +142,8 @@ android.graphics.RectF
android.content.ContentProvider
+android.app.Instrumentation
+
android.metrics.LogMaker
android.view.Display$HdrCapabilities
diff --git a/services/core/java/com/android/server/BinderCallsStatsService.java b/services/core/java/com/android/server/BinderCallsStatsService.java
index b87184aa5582..416b36feb94d 100644
--- a/services/core/java/com/android/server/BinderCallsStatsService.java
+++ b/services/core/java/com/android/server/BinderCallsStatsService.java
@@ -288,22 +288,23 @@ public class BinderCallsStatsService extends Binder {
CachedDeviceState.Readonly.class);
mBinderCallsStats.setDeviceState(deviceState);
- BatteryStatsInternal batteryStatsInternal = getLocalService(
- BatteryStatsInternal.class);
- mBinderCallsStats.setCallStatsObserver(new BinderInternal.CallStatsObserver() {
- @Override
- public void noteCallStats(int workSourceUid, long incrementalCallCount,
- Collection<BinderCallsStats.CallStat> callStats) {
- batteryStatsInternal.noteBinderCallStats(workSourceUid,
- incrementalCallCount, callStats);
- }
-
- @Override
- public void noteBinderThreadNativeIds(int[] binderThreadNativeTids) {
- batteryStatsInternal.noteBinderThreadNativeIds(binderThreadNativeTids);
- }
- });
-
+ if (!com.android.server.power.optimization.Flags.disableSystemServicePowerAttr()) {
+ BatteryStatsInternal batteryStatsInternal = getLocalService(
+ BatteryStatsInternal.class);
+ mBinderCallsStats.setCallStatsObserver(new BinderInternal.CallStatsObserver() {
+ @Override
+ public void noteCallStats(int workSourceUid, long incrementalCallCount,
+ Collection<BinderCallsStats.CallStat> callStats) {
+ batteryStatsInternal.noteBinderCallStats(workSourceUid,
+ incrementalCallCount, callStats);
+ }
+
+ @Override
+ public void noteBinderThreadNativeIds(int[] binderThreadNativeTids) {
+ batteryStatsInternal.noteBinderThreadNativeIds(binderThreadNativeTids);
+ }
+ });
+ }
// It needs to be called before mService.systemReady to make sure the observer is
// initialized before installing it.
mWorkSourceProvider.systemReady(getContext());
diff --git a/services/core/java/com/android/server/SensitiveContentProtectionManagerService.java b/services/core/java/com/android/server/SensitiveContentProtectionManagerService.java
index c3916422159e..f619ca3f66a2 100644
--- a/services/core/java/com/android/server/SensitiveContentProtectionManagerService.java
+++ b/services/core/java/com/android/server/SensitiveContentProtectionManagerService.java
@@ -27,6 +27,7 @@ import android.media.projection.MediaProjectionManager;
import android.os.Handler;
import android.os.Looper;
import android.os.RemoteException;
+import android.os.Trace;
import android.os.UserHandle;
import android.service.notification.NotificationListenerService;
import android.service.notification.NotificationListenerService.RankingMap;
@@ -49,12 +50,12 @@ public final class SensitiveContentProtectionManagerService extends SystemServic
private static final String TAG = "SensitiveContentProtect";
private static final boolean DEBUG = false;
- @VisibleForTesting
- NotificationListener mNotificationListener;
+ @VisibleForTesting NotificationListener mNotificationListener;
private @Nullable MediaProjectionManager mProjectionManager;
private @Nullable WindowManagerInternal mWindowManager;
final Object mSensitiveContentProtectionLock = new Object();
+
@GuardedBy("mSensitiveContentProtectionLock")
private boolean mProjectionActive = false;
@@ -63,13 +64,24 @@ public final class SensitiveContentProtectionManagerService extends SystemServic
@Override
public void onStart(MediaProjectionInfo info) {
if (DEBUG) Log.d(TAG, "onStart projection: " + info);
- onProjectionStart();
+ Trace.beginSection(
+ "SensitiveContentProtectionManagerService.onProjectionStart");
+ try {
+ onProjectionStart();
+ } finally {
+ Trace.endSection();
+ }
}
@Override
public void onStop(MediaProjectionInfo info) {
if (DEBUG) Log.d(TAG, "onStop projection: " + info);
- onProjectionEnd();
+ Trace.beginSection("SensitiveContentProtectionManagerService.onProjectionStop");
+ try {
+ onProjectionEnd();
+ } finally {
+ Trace.endSection();
+ }
}
};
@@ -94,8 +106,7 @@ public final class SensitiveContentProtectionManagerService extends SystemServic
}
@VisibleForTesting
- void init(MediaProjectionManager projectionManager,
- WindowManagerInternal windowManager) {
+ void init(MediaProjectionManager projectionManager, WindowManagerInternal windowManager) {
if (DEBUG) Log.d(TAG, "init");
checkNotNull(projectionManager, "Failed to get valid MediaProjectionManager");
@@ -109,7 +120,8 @@ public final class SensitiveContentProtectionManagerService extends SystemServic
mProjectionManager.addCallback(mProjectionCallback, new Handler(Looper.getMainLooper()));
try {
- mNotificationListener.registerAsSystemService(getContext(),
+ mNotificationListener.registerAsSystemService(
+ getContext(),
new ComponentName(getContext(), NotificationListener.class),
UserHandle.USER_ALL);
} catch (RemoteException e) {
@@ -174,8 +186,8 @@ public final class SensitiveContentProtectionManagerService extends SystemServic
}
// notify windowmanager of any currently posted sensitive content notifications
- ArraySet<PackageInfo> packageInfos = getSensitivePackagesFromNotifications(
- notifications, rankingMap);
+ ArraySet<PackageInfo> packageInfos =
+ getSensitivePackagesFromNotifications(notifications, rankingMap);
mWindowManager.addBlockScreenCaptureForApps(packageInfos);
}
@@ -197,8 +209,8 @@ public final class SensitiveContentProtectionManagerService extends SystemServic
return sensitivePackages;
}
- private PackageInfo getSensitivePackageFromNotification(StatusBarNotification sbn,
- RankingMap rankingMap) {
+ private PackageInfo getSensitivePackageFromNotification(
+ StatusBarNotification sbn, RankingMap rankingMap) {
if (sbn == null) {
Log.w(TAG, "Unable to protect null notification");
return null;
@@ -220,38 +232,55 @@ public final class SensitiveContentProtectionManagerService extends SystemServic
@Override
public void onListenerConnected() {
super.onListenerConnected();
- // Projection started before notification listener was connected
- synchronized (mSensitiveContentProtectionLock) {
- if (mProjectionActive) {
- updateAppsThatShouldBlockScreenCapture();
+ Trace.beginSection("SensitiveContentProtectionManagerService.onListenerConnected");
+ try {
+ // Projection started before notification listener was connected
+ synchronized (mSensitiveContentProtectionLock) {
+ if (mProjectionActive) {
+ updateAppsThatShouldBlockScreenCapture();
+ }
}
+ } finally {
+ Trace.endSection();
}
}
@Override
public void onNotificationPosted(StatusBarNotification sbn, RankingMap rankingMap) {
super.onNotificationPosted(sbn, rankingMap);
- synchronized (mSensitiveContentProtectionLock) {
- if (!mProjectionActive) {
- return;
- }
-
- // notify windowmanager of any currently posted sensitive content notifications
- PackageInfo packageInfo = getSensitivePackageFromNotification(sbn, rankingMap);
-
- if (packageInfo != null) {
- mWindowManager.addBlockScreenCaptureForApps(new ArraySet(Set.of(packageInfo)));
+ Trace.beginSection("SensitiveContentProtectionManagerService.onNotificationPosted");
+ try {
+ synchronized (mSensitiveContentProtectionLock) {
+ if (!mProjectionActive) {
+ return;
+ }
+
+ // notify windowmanager of any currently posted sensitive content notifications
+ PackageInfo packageInfo = getSensitivePackageFromNotification(sbn, rankingMap);
+
+ if (packageInfo != null) {
+ mWindowManager.addBlockScreenCaptureForApps(
+ new ArraySet(Set.of(packageInfo)));
+ }
}
+ } finally {
+ Trace.endSection();
}
}
@Override
public void onNotificationRankingUpdate(RankingMap rankingMap) {
super.onNotificationRankingUpdate(rankingMap);
- synchronized (mSensitiveContentProtectionLock) {
- if (mProjectionActive) {
- updateAppsThatShouldBlockScreenCapture(rankingMap);
+ Trace.beginSection(
+ "SensitiveContentProtectionManagerService.onNotificationRankingUpdate");
+ try {
+ synchronized (mSensitiveContentProtectionLock) {
+ if (mProjectionActive) {
+ updateAppsThatShouldBlockScreenCapture(rankingMap);
+ }
}
+ } finally {
+ Trace.endSection();
}
}
}
diff --git a/services/core/java/com/android/server/am/BatteryStatsService.java b/services/core/java/com/android/server/am/BatteryStatsService.java
index 3487ae3c6e6c..4f46ecdb9228 100644
--- a/services/core/java/com/android/server/am/BatteryStatsService.java
+++ b/services/core/java/com/android/server/am/BatteryStatsService.java
@@ -422,7 +422,9 @@ public final class BatteryStatsService extends IBatteryStats.Stub
mStats.setExternalStatsSyncLocked(mWorker);
mStats.setRadioScanningTimeoutLocked(mContext.getResources().getInteger(
com.android.internal.R.integer.config_radioScanningTimeout) * 1000L);
- mStats.startTrackingSystemServerCpuTime();
+ if (!Flags.disableSystemServicePowerAttr()) {
+ mStats.startTrackingSystemServerCpuTime();
+ }
mAggregatedPowerStatsConfig = createAggregatedPowerStatsConfig();
mPowerStatsStore = new PowerStatsStore(systemDir, mHandler, mAggregatedPowerStatsConfig);
diff --git a/services/core/java/com/android/server/content/SyncManager.java b/services/core/java/com/android/server/content/SyncManager.java
index df179a9b6d65..5b23364cf546 100644
--- a/services/core/java/com/android/server/content/SyncManager.java
+++ b/services/core/java/com/android/server/content/SyncManager.java
@@ -138,6 +138,7 @@ import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
+import java.util.NoSuchElementException;
import java.util.Objects;
import java.util.Random;
import java.util.Set;
@@ -3870,8 +3871,12 @@ public class SyncManager {
final SyncStorageEngine.EndPoint info = syncOperation.target;
if (activeSyncContext.mIsLinkedToDeath) {
- activeSyncContext.mSyncAdapter.asBinder().unlinkToDeath(activeSyncContext, 0);
- activeSyncContext.mIsLinkedToDeath = false;
+ try {
+ activeSyncContext.mSyncAdapter.asBinder().unlinkToDeath(activeSyncContext, 0);
+ activeSyncContext.mIsLinkedToDeath = false;
+ } catch (NoSuchElementException e) {
+ Slog.wtf(TAG, "Failed to unlink active sync adapter to death", e);
+ }
}
final long elapsedTime = SystemClock.elapsedRealtime() - activeSyncContext.mStartTime;
String historyMessage;
diff --git a/services/core/java/com/android/server/display/DisplayManagerService.java b/services/core/java/com/android/server/display/DisplayManagerService.java
index 245fcea06eac..93addcd84d12 100644
--- a/services/core/java/com/android/server/display/DisplayManagerService.java
+++ b/services/core/java/com/android/server/display/DisplayManagerService.java
@@ -1656,14 +1656,16 @@ public final class DisplayManagerService extends SystemService {
ContentRecordingSession session = null;
try {
if (projection != null) {
- IBinder launchCookie = projection.getLaunchCookie();
- if (launchCookie == null) {
+ IBinder taskWindowContainerToken = projection.getLaunchCookie() == null ? null
+ : projection.getLaunchCookie().binder;
+ if (taskWindowContainerToken == null) {
// Record a particular display.
session = ContentRecordingSession.createDisplaySession(
virtualDisplayConfig.getDisplayIdToMirror());
} else {
// Record a single task indicated by the launch cookie.
- session = ContentRecordingSession.createTaskSession(launchCookie);
+ session = ContentRecordingSession.createTaskSession(
+ taskWindowContainerToken);
}
}
} catch (RemoteException e) {
diff --git a/services/core/java/com/android/server/inputmethod/ClientController.java b/services/core/java/com/android/server/inputmethod/ClientController.java
index ece236a5f18c..86f4db959409 100644
--- a/services/core/java/com/android/server/inputmethod/ClientController.java
+++ b/services/core/java/com/android/server/inputmethod/ClientController.java
@@ -17,6 +17,7 @@
package com.android.server.inputmethod;
import android.annotation.NonNull;
+import android.annotation.Nullable;
import android.content.pm.PackageManagerInternal;
import android.os.IBinder;
import android.os.RemoteException;
@@ -29,6 +30,7 @@ import com.android.internal.inputmethod.IRemoteInputConnection;
import java.util.ArrayList;
import java.util.List;
+import java.util.function.Consumer;
/**
* Store and manage {@link InputMethodManagerService} clients. This class was designed to be a
@@ -62,7 +64,7 @@ final class ClientController {
// TODO(b/314150112): Make this field private when breaking the cycle with IMMS.
@GuardedBy("ImfLock.class")
- final ArrayMap<IBinder, ClientState> mClients = new ArrayMap<>();
+ private final ArrayMap<IBinder, ClientState> mClients = new ArrayMap<>();
@GuardedBy("ImfLock.class")
private final List<ClientControllerCallback> mCallbacks = new ArrayList<>();
@@ -145,6 +147,19 @@ final class ClientController {
}
@GuardedBy("ImfLock.class")
+ @Nullable
+ ClientState getClient(IBinder binder) {
+ return mClients.get(binder);
+ }
+
+ @GuardedBy("ImfLock.class")
+ void forAllClients(Consumer<ClientState> consumer) {
+ for (int i = 0; i < mClients.size(); i++) {
+ consumer.accept(mClients.valueAt(i));
+ }
+ }
+
+ @GuardedBy("ImfLock.class")
boolean verifyClientAndPackageMatch(
@NonNull IInputMethodClient client, @NonNull String packageName) {
final ClientState cs = mClients.get(client.asBinder());
diff --git a/services/core/java/com/android/server/inputmethod/InputMethodManagerService.java b/services/core/java/com/android/server/inputmethod/InputMethodManagerService.java
index 4767ebd0aab0..f031b7b677ac 100644
--- a/services/core/java/com/android/server/inputmethod/InputMethodManagerService.java
+++ b/services/core/java/com/android/server/inputmethod/InputMethodManagerService.java
@@ -205,6 +205,7 @@ import java.util.WeakHashMap;
import java.util.concurrent.CopyOnWriteArrayList;
import java.util.concurrent.Future;
import java.util.concurrent.atomic.AtomicInteger;
+import java.util.function.Consumer;
import java.util.function.IntConsumer;
/**
@@ -270,7 +271,6 @@ public final class InputMethodManagerService extends IInputMethodManager.Stub
@NonNull
private final String[] mNonPreemptibleInputMethods;
- // TODO(b/314150112): Move this to ClientController.
@UserIdInt
private int mLastSwitchUserId;
@@ -1819,10 +1819,8 @@ public final class InputMethodManagerService extends IInputMethodManager.Stub
}
mLastSwitchUserId = newUserId;
-
if (mIsInteractive && clientToBeReset != null) {
- final ClientState cs =
- mClientController.mClients.get(clientToBeReset.asBinder());
+ final ClientState cs = mClientController.getClient(clientToBeReset.asBinder());
if (cs == null) {
// The client is already gone.
return;
@@ -2165,26 +2163,25 @@ public final class InputMethodManagerService extends IInputMethodManager.Stub
/**
* Hide the IME if the removed user is the current user.
*/
+ @GuardedBy("ImfLock.class")
private void onClientRemoved(ClientState client) {
- synchronized (ImfLock.class) {
- clearClientSessionLocked(client);
- clearClientSessionForAccessibilityLocked(client);
- if (mCurClient == client) {
- hideCurrentInputLocked(mCurFocusedWindow, null /* statsToken */, 0 /* flags */,
- null /* resultReceiver */, SoftInputShowHideReason.HIDE_REMOVE_CLIENT);
- if (mBoundToMethod) {
- mBoundToMethod = false;
- IInputMethodInvoker curMethod = getCurMethodLocked();
- if (curMethod != null) {
- // When we unbind input, we are unbinding the client, so we always
- // unbind ime and a11y together.
- curMethod.unbindInput();
- AccessibilityManagerInternal.get().unbindInput();
- }
+ clearClientSessionLocked(client);
+ clearClientSessionForAccessibilityLocked(client);
+ if (mCurClient == client) {
+ hideCurrentInputLocked(mCurFocusedWindow, null /* statsToken */, 0 /* flags */,
+ null /* resultReceiver */, SoftInputShowHideReason.HIDE_REMOVE_CLIENT);
+ if (mBoundToMethod) {
+ mBoundToMethod = false;
+ IInputMethodInvoker curMethod = getCurMethodLocked();
+ if (curMethod != null) {
+ // When we unbind input, we are unbinding the client, so we always
+ // unbind ime and a11y together.
+ curMethod.unbindInput();
+ AccessibilityManagerInternal.get().unbindInput();
}
- mBoundToAccessibility = false;
- mCurClient = null;
}
+ mBoundToAccessibility = false;
+ mCurClient = null;
if (mCurFocusedWindowClient == client) {
mCurFocusedWindowClient = null;
mCurFocusedWindowEditorInfo = null;
@@ -2192,7 +2189,6 @@ public final class InputMethodManagerService extends IInputMethodManager.Stub
}
}
- // TODO(b/314150112): Move this to ClientController.
@GuardedBy("ImfLock.class")
void unbindCurrentClientLocked(@UnbindReason int unbindClientReason) {
if (mCurClient != null) {
@@ -2883,11 +2879,16 @@ public final class InputMethodManagerService extends IInputMethodManager.Stub
@GuardedBy("ImfLock.class")
void clearClientSessionsLocked() {
if (getCurMethodLocked() != null) {
- final int numClients = mClientController.mClients.size();
- for (int i = 0; i < numClients; ++i) {
- clearClientSessionLocked(mClientController.mClients.valueAt(i));
- clearClientSessionForAccessibilityLocked(mClientController.mClients.valueAt(i));
- }
+ // TODO(b/322816970): Replace this with lambda.
+ mClientController.forAllClients(new Consumer<ClientState>() {
+
+ @GuardedBy("ImfLock.class")
+ @Override
+ public void accept(ClientState c) {
+ clearClientSessionLocked(c);
+ clearClientSessionForAccessibilityLocked(c);
+ }
+ });
finishSessionLocked(mEnabledSession);
for (int i = 0; i < mEnabledAccessibilitySessions.size(); i++) {
@@ -3732,9 +3733,9 @@ public final class InputMethodManagerService extends IInputMethodManager.Stub
return InputBindResult.INVALID_USER;
}
- final ClientState cs = mClientController.mClients.get(client.asBinder());
+ final ClientState cs = mClientController.getClient(client.asBinder());
if (cs == null) {
- throw new IllegalArgumentException("unknown client " + client.asBinder());
+ throw new IllegalArgumentException("Unknown client " + client.asBinder());
}
final int imeClientFocus = mWindowManagerInternal.hasInputMethodClientFocus(
@@ -3906,8 +3907,7 @@ public final class InputMethodManagerService extends IInputMethodManager.Stub
// We need to check if this is the current client with
// focus in the window manager, to allow this call to
// be made before input is started in it.
- final ClientState cs =
- mClientController.mClients.get(client.asBinder());
+ final ClientState cs = mClientController.getClient(client.asBinder());
if (cs == null) {
ImeTracker.forLogging().onFailed(statsToken, ImeTracker.PHASE_SERVER_CLIENT_KNOWN);
throw new IllegalArgumentException("unknown client " + client.asBinder());
@@ -4518,16 +4518,17 @@ public final class InputMethodManagerService extends IInputMethodManager.Stub
@Override
public void startImeTrace() {
super.startImeTrace_enforcePermission();
-
ImeTracing.getInstance().startTrace(null /* printwriter */);
- ArrayMap<IBinder, ClientState> clients;
synchronized (ImfLock.class) {
- clients = new ArrayMap<>(mClientController.mClients);
- }
- for (ClientState state : clients.values()) {
- if (state != null) {
- state.mClient.setImeTraceEnabled(true /* enabled */);
- }
+ // TODO(b/322816970): Replace this with lambda.
+ mClientController.forAllClients(new Consumer<ClientState>() {
+
+ @GuardedBy("ImfLock.class")
+ @Override
+ public void accept(ClientState c) {
+ c.mClient.setImeTraceEnabled(true /* enabled */);
+ }
+ });
}
}
@@ -4538,14 +4539,16 @@ public final class InputMethodManagerService extends IInputMethodManager.Stub
super.stopImeTrace_enforcePermission();
ImeTracing.getInstance().stopTrace(null /* printwriter */);
- ArrayMap<IBinder, ClientState> clients;
synchronized (ImfLock.class) {
- clients = new ArrayMap<>(mClientController.mClients);
- }
- for (ClientState state : clients.values()) {
- if (state != null) {
- state.mClient.setImeTraceEnabled(false /* enabled */);
- }
+ // TODO(b/322816970): Replace this with lambda.
+ mClientController.forAllClients(new Consumer<ClientState>() {
+
+ @GuardedBy("ImfLock.class")
+ @Override
+ public void accept(ClientState c) {
+ c.mClient.setImeTraceEnabled(false /* enabled */);
+ }
+ });
}
}
@@ -5779,11 +5782,15 @@ public final class InputMethodManagerService extends IInputMethodManager.Stub
// We only have sessions when we bound to an input method. Remove this session
// from all clients.
if (getCurMethodLocked() != null) {
- final int numClients = mClientController.mClients.size();
- for (int i = 0; i < numClients; ++i) {
- clearClientSessionForAccessibilityLocked(
- mClientController.mClients.valueAt(i), accessibilityConnectionId);
- }
+ // TODO(b/322816970): Replace this with lambda.
+ mClientController.forAllClients(new Consumer<ClientState>() {
+
+ @GuardedBy("ImfLock.class")
+ @Override
+ public void accept(ClientState c) {
+ clearClientSessionForAccessibilityLocked(c, accessibilityConnectionId);
+ }
+ });
AccessibilitySessionState session = mEnabledAccessibilitySessions.get(
accessibilityConnectionId);
if (session != null) {
@@ -5967,19 +5974,26 @@ public final class InputMethodManagerService extends IInputMethodManager.Stub
p.println(" InputMethod #" + i + ":");
info.dump(p, " ");
}
+ // Dump ClientController#mClients
p.println(" ClientStates:");
- // TODO(b/314150112): move client related dump info to ClientController#dump
- final int numClients = mClientController.mClients.size();
- for (int i = 0; i < numClients; ++i) {
- final ClientState ci = mClientController.mClients.valueAt(i);
- p.println(" " + ci + ":");
- p.println(" client=" + ci.mClient);
- p.println(" fallbackInputConnection=" + ci.mFallbackInputConnection);
- p.println(" sessionRequested=" + ci.mSessionRequested);
- p.println(" sessionRequestedForAccessibility="
- + ci.mSessionRequestedForAccessibility);
- p.println(" curSession=" + ci.mCurSession);
- }
+ // TODO(b/322816970): Replace this with lambda.
+ mClientController.forAllClients(new Consumer<ClientState>() {
+
+ @GuardedBy("ImfLock.class")
+ @Override
+ public void accept(ClientState c) {
+ p.println(" " + c + ":");
+ p.println(" client=" + c.mClient);
+ p.println(" fallbackInputConnection="
+ + c.mFallbackInputConnection);
+ p.println(" sessionRequested="
+ + c.mSessionRequested);
+ p.println(
+ " sessionRequestedForAccessibility="
+ + c.mSessionRequestedForAccessibility);
+ p.println(" curSession=" + c.mCurSession);
+ }
+ });
p.println(" mCurMethodId=" + getSelectedMethodIdLocked());
client = mCurClient;
p.println(" mCurClient=" + client + " mCurSeq=" + getSequenceNumberLocked());
@@ -6583,14 +6597,16 @@ public final class InputMethodManagerService extends IInputMethodManager.Stub
}
}
boolean isImeTraceEnabled = ImeTracing.getInstance().isEnabled();
- ArrayMap<IBinder, ClientState> clients;
synchronized (ImfLock.class) {
- clients = new ArrayMap<>(mClientController.mClients);
- }
- for (ClientState state : clients.values()) {
- if (state != null) {
- state.mClient.setImeTraceEnabled(isImeTraceEnabled);
- }
+ // TODO(b/322816970): Replace this with lambda.
+ mClientController.forAllClients(new Consumer<ClientState>() {
+
+ @GuardedBy("ImfLock.class")
+ @Override
+ public void accept(ClientState c) {
+ c.mClient.setImeTraceEnabled(isImeTraceEnabled);
+ }
+ });
}
return ShellCommandResult.SUCCESS;
}
diff --git a/services/core/java/com/android/server/media/MediaSessionService.java b/services/core/java/com/android/server/media/MediaSessionService.java
index 1d516e2931d7..7fabdf293b39 100644
--- a/services/core/java/com/android/server/media/MediaSessionService.java
+++ b/services/core/java/com/android/server/media/MediaSessionService.java
@@ -34,6 +34,8 @@ import android.app.ForegroundServiceDelegationOptions;
import android.app.KeyguardManager;
import android.app.NotificationManager;
import android.app.PendingIntent;
+import android.app.usage.UsageStatsManager;
+import android.app.usage.UsageStatsManagerInternal;
import android.content.ActivityNotFoundException;
import android.content.BroadcastReceiver;
import android.content.ComponentName;
@@ -68,6 +70,7 @@ import android.os.Handler;
import android.os.HandlerThread;
import android.os.IBinder;
import android.os.Message;
+import android.os.PersistableBundle;
import android.os.PowerExemptionManager;
import android.os.PowerManager;
import android.os.Process;
@@ -100,7 +103,9 @@ import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationTargetException;
import java.util.ArrayList;
import java.util.HashMap;
+import java.util.HashSet;
import java.util.List;
+import java.util.Set;
/**
* System implementation of MediaSessionManager
@@ -145,6 +150,8 @@ public class MediaSessionService extends SystemService implements Monitor {
private AudioManager mAudioManager;
private boolean mHasFeatureLeanback;
private ActivityManagerInternal mActivityManagerInternal;
+ private UsageStatsManagerInternal mUsageStatsManagerInternal;
+ private final Set<Integer> mUserEngagingSessions = new HashSet<>();
// The FullUserRecord of the current users. (i.e. The foreground user that isn't a profile)
// It's always not null after the MediaSessionService is started.
@@ -230,6 +237,7 @@ public class MediaSessionService extends SystemService implements Monitor {
mContext.registerReceiver(mNotificationListenerEnabledChangedReceiver, filter);
mActivityManagerInternal = LocalServices.getService(ActivityManagerInternal.class);
+ mUsageStatsManagerInternal = LocalServices.getService(UsageStatsManagerInternal.class);
}
@Override
@@ -582,12 +590,43 @@ public class MediaSessionService extends SystemService implements Monitor {
if (allowRunningInForeground) {
mActivityManagerInternal.startForegroundServiceDelegate(
foregroundServiceDelegationOptions, /* connection= */ null);
+ reportMediaInteractionEvent(record, /* userEngaged= */ true);
} else {
mActivityManagerInternal.stopForegroundServiceDelegate(
foregroundServiceDelegationOptions);
+ reportMediaInteractionEvent(record, /* userEngaged= */ false);
}
}
+ private void reportMediaInteractionEvent(MediaSessionRecordImpl record, boolean userEngaged) {
+ if (!android.app.usage.Flags.userInteractionTypeApi()) {
+ return;
+ }
+
+ String packageName = record.getPackageName();
+ int sessionUid = record.getUid();
+ String actionToLog = null;
+ if (userEngaged) {
+ if (!mUserEngagingSessions.contains(sessionUid)) {
+ actionToLog = "start";
+ }
+ mUserEngagingSessions.add(sessionUid);
+ } else {
+ if (mUserEngagingSessions.contains(sessionUid)) {
+ actionToLog = "stop";
+ }
+ mUserEngagingSessions.remove(sessionUid);
+ }
+
+ if (actionToLog != null) {
+ PersistableBundle extras = new PersistableBundle();
+ extras.putString(UsageStatsManager.EXTRA_EVENT_CATEGORY, "android.media");
+ extras.putString(UsageStatsManager.EXTRA_EVENT_ACTION, actionToLog);
+ mUsageStatsManagerInternal.reportUserInteractionEvent(
+ packageName, record.getUserId(), extras);
+ }
+ }
+
void tempAllowlistTargetPkgIfPossible(int targetUid, String targetPackage,
int callingPid, int callingUid, String callingPackage, String reason) {
final long token = Binder.clearCallingIdentity();
diff --git a/services/core/java/com/android/server/media/projection/MediaProjectionManagerService.java b/services/core/java/com/android/server/media/projection/MediaProjectionManagerService.java
index 978f46808e3b..bbb19e351b5d 100644
--- a/services/core/java/com/android/server/media/projection/MediaProjectionManagerService.java
+++ b/services/core/java/com/android/server/media/projection/MediaProjectionManagerService.java
@@ -35,6 +35,7 @@ import android.annotation.EnforcePermission;
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.app.ActivityManagerInternal;
+import android.app.ActivityOptions.LaunchCookie;
import android.app.AppOpsManager;
import android.app.IProcessObserver;
import android.app.compat.CompatChanges;
@@ -548,8 +549,11 @@ public final class MediaProjectionManagerService extends SystemService
DEFAULT_DISPLAY));
break;
case RECORD_CONTENT_TASK:
- setReviewedConsentSessionLocked(ContentRecordingSession.createTaskSession(
- mProjectionGrant.getLaunchCookie()));
+ IBinder taskWindowContainerToken =
+ mProjectionGrant.getLaunchCookie() == null ? null
+ : mProjectionGrant.getLaunchCookie().binder;
+ setReviewedConsentSessionLocked(
+ ContentRecordingSession.createTaskSession(taskWindowContainerToken));
break;
}
}
@@ -973,7 +977,7 @@ public final class MediaProjectionManagerService extends SystemService
private IBinder mToken;
private IBinder.DeathRecipient mDeathEater;
private boolean mRestoreSystemAlertWindow;
- private IBinder mLaunchCookie = null;
+ private LaunchCookie mLaunchCookie = null;
// Values for tracking token validity.
// Timeout value to compare creation time against.
@@ -1186,14 +1190,14 @@ public final class MediaProjectionManagerService extends SystemService
@android.annotation.EnforcePermission(android.Manifest.permission.MANAGE_MEDIA_PROJECTION)
@Override // Binder call
- public void setLaunchCookie(IBinder launchCookie) {
+ public void setLaunchCookie(LaunchCookie launchCookie) {
setLaunchCookie_enforcePermission();
mLaunchCookie = launchCookie;
}
@android.annotation.EnforcePermission(android.Manifest.permission.MANAGE_MEDIA_PROJECTION)
@Override // Binder call
- public IBinder getLaunchCookie() {
+ public LaunchCookie getLaunchCookie() {
getLaunchCookie_enforcePermission();
return mLaunchCookie;
}
diff --git a/services/core/java/com/android/server/pm/PackageManagerService.java b/services/core/java/com/android/server/pm/PackageManagerService.java
index 135bd4f911f9..9617098d1016 100644
--- a/services/core/java/com/android/server/pm/PackageManagerService.java
+++ b/services/core/java/com/android/server/pm/PackageManagerService.java
@@ -7807,7 +7807,8 @@ public class PackageManagerService implements PackageSender, TestUtilityService
mResolveActivity.launchMode = ActivityInfo.LAUNCH_MULTIPLE;
mResolveActivity.flags = ActivityInfo.FLAG_EXCLUDE_FROM_RECENTS
| ActivityInfo.FLAG_FINISH_ON_CLOSE_SYSTEM_DIALOGS
- | ActivityInfo.FLAG_CAN_DISPLAY_ON_REMOTE_DEVICES;
+ | ActivityInfo.FLAG_CAN_DISPLAY_ON_REMOTE_DEVICES
+ | ActivityInfo.FLAG_HARDWARE_ACCELERATED;
mResolveActivity.theme = 0;
mResolveActivity.exported = true;
mResolveActivity.enabled = true;
@@ -7841,7 +7842,8 @@ public class PackageManagerService implements PackageSender, TestUtilityService
mResolveActivity.documentLaunchMode = ActivityInfo.DOCUMENT_LAUNCH_NEVER;
mResolveActivity.flags = ActivityInfo.FLAG_EXCLUDE_FROM_RECENTS
| ActivityInfo.FLAG_RELINQUISH_TASK_IDENTITY
- | ActivityInfo.FLAG_CAN_DISPLAY_ON_REMOTE_DEVICES;
+ | ActivityInfo.FLAG_CAN_DISPLAY_ON_REMOTE_DEVICES
+ | ActivityInfo.FLAG_HARDWARE_ACCELERATED;
mResolveActivity.theme = R.style.Theme_Material_Dialog_Alert;
mResolveActivity.exported = true;
mResolveActivity.enabled = true;
diff --git a/services/core/java/com/android/server/power/stats/BatteryStatsImpl.java b/services/core/java/com/android/server/power/stats/BatteryStatsImpl.java
index 09b19e6196a1..25e749f08782 100644
--- a/services/core/java/com/android/server/power/stats/BatteryStatsImpl.java
+++ b/services/core/java/com/android/server/power/stats/BatteryStatsImpl.java
@@ -138,6 +138,7 @@ import com.android.internal.util.XmlUtils;
import com.android.modules.utils.TypedXmlPullParser;
import com.android.modules.utils.TypedXmlSerializer;
import com.android.net.module.util.NetworkCapabilitiesUtils;
+import com.android.server.power.optimization.Flags;
import com.android.server.power.stats.SystemServerCpuThreadReader.SystemServiceCpuThreadTimes;
import libcore.util.EmptyArray;
@@ -185,7 +186,8 @@ public class BatteryStatsImpl extends BatteryStats {
// TODO: remove "tcp" from network methods, since we measure total stats.
// Current on-disk Parcel version. Must be updated when the format of the parcelable changes
- public static final int VERSION = 214;
+ public static final int VERSION =
+ !Flags.disableSystemServicePowerAttr() ? 214 : 215;
// The maximum number of names wakelocks we will keep track of
// per uid; once the limit is reached, we batch the remaining wakelocks
@@ -1753,7 +1755,9 @@ public class BatteryStatsImpl extends BatteryStats {
mCpuUidActiveTimeReader = new KernelCpuUidActiveTimeReader(true, mClock);
mCpuUidClusterTimeReader = new KernelCpuUidClusterTimeReader(true, mClock);
mKernelWakelockReader = new KernelWakelockReader();
- mSystemServerCpuThreadReader = SystemServerCpuThreadReader.create();
+ if (!Flags.disableSystemServicePowerAttr()) {
+ mSystemServerCpuThreadReader = SystemServerCpuThreadReader.create();
+ }
mKernelMemoryBandwidthStats = new KernelMemoryBandwidthStats();
mTmpRailStats = new RailStats();
}
@@ -11459,7 +11463,7 @@ public class BatteryStatsImpl extends BatteryStats {
@Override
public BatteryStatsHistoryIterator iterateBatteryStatsHistory(long startTimeMs,
long endTimeMs) {
- return mHistory.copy().iterate(startTimeMs, endTimeMs);
+ return mHistory.iterate(startTimeMs, endTimeMs);
}
@Override
@@ -11702,7 +11706,9 @@ public class BatteryStatsImpl extends BatteryStats {
EnergyConsumerStats.resetIfNotNull(mGlobalEnergyConsumerStats);
- resetIfNotNull(mBinderThreadCpuTimesUs, false, elapsedRealtimeUs);
+ if (!Flags.disableSystemServicePowerAttr()) {
+ resetIfNotNull(mBinderThreadCpuTimesUs, false, elapsedRealtimeUs);
+ }
mNumAllUidCpuTimeReads = 0;
mNumUidsRemoved = 0;
@@ -13676,7 +13682,9 @@ public class BatteryStatsImpl extends BatteryStats {
mKernelCpuSpeedReaders[i].readDelta();
}
}
- mSystemServerCpuThreadReader.readDelta();
+ if (!Flags.disableSystemServicePowerAttr()) {
+ mSystemServerCpuThreadReader.readDelta();
+ }
return;
}
@@ -15696,23 +15704,25 @@ public class BatteryStatsImpl extends BatteryStats {
}
}
- updateSystemServiceCallStats();
- if (mBinderThreadCpuTimesUs != null) {
- pw.println("Per UID System server binder time in ms:");
- long[] systemServiceTimeAtCpuSpeeds = getSystemServiceTimeAtCpuSpeeds();
- for (int i = 0; i < size; i++) {
- int u = mUidStats.keyAt(i);
- Uid uid = mUidStats.get(u);
- double proportionalSystemServiceUsage = uid.getProportionalSystemServiceUsage();
- long timeUs = 0;
- for (int j = systemServiceTimeAtCpuSpeeds.length - 1; j >= 0; j--) {
- timeUs += systemServiceTimeAtCpuSpeeds[j] * proportionalSystemServiceUsage;
- }
+ if (!Flags.disableSystemServicePowerAttr()) {
+ updateSystemServiceCallStats();
+ if (mBinderThreadCpuTimesUs != null) {
+ pw.println("Per UID System server binder time in ms:");
+ long[] systemServiceTimeAtCpuSpeeds = getSystemServiceTimeAtCpuSpeeds();
+ for (int i = 0; i < size; i++) {
+ int u = mUidStats.keyAt(i);
+ Uid uid = mUidStats.get(u);
+ double proportionalSystemServiceUsage = uid.getProportionalSystemServiceUsage();
+ long timeUs = 0;
+ for (int j = systemServiceTimeAtCpuSpeeds.length - 1; j >= 0; j--) {
+ timeUs += systemServiceTimeAtCpuSpeeds[j] * proportionalSystemServiceUsage;
+ }
- pw.print(" ");
- pw.print(u);
- pw.print(": ");
- pw.println(timeUs / 1000);
+ pw.print(" ");
+ pw.print(u);
+ pw.print(": ");
+ pw.println(timeUs / 1000);
+ }
}
}
}
@@ -16428,8 +16438,10 @@ public class BatteryStatsImpl extends BatteryStats {
}
}
- mBinderThreadCpuTimesUs =
- LongSamplingCounterArray.readSummaryFromParcelLocked(in, mOnBatteryTimeBase);
+ if (!Flags.disableSystemServicePowerAttr()) {
+ mBinderThreadCpuTimesUs =
+ LongSamplingCounterArray.readSummaryFromParcelLocked(in, mOnBatteryTimeBase);
+ }
}
/**
@@ -16973,7 +16985,9 @@ public class BatteryStatsImpl extends BatteryStats {
}
}
- LongSamplingCounterArray.writeSummaryToParcelLocked(out, mBinderThreadCpuTimesUs);
+ if (!Flags.disableSystemServicePowerAttr()) {
+ LongSamplingCounterArray.writeSummaryToParcelLocked(out, mBinderThreadCpuTimesUs);
+ }
}
@GuardedBy("this")
@@ -16985,7 +16999,9 @@ public class BatteryStatsImpl extends BatteryStats {
// if we had originally pulled a time before the RTC was set.
getStartClockTime();
- updateSystemServiceCallStats();
+ if (!Flags.disableSystemServicePowerAttr()) {
+ updateSystemServiceCallStats();
+ }
}
@GuardedBy("this")
diff --git a/services/core/java/com/android/server/power/stats/BatteryUsageStatsProvider.java b/services/core/java/com/android/server/power/stats/BatteryUsageStatsProvider.java
index c3221e4929bd..30b80ae781ff 100644
--- a/services/core/java/com/android/server/power/stats/BatteryUsageStatsProvider.java
+++ b/services/core/java/com/android/server/power/stats/BatteryUsageStatsProvider.java
@@ -96,11 +96,13 @@ public class BatteryUsageStatsProvider {
mPowerCalculators.add(new CustomEnergyConsumerPowerCalculator(mPowerProfile));
mPowerCalculators.add(new UserPowerCalculator());
- // It is important that SystemServicePowerCalculator be applied last,
- // because it re-attributes some of the power estimated by the other
- // calculators.
- mPowerCalculators.add(
- new SystemServicePowerCalculator(mCpuScalingPolicies, mPowerProfile));
+ if (!com.android.server.power.optimization.Flags.disableSystemServicePowerAttr()) {
+ // It is important that SystemServicePowerCalculator be applied last,
+ // because it re-attributes some of the power estimated by the other
+ // calculators.
+ mPowerCalculators.add(
+ new SystemServicePowerCalculator(mCpuScalingPolicies, mPowerProfile));
+ }
}
}
return mPowerCalculators;
diff --git a/services/core/java/com/android/server/power/stats/PowerStatsAggregator.java b/services/core/java/com/android/server/power/stats/PowerStatsAggregator.java
index cd3db36662d6..ba4c127ac3d0 100644
--- a/services/core/java/com/android/server/power/stats/PowerStatsAggregator.java
+++ b/services/core/java/com/android/server/power/stats/PowerStatsAggregator.java
@@ -74,8 +74,7 @@ public class PowerStatsAggregator {
boolean clockUpdateAdded = false;
long baseTime = startTimeMs > 0 ? startTimeMs : UNINITIALIZED;
long lastTime = 0;
- try (BatteryStatsHistoryIterator iterator =
- mHistory.copy().iterate(startTimeMs, endTimeMs)) {
+ try (BatteryStatsHistoryIterator iterator = mHistory.iterate(startTimeMs, endTimeMs)) {
while (iterator.hasNext()) {
BatteryStats.HistoryItem item = iterator.next();
diff --git a/services/core/java/com/android/server/power/stats/flags.aconfig b/services/core/java/com/android/server/power/stats/flags.aconfig
index 0f135715ebc3..65466461c82e 100644
--- a/services/core/java/com/android/server/power/stats/flags.aconfig
+++ b/services/core/java/com/android/server/power/stats/flags.aconfig
@@ -13,3 +13,11 @@ flag {
description: "Feature flag for streamlined battery stats"
bug: "285646152"
}
+
+flag {
+ name: "disable_system_service_power_attr"
+ namespace: "backstage_power"
+ description: "Deprecation of system service power re-attribution"
+ bug: "311793616"
+ is_fixed_read_only: true
+}
diff --git a/services/core/java/com/android/server/stats/pull/StatsPullAtomService.java b/services/core/java/com/android/server/stats/pull/StatsPullAtomService.java
index 285bcc328c0c..0ffd002197c4 100644
--- a/services/core/java/com/android/server/stats/pull/StatsPullAtomService.java
+++ b/services/core/java/com/android/server/stats/pull/StatsPullAtomService.java
@@ -2058,7 +2058,8 @@ public class StatsPullAtomService extends SystemService {
}
private void registerCpuCyclesPerThreadGroupCluster() {
- if (KernelCpuBpfTracking.isSupported()) {
+ if (KernelCpuBpfTracking.isSupported()
+ && !com.android.server.power.optimization.Flags.disableSystemServicePowerAttr()) {
int tagId = FrameworkStatsLog.CPU_CYCLES_PER_THREAD_GROUP_CLUSTER;
PullAtomMetadata metadata = new PullAtomMetadata.Builder()
.setAdditiveFields(new int[]{3, 4})
@@ -2073,6 +2074,10 @@ public class StatsPullAtomService extends SystemService {
}
int pullCpuCyclesPerThreadGroupCluster(int atomTag, List<StatsEvent> pulledData) {
+ if (com.android.server.power.optimization.Flags.disableSystemServicePowerAttr()) {
+ return StatsManager.PULL_SKIP;
+ }
+
SystemServiceCpuThreadTimes times = LocalServices.getService(BatteryStatsInternal.class)
.getSystemServiceCpuThreadTimes();
if (times == null) {
diff --git a/services/core/java/com/android/server/tv/interactive/TvInteractiveAppManagerService.java b/services/core/java/com/android/server/tv/interactive/TvInteractiveAppManagerService.java
index b6d0ca19d484..eacd3f8d4d86 100644
--- a/services/core/java/com/android/server/tv/interactive/TvInteractiveAppManagerService.java
+++ b/services/core/java/com/android/server/tv/interactive/TvInteractiveAppManagerService.java
@@ -4152,6 +4152,25 @@ public class TvInteractiveAppManagerService extends SystemService {
}
@Override
+ public void onRequestSigning2(String id, String algorithm, String host,
+ int port, byte[] data) {
+ synchronized (mLock) {
+ if (DEBUG) {
+ Slogf.d(TAG, "onRequestSigning");
+ }
+ if (mSessionState.mSession == null || mSessionState.mClient == null) {
+ return;
+ }
+ try {
+ mSessionState.mClient.onRequestSigning2(
+ id, algorithm, host, port, data, mSessionState.mSeq);
+ } catch (RemoteException e) {
+ Slogf.e(TAG, "error in onRequestSigning", e);
+ }
+ }
+ }
+
+ @Override
public void onRequestCertificate(String host, int port) {
synchronized (mLock) {
if (DEBUG) {
diff --git a/services/core/java/com/android/server/wm/ScreenRecordingCallbackController.java b/services/core/java/com/android/server/wm/ScreenRecordingCallbackController.java
index 5f488b769885..bdb45884887c 100644
--- a/services/core/java/com/android/server/wm/ScreenRecordingCallbackController.java
+++ b/services/core/java/com/android/server/wm/ScreenRecordingCallbackController.java
@@ -97,7 +97,7 @@ public class ScreenRecordingCallbackController {
mRecordedWC = (WindowContainer) mWms.mRoot.getDefaultDisplay();
} else {
mRecordedWC = mWms.mRoot.getActivity(activity -> activity.mLaunchCookie
- == mediaProjectionInfo.getLaunchCookie()).getTask();
+ == mediaProjectionInfo.getLaunchCookie().binder).getTask();
}
}
diff --git a/services/core/jni/com_android_server_am_CachedAppOptimizer.cpp b/services/core/jni/com_android_server_am_CachedAppOptimizer.cpp
index 7b084132ed1c..4403bce484ad 100644
--- a/services/core/jni/com_android_server_am_CachedAppOptimizer.cpp
+++ b/services/core/jni/com_android_server_am_CachedAppOptimizer.cpp
@@ -571,8 +571,8 @@ static jstring com_android_server_am_CachedAppOptimizer_getFreezerCheckPath(JNIE
}
static jboolean com_android_server_am_CachedAppOptimizer_isFreezerProfileValid(JNIEnv* env) {
- int uid = getuid();
- int pid = getpid();
+ uid_t uid = getuid();
+ pid_t pid = getpid();
return isProfileValidForProcess("Frozen", uid, pid) &&
isProfileValidForProcess("Unfrozen", uid, pid);
diff --git a/services/credentials/java/com/android/server/credentials/CredentialManagerService.java b/services/credentials/java/com/android/server/credentials/CredentialManagerService.java
index 667e086c8b40..281fb1c4635b 100644
--- a/services/credentials/java/com/android/server/credentials/CredentialManagerService.java
+++ b/services/credentials/java/com/android/server/credentials/CredentialManagerService.java
@@ -27,6 +27,7 @@ import android.annotation.Nullable;
import android.annotation.UserIdInt;
import android.app.ActivityManager;
import android.content.ComponentName;
+import android.content.ContentResolver;
import android.content.Context;
import android.content.pm.PackageInfo;
import android.content.pm.PackageManager;
@@ -201,7 +202,7 @@ public final class CredentialManagerService
@SuppressWarnings("GuardedBy") // ErrorProne requires service.mLock which is the same
// this.mLock
protected void handlePackageRemovedMultiModeLocked(String packageName, int userId) {
- updateProvidersWhenPackageRemoved(mContext, packageName);
+ updateProvidersWhenPackageRemoved(new SettingsWrapper(mContext), packageName);
List<CredentialManagerServiceImpl> services = peekServiceListForUserLocked(userId);
if (services == null) {
@@ -1134,13 +1135,14 @@ public final class CredentialManagerService
}
/** Updates the list of providers when an app is uninstalled. */
- public static void updateProvidersWhenPackageRemoved(Context context, String packageName) {
+ public static void updateProvidersWhenPackageRemoved(
+ SettingsWrapper settingsWrapper, String packageName) {
+ Slog.i(TAG, "updateProvidersWhenPackageRemoved");
+
// Get the current providers.
String rawProviders =
- Settings.Secure.getStringForUser(
- context.getContentResolver(),
- Settings.Secure.CREDENTIAL_SERVICE_PRIMARY,
- UserHandle.myUserId());
+ settingsWrapper.getStringForUser(
+ Settings.Secure.CREDENTIAL_SERVICE_PRIMARY, UserHandle.myUserId());
if (rawProviders == null) {
Slog.w(TAG, "settings key is null");
return;
@@ -1148,44 +1150,44 @@ public final class CredentialManagerService
// Remove any providers from the primary setting that contain the package name
// being removed.
- Set<String> primaryProviders =
- getStoredProviders(rawProviders, packageName);
- if (!Settings.Secure.putString(
- context.getContentResolver(),
+ Set<String> primaryProviders = getStoredProviders(rawProviders, packageName);
+ if (!settingsWrapper.putStringForUser(
Settings.Secure.CREDENTIAL_SERVICE_PRIMARY,
- String.join(":", primaryProviders))) {
- Slog.w(TAG, "Failed to remove primary package: " + packageName);
+ String.join(":", primaryProviders),
+ UserHandle.myUserId(),
+ /* overrideableByRestore= */ true)) {
+ Slog.e(TAG, "Failed to remove primary package: " + packageName);
return;
}
// Read the autofill provider so we don't accidentally erase it.
String autofillProvider =
- Settings.Secure.getStringForUser(
- context.getContentResolver(),
- Settings.Secure.AUTOFILL_SERVICE,
- UserHandle.myUserId());
+ settingsWrapper.getStringForUser(
+ Settings.Secure.AUTOFILL_SERVICE, UserHandle.myUserId());
// If there is an autofill provider and it is the placeholder indicating
// that the currently selected primary provider does not support autofill
// then we should wipe the setting to keep it in sync.
if (autofillProvider != null && primaryProviders.isEmpty()) {
if (autofillProvider.equals(AUTOFILL_PLACEHOLDER_VALUE)) {
- if (!Settings.Secure.putString(
- context.getContentResolver(),
+ if (!settingsWrapper.putStringForUser(
Settings.Secure.AUTOFILL_SERVICE,
- "")) {
- Slog.w(TAG, "Failed to remove autofill package: " + packageName);
+ "",
+ UserHandle.myUserId(),
+ /* overrideableByRestore= */ true)) {
+ Slog.e(TAG, "Failed to remove autofill package: " + packageName);
}
} else {
// If the existing autofill provider is from the app being removed
// then erase the autofill service setting.
ComponentName cn = ComponentName.unflattenFromString(autofillProvider);
if (cn != null && cn.getPackageName().equals(packageName)) {
- if (!Settings.Secure.putString(
- context.getContentResolver(),
+ if (!settingsWrapper.putStringForUser(
Settings.Secure.AUTOFILL_SERVICE,
- "")) {
- Slog.w(TAG, "Failed to remove autofill package: " + packageName);
+ "",
+ UserHandle.myUserId(),
+ /* overrideableByRestore= */ true)) {
+ Slog.e(TAG, "Failed to remove autofill package: " + packageName);
}
}
}
@@ -1193,19 +1195,17 @@ public final class CredentialManagerService
// Read the credential providers to remove any reference of the removed app.
String rawCredentialProviders =
- Settings.Secure.getStringForUser(
- context.getContentResolver(),
- Settings.Secure.CREDENTIAL_SERVICE,
- UserHandle.myUserId());
+ settingsWrapper.getStringForUser(
+ Settings.Secure.CREDENTIAL_SERVICE, UserHandle.myUserId());
// Remove any providers that belong to the removed app.
- Set<String> credentialProviders =
- getStoredProviders(rawCredentialProviders, packageName);
- if (!Settings.Secure.putString(
- context.getContentResolver(),
+ Set<String> credentialProviders = getStoredProviders(rawCredentialProviders, packageName);
+ if (!settingsWrapper.putStringForUser(
Settings.Secure.CREDENTIAL_SERVICE,
- String.join(":", credentialProviders))) {
- Slog.w(TAG, "Failed to remove secondary package: " + packageName);
+ String.join(":", credentialProviders),
+ UserHandle.myUserId(),
+ /* overrideableByRestore= */ true)) {
+ Slog.e(TAG, "Failed to remove secondary package: " + packageName);
}
}
@@ -1232,4 +1232,38 @@ public final class CredentialManagerService
return providers;
}
+
+ /** A wrapper class that can be used by tests for intercepting reads/writes. */
+ public static class SettingsWrapper {
+ private final Context mContext;
+
+ public SettingsWrapper(@NonNull Context context) {
+ this.mContext = context;
+ }
+
+ ContentResolver getContentResolver() {
+ return mContext.getContentResolver();
+ }
+
+ /** Retrieves the string value of a system setting */
+ public String getStringForUser(String name, int userHandle) {
+ return Settings.Secure.getStringForUser(getContentResolver(), name, userHandle);
+ }
+
+ /** Updates the string value of a system setting */
+ public boolean putStringForUser(
+ String name,
+ String value,
+ int userHandle,
+ boolean overrideableByRestore) {
+ return Settings.Secure.putStringForUser(
+ getContentResolver(),
+ name,
+ value,
+ null,
+ false,
+ userHandle,
+ overrideableByRestore);
+ }
+ }
}
diff --git a/services/tests/InputMethodSystemServerTests/src/com/android/server/inputmethod/ClientControllerTest.java b/services/tests/InputMethodSystemServerTests/src/com/android/server/inputmethod/ClientControllerTest.java
index b9f1ea06aebe..dc9631a8f2e2 100644
--- a/services/tests/InputMethodSystemServerTests/src/com/android/server/inputmethod/ClientControllerTest.java
+++ b/services/tests/InputMethodSystemServerTests/src/com/android/server/inputmethod/ClientControllerTest.java
@@ -116,7 +116,7 @@ public final class ClientControllerTest {
ANY_CALLER_PID);
verify(invoker.asBinder()).linkToDeath(any(IBinder.DeathRecipient.class), eq(0));
- assertThat(mController.mClients).containsEntry(invoker.asBinder(), added);
+ assertThat(mController.getClient(invoker.asBinder())).isSameInstanceAs(added);
}
}
@@ -133,7 +133,7 @@ public final class ClientControllerTest {
var invoker = IInputMethodClientInvoker.create(mClient, mHandler);
added = mController.addClient(invoker, mConnection, ANY_DISPLAY_ID, ANY_CALLER_UID,
ANY_CALLER_PID);
- assertThat(mController.mClients).containsEntry(invoker.asBinder(), added);
+ assertThat(mController.getClient(invoker.asBinder())).isSameInstanceAs(added);
assertThat(mController.removeClient(mClient)).isTrue();
}
diff --git a/services/tests/displayservicetests/src/com/android/server/display/DisplayManagerServiceTest.java b/services/tests/displayservicetests/src/com/android/server/display/DisplayManagerServiceTest.java
index 02e3ef4d5f0b..75febd902dcf 100644
--- a/services/tests/displayservicetests/src/com/android/server/display/DisplayManagerServiceTest.java
+++ b/services/tests/displayservicetests/src/com/android/server/display/DisplayManagerServiceTest.java
@@ -61,6 +61,7 @@ import static org.mockito.Mockito.when;
import android.annotation.NonNull;
import android.annotation.Nullable;
+import android.app.ActivityOptions.LaunchCookie;
import android.app.PropertyInvalidatedCache;
import android.companion.virtual.IVirtualDevice;
import android.companion.virtual.IVirtualDeviceManager;
@@ -1557,7 +1558,7 @@ public class DisplayManagerServiceTest {
when(mMockProjectionService
.setContentRecordingSession(any(ContentRecordingSession.class), eq(projection)))
.thenReturn(true);
- doReturn(mock(IBinder.class)).when(projection).getLaunchCookie();
+ doReturn(new LaunchCookie()).when(projection).getLaunchCookie();
doReturn(true).when(mMockProjectionService).isCurrentProjection(eq(projection));
final VirtualDisplayConfig.Builder builder = new VirtualDisplayConfig.Builder(
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 bb70080362b1..92513760fa4a 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
@@ -21,6 +21,9 @@ import static com.google.common.truth.Truth.assertThat;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertTrue;
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.Mockito.doAnswer;
+import static org.mockito.Mockito.spy;
import static org.mockito.Mockito.when;
import android.content.Context;
@@ -96,18 +99,11 @@ public class BatteryStatsHistoryTest {
mClock.realtime = 123;
mHistory = new BatteryStatsHistory(mHistoryBuffer, mSystemDir, 32, 1024,
- mStepDetailsCalculator, mClock, mMonotonicClock, mTracer) {
- @Override
- public boolean readFileToParcel(Parcel out, AtomicFile file) {
- mReadFiles.add(file.getBaseFile().getName());
- return super.readFileToParcel(out, file);
- }
- };
+ mStepDetailsCalculator, mClock, mMonotonicClock, mTracer);
when(mStepDetailsCalculator.getHistoryStepDetails())
.thenReturn(new BatteryStats.HistoryStepDetails());
-
mHistoryPrinter = new BatteryStats.HistoryPrinter();
}
@@ -276,6 +272,15 @@ public class BatteryStatsHistoryTest {
mReadFiles.clear();
+ // Make an immutable copy and spy on it
+ mHistory = spy(mHistory.copy());
+
+ doAnswer(invocation -> {
+ AtomicFile file = invocation.getArgument(1);
+ mReadFiles.add(file.getBaseFile().getName());
+ return invocation.callRealMethod();
+ }).when(mHistory).readFileToParcel(any(), any());
+
// Prepare history for iteration
mHistory.iterate(0, MonotonicClock.UNDEFINED);
@@ -309,6 +314,15 @@ public class BatteryStatsHistoryTest {
mReadFiles.clear();
+ // Make an immutable copy and spy on it
+ mHistory = spy(mHistory.copy());
+
+ doAnswer(invocation -> {
+ AtomicFile file = invocation.getArgument(1);
+ mReadFiles.add(file.getBaseFile().getName());
+ return invocation.callRealMethod();
+ }).when(mHistory).readFileToParcel(any(), any());
+
// Prepare history for iteration
mHistory.iterate(1000, 3000);
diff --git a/services/tests/powerstatstests/src/com/android/server/power/stats/SystemServicePowerCalculatorTest.java b/services/tests/powerstatstests/src/com/android/server/power/stats/SystemServicePowerCalculatorTest.java
index 4dae2d548057..8e53d5285cc4 100644
--- a/services/tests/powerstatstests/src/com/android/server/power/stats/SystemServicePowerCalculatorTest.java
+++ b/services/tests/powerstatstests/src/com/android/server/power/stats/SystemServicePowerCalculatorTest.java
@@ -28,6 +28,9 @@ import static org.mockito.Mockito.when;
import android.os.BatteryConsumer;
import android.os.Binder;
import android.os.Process;
+import android.platform.test.annotations.RequiresFlagsDisabled;
+import android.platform.test.flag.junit.CheckFlagsRule;
+import android.platform.test.flag.junit.DeviceFlagsValueProvider;
import androidx.test.filters.SmallTest;
import androidx.test.runner.AndroidJUnit4;
@@ -38,6 +41,7 @@ import com.android.internal.os.KernelCpuUidTimeReader;
import com.android.internal.os.KernelSingleUidTimeReader;
import com.android.internal.os.PowerProfile;
import com.android.internal.power.EnergyConsumerStats;
+import com.android.server.power.optimization.Flags;
import org.junit.Before;
import org.junit.Rule;
@@ -54,6 +58,8 @@ import java.util.Collection;
@RunWith(AndroidJUnit4.class)
@SuppressWarnings("GuardedBy")
public class SystemServicePowerCalculatorTest {
+ @Rule
+ public final CheckFlagsRule mCheckFlagsRule = DeviceFlagsValueProvider.createCheckFlagsRule();
private static final double PRECISION = 0.000001;
private static final int APP_UID1 = 100;
@@ -108,6 +114,7 @@ public class SystemServicePowerCalculatorTest {
}
@Test
+ @RequiresFlagsDisabled(Flags.FLAG_DISABLE_SYSTEM_SERVICE_POWER_ATTR)
public void testPowerProfileBasedModel() {
prepareBatteryStats(null);
@@ -135,6 +142,7 @@ public class SystemServicePowerCalculatorTest {
}
@Test
+ @RequiresFlagsDisabled(Flags.FLAG_DISABLE_SYSTEM_SERVICE_POWER_ATTR)
public void testMeasuredEnergyBasedModel() {
final boolean[] supportedPowerBuckets =
new boolean[EnergyConsumerStats.NUMBER_STANDARD_POWER_BUCKETS];
diff --git a/services/tests/servicestests/Android.bp b/services/tests/servicestests/Android.bp
index 8958fac87bb6..e22d99d45521 100644
--- a/services/tests/servicestests/Android.bp
+++ b/services/tests/servicestests/Android.bp
@@ -36,6 +36,7 @@ android_test {
"-Werror",
],
static_libs: [
+ "cts-input-lib",
"frameworks-base-testutils",
"services.accessibility",
"services.appwidget",
diff --git a/services/tests/servicestests/src/com/android/server/accessibility/AccessibilityInputFilterInputTest.kt b/services/tests/servicestests/src/com/android/server/accessibility/AccessibilityInputFilterInputTest.kt
new file mode 100644
index 000000000000..52c7d8d2bd2e
--- /dev/null
+++ b/services/tests/servicestests/src/com/android/server/accessibility/AccessibilityInputFilterInputTest.kt
@@ -0,0 +1,280 @@
+/*
+ * Copyright 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.android.server.accessibility
+
+import android.hardware.display.DisplayManagerGlobal
+import android.os.SystemClock
+import android.view.Display
+import android.view.Display.DEFAULT_DISPLAY
+import android.view.DisplayAdjustments
+import android.view.DisplayInfo
+import android.view.IInputFilterHost
+import android.view.InputDevice.SOURCE_TOUCHSCREEN
+import android.view.InputEvent
+import android.view.MotionEvent
+import android.view.MotionEvent.ACTION_DOWN
+import android.view.MotionEvent.ACTION_MOVE
+import android.view.MotionEvent.ACTION_UP
+import android.view.MotionEvent.ACTION_HOVER_ENTER
+import android.view.MotionEvent.ACTION_HOVER_EXIT
+import android.view.MotionEvent.ACTION_HOVER_MOVE
+import android.view.WindowManagerPolicyConstants.FLAG_PASS_TO_USER
+import androidx.test.ext.junit.runners.AndroidJUnit4
+import androidx.test.platform.app.InstrumentationRegistry
+import com.android.cts.input.inputeventmatchers.withDeviceId
+import com.android.cts.input.inputeventmatchers.withMotionAction
+import com.android.server.LocalServices
+import com.android.server.accessibility.magnification.MagnificationProcessor
+import com.android.server.wm.WindowManagerInternal
+import java.util.concurrent.LinkedBlockingQueue
+import org.hamcrest.Matchers.allOf
+import org.junit.After
+import org.junit.Before
+import org.junit.Rule
+import org.junit.Test
+import org.junit.runner.RunWith
+import org.mockito.ArgumentMatchers.any
+import org.mockito.ArgumentMatchers.anyInt
+import org.mockito.Mock
+import org.mockito.Mockito
+import org.mockito.Mockito.doAnswer
+import org.mockito.Mockito.`when`
+import org.mockito.junit.MockitoJUnit
+import org.mockito.junit.MockitoRule
+import org.mockito.stubbing.OngoingStubbing
+
+
+/**
+ * Create a MotionEvent with the provided action, eventTime, and source
+ */
+fun createMotionEvent(action: Int, downTime: Long, eventTime: Long, source: Int, deviceId: Int):
+ MotionEvent {
+ val x = 1f
+ val y = 2f
+ val pressure = 3f
+ val size = 1f
+ val metaState = 0
+ val xPrecision = 0f
+ val yPrecision = 0f
+ val edgeFlags = 0
+ val displayId = 0
+ return MotionEvent.obtain(downTime, eventTime, action, x, y, pressure, size, metaState,
+ xPrecision, yPrecision, deviceId, edgeFlags, source, displayId)
+}
+
+/**
+ * Tests for AccessibilityInputFilter, focusing on the input event processing as seen by the callers
+ * of the InputFilter interface.
+ * The main interaction with AccessibilityInputFilter in these tests is with the filterInputEvent
+ * and sendInputEvent APIs of InputFilter.
+ */
+@RunWith(AndroidJUnit4::class)
+class AccessibilityInputFilterInputTest {
+ private val instrumentation = InstrumentationRegistry.getInstrumentation()
+
+ private companion object{
+ const val ALL_A11Y_FEATURES = (AccessibilityInputFilter.FLAG_FEATURE_AUTOCLICK
+ or AccessibilityInputFilter.FLAG_FEATURE_TOUCH_EXPLORATION
+ or AccessibilityInputFilter.FLAG_FEATURE_CONTROL_SCREEN_MAGNIFIER
+ or AccessibilityInputFilter.FLAG_FEATURE_TRIGGERED_SCREEN_MAGNIFIER
+ or AccessibilityInputFilter.FLAG_FEATURE_INJECT_MOTION_EVENTS
+ or AccessibilityInputFilter.FLAG_FEATURE_FILTER_KEY_EVENTS)
+ }
+
+ @Rule
+ @JvmField
+ val mocks: MockitoRule = MockitoJUnit.rule()
+
+ @Mock
+ private lateinit var mockA11yController: WindowManagerInternal.AccessibilityControllerInternal
+
+ @Mock
+ private lateinit var mockWindowManagerService: WindowManagerInternal
+
+ @Mock
+ private lateinit var mockMagnificationProcessor: MagnificationProcessor
+
+ private val inputEvents = LinkedBlockingQueue<InputEvent>()
+ private val verifier = BlockingQueueEventVerifier(inputEvents)
+
+ @Mock
+ private lateinit var host: IInputFilterHost
+ private lateinit var ams: AccessibilityManagerService
+ private lateinit var a11yInputFilter: AccessibilityInputFilter
+ private val touchDeviceId = 1
+
+ @Before
+ fun setUp() {
+ val context = instrumentation.context
+ LocalServices.removeServiceForTest(WindowManagerInternal::class.java)
+ LocalServices.addService(WindowManagerInternal::class.java, mockWindowManagerService)
+
+ whenever(mockA11yController.isAccessibilityTracingEnabled).thenReturn(false)
+ whenever(
+ mockWindowManagerService.accessibilityController).thenReturn(
+ mockA11yController)
+
+ ams = Mockito.spy(AccessibilityManagerService(context))
+ val displayList = arrayListOf(createStubDisplay(DEFAULT_DISPLAY, DisplayInfo()))
+ whenever(ams.validDisplayList).thenReturn(displayList)
+ whenever(ams.magnificationProcessor).thenReturn(mockMagnificationProcessor)
+
+ doAnswer {
+ val event = it.getArgument(0) as MotionEvent
+ inputEvents.add(MotionEvent.obtain(event))
+ }.`when`(host).sendInputEvent(any(), anyInt())
+
+ a11yInputFilter = AccessibilityInputFilter(context, ams)
+ a11yInputFilter.install(host)
+ }
+
+ @After
+ fun tearDown() {
+ if (this::a11yInputFilter.isInitialized) {
+ a11yInputFilter.uninstall()
+ }
+ }
+
+ /**
+ * When no features are enabled, the events pass through the filter without getting modified.
+ */
+ @Test
+ fun testSingleDeviceTouchEventsWithoutA11yFeatures() {
+ enableFeatures(0)
+
+ val downTime = SystemClock.uptimeMillis()
+ val downEvent = createMotionEvent(
+ ACTION_DOWN, downTime, downTime, SOURCE_TOUCHSCREEN, touchDeviceId)
+ send(downEvent)
+ verifier.assertReceivedMotion(
+ allOf(withMotionAction(ACTION_DOWN), withDeviceId(touchDeviceId)))
+
+ val moveEvent = createMotionEvent(
+ ACTION_MOVE, downTime, SystemClock.uptimeMillis(), SOURCE_TOUCHSCREEN, touchDeviceId)
+ send(moveEvent)
+ verifier.assertReceivedMotion(
+ allOf(withMotionAction(ACTION_MOVE), withDeviceId(touchDeviceId)))
+
+ val upEvent = createMotionEvent(
+ ACTION_UP, downTime, SystemClock.uptimeMillis(), SOURCE_TOUCHSCREEN, touchDeviceId)
+ send(upEvent)
+ verifier.assertReceivedMotion(
+ allOf(withMotionAction(ACTION_UP), withDeviceId(touchDeviceId)))
+
+ verifier.assertNoEvents()
+ }
+
+ /**
+ * Enable all a11y features and send a touchscreen stream of DOWN -> MOVE -> UP events.
+ * These get converted into HOVER_ENTER -> HOVER_MOVE -> HOVER_EXIT events by the input filter.
+ */
+ @Test
+ fun testSingleDeviceTouchEventsWithAllA11yFeatures() {
+ enableFeatures(ALL_A11Y_FEATURES)
+
+ val downTime = SystemClock.uptimeMillis()
+ val downEvent = createMotionEvent(
+ ACTION_DOWN, downTime, downTime, SOURCE_TOUCHSCREEN, touchDeviceId)
+ send(MotionEvent.obtain(downEvent))
+
+ // DOWN event gets transformed to HOVER_ENTER
+ verifier.assertReceivedMotion(
+ allOf(withMotionAction(ACTION_HOVER_ENTER), withDeviceId(touchDeviceId)))
+
+ // MOVE becomes HOVER_MOVE
+ val moveEvent = createMotionEvent(
+ ACTION_MOVE, downTime, SystemClock.uptimeMillis(), SOURCE_TOUCHSCREEN, touchDeviceId)
+ send(moveEvent)
+ verifier.assertReceivedMotion(
+ allOf(withMotionAction(ACTION_HOVER_MOVE), withDeviceId(touchDeviceId)))
+
+ // UP becomes HOVER_EXIT
+ val upEvent = createMotionEvent(
+ ACTION_UP, downTime, SystemClock.uptimeMillis(), SOURCE_TOUCHSCREEN, touchDeviceId)
+ send(upEvent)
+
+ verifier.assertReceivedMotion(
+ allOf(withMotionAction(ACTION_HOVER_EXIT), withDeviceId(touchDeviceId)))
+
+ verifier.assertNoEvents()
+ }
+
+ /**
+ * Enable all a11y features and send a touchscreen event stream. In the middle of the gesture,
+ * disable the a11y features.
+ * When the a11y features are disabled, the filter generates HOVER_EXIT without further input
+ * from the dispatcher.
+ */
+ @Test
+ fun testSingleDeviceTouchEventsDisableFeaturesMidGesture() {
+ enableFeatures(ALL_A11Y_FEATURES)
+
+ val downTime = SystemClock.uptimeMillis()
+ val downEvent = createMotionEvent(
+ ACTION_DOWN, downTime, downTime, SOURCE_TOUCHSCREEN, touchDeviceId)
+ send(MotionEvent.obtain(downEvent))
+
+ // DOWN event gets transformed to HOVER_ENTER
+ verifier.assertReceivedMotion(
+ allOf(withMotionAction(ACTION_HOVER_ENTER), withDeviceId(touchDeviceId)))
+ verifier.assertNoEvents()
+
+ enableFeatures(0)
+ verifier.assertReceivedMotion(
+ allOf(withMotionAction(ACTION_HOVER_EXIT), withDeviceId(touchDeviceId)))
+ verifier.assertNoEvents()
+
+ val moveEvent = createMotionEvent(
+ ACTION_MOVE, downTime, SystemClock.uptimeMillis(), SOURCE_TOUCHSCREEN, touchDeviceId)
+ send(moveEvent)
+ val upEvent = createMotionEvent(
+ ACTION_UP, downTime, SystemClock.uptimeMillis(), SOURCE_TOUCHSCREEN, touchDeviceId)
+ send(upEvent)
+ // As the original gesture continues, no additional events should be getting sent by the
+ // filter because the HOVER_EXIT above already effectively finished the current gesture and
+ // the DOWN event was never sent to the host.
+
+ // Bug: the down event was swallowed, so the remainder of the gesture should be swallowed
+ // too. However, the MOVE and UP events are currently passed back to the dispatcher.
+ // TODO(b/310014874) - ensure a11y sends consistent input streams to the dispatcher
+ verifier.assertReceivedMotion(
+ allOf(withMotionAction(ACTION_MOVE), withDeviceId(touchDeviceId)))
+ verifier.assertReceivedMotion(
+ allOf(withMotionAction(ACTION_UP), withDeviceId(touchDeviceId)))
+
+ verifier.assertNoEvents()
+ }
+
+ private fun createStubDisplay(displayId: Int, displayInfo: DisplayInfo): Display {
+ val display = Display(DisplayManagerGlobal.getInstance(), displayId,
+ displayInfo, DisplayAdjustments.DEFAULT_DISPLAY_ADJUSTMENTS)
+ return display
+ }
+
+ private fun send(event: InputEvent) {
+ // We need to make a copy of the event before sending it to the filter, because the filter
+ // will recycle it, but the caller of this function might want to still be able to use
+ // this event for subsequent checks
+ val eventCopy = if (event is MotionEvent) MotionEvent.obtain(event) else event
+ a11yInputFilter.filterInputEvent(eventCopy, FLAG_PASS_TO_USER)
+ }
+
+ private fun enableFeatures(features: Int) {
+ instrumentation.runOnMainSync { a11yInputFilter.setUserAndEnabledFeatures(0, features) }
+ }
+}
+
+private fun <T> whenever(methodCall: T): OngoingStubbing<T> = `when`(methodCall)
diff --git a/services/tests/servicestests/src/com/android/server/accessibility/BlockingQueueEventVerifier.kt b/services/tests/servicestests/src/com/android/server/accessibility/BlockingQueueEventVerifier.kt
new file mode 100644
index 000000000000..b12f537d1482
--- /dev/null
+++ b/services/tests/servicestests/src/com/android/server/accessibility/BlockingQueueEventVerifier.kt
@@ -0,0 +1,57 @@
+/*
+ * Copyright 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.android.server.accessibility
+
+import android.os.InputConstants.DEFAULT_DISPATCHING_TIMEOUT_MILLIS
+import android.view.InputEvent
+import android.view.MotionEvent
+import java.time.Duration
+import java.util.concurrent.BlockingQueue
+import java.util.concurrent.TimeUnit
+import org.junit.Assert.fail
+
+import org.hamcrest.Matcher
+import org.hamcrest.MatcherAssert.assertThat
+import org.junit.Assert.assertNull
+
+private fun <T> getEvent(queue: BlockingQueue<T>, timeout: Duration): T? {
+ return queue.poll(timeout.toMillis(), TimeUnit.MILLISECONDS)
+}
+
+class BlockingQueueEventVerifier(val queue: BlockingQueue<InputEvent>) {
+ fun assertReceivedMotion(matcher: Matcher<MotionEvent>) {
+ val event = getMotionEvent()
+ assertThat("MotionEvent checks", event, matcher)
+ }
+
+ fun assertNoEvents() {
+ val event = getEvent(queue, Duration.ofMillis(50))
+ assertNull(event)
+ }
+
+ private fun getMotionEvent(): MotionEvent {
+ val event = getEvent(queue, Duration.ofMillis(DEFAULT_DISPATCHING_TIMEOUT_MILLIS.toLong()))
+ if (event == null) {
+ fail("Did not get an event")
+ }
+ if (event is MotionEvent) {
+ return event
+ }
+ fail("Instead of motion, got $event")
+ throw RuntimeException("should not reach here")
+ }
+}
+
diff --git a/services/tests/servicestests/src/com/android/server/credentials/CredentialManagerServiceTest.java b/services/tests/servicestests/src/com/android/server/credentials/CredentialManagerServiceTest.java
index d850c73ebc26..57f3cc03980e 100644
--- a/services/tests/servicestests/src/com/android/server/credentials/CredentialManagerServiceTest.java
+++ b/services/tests/servicestests/src/com/android/server/credentials/CredentialManagerServiceTest.java
@@ -22,6 +22,7 @@ import android.content.Context;
import android.os.UserHandle;
import android.provider.Settings;
+import androidx.annotation.NonNull;
import androidx.test.core.app.ApplicationProvider;
import androidx.test.filters.SmallTest;
import androidx.test.runner.AndroidJUnit4;
@@ -40,10 +41,12 @@ import java.util.Set;
public final class CredentialManagerServiceTest {
Context mContext = null;
+ MockSettingsWrapper mSettingsWrapper = null;
@Before
public void setUp() throws CertificateException {
mContext = ApplicationProvider.getApplicationContext();
+ mSettingsWrapper = new MockSettingsWrapper(mContext);
}
@Test
@@ -81,7 +84,8 @@ public final class CredentialManagerServiceTest {
Settings.Secure.CREDENTIAL_SERVICE_PRIMARY,
"com.example.test/com.example.test.TestActivity");
- CredentialManagerService.updateProvidersWhenPackageRemoved(mContext, "com.example.test");
+ CredentialManagerService.updateProvidersWhenPackageRemoved(
+ mSettingsWrapper, "com.example.test");
assertThat(getSettingsKey(Settings.Secure.AUTOFILL_SERVICE)).isEqualTo("");
assertThat(getSettingsKey(Settings.Secure.CREDENTIAL_SERVICE))
@@ -101,7 +105,8 @@ public final class CredentialManagerServiceTest {
setSettingsKey(Settings.Secure.CREDENTIAL_SERVICE, testCredentialValue);
setSettingsKey(Settings.Secure.CREDENTIAL_SERVICE_PRIMARY, testCredentialPrimaryValue);
- CredentialManagerService.updateProvidersWhenPackageRemoved(mContext, "com.example.test3");
+ CredentialManagerService.updateProvidersWhenPackageRemoved(
+ mSettingsWrapper, "com.example.test3");
// Since the provider removed was not a primary provider then we should do nothing.
assertThat(getSettingsKey(Settings.Secure.AUTOFILL_SERVICE))
@@ -125,7 +130,8 @@ public final class CredentialManagerServiceTest {
Settings.Secure.CREDENTIAL_SERVICE_PRIMARY,
"com.example.test/com.example.test.TestActivity");
- CredentialManagerService.updateProvidersWhenPackageRemoved(mContext, "com.example.test");
+ CredentialManagerService.updateProvidersWhenPackageRemoved(
+ mSettingsWrapper, "com.example.test");
assertThat(getSettingsKey(Settings.Secure.AUTOFILL_SERVICE)).isEqualTo("");
assertThat(getSettingsKey(Settings.Secure.CREDENTIAL_SERVICE))
@@ -144,7 +150,8 @@ public final class CredentialManagerServiceTest {
setSettingsKey(Settings.Secure.CREDENTIAL_SERVICE, testCredentialValue);
setSettingsKey(Settings.Secure.CREDENTIAL_SERVICE_PRIMARY, testCredentialPrimaryValue);
- CredentialManagerService.updateProvidersWhenPackageRemoved(mContext, "com.example.test3");
+ CredentialManagerService.updateProvidersWhenPackageRemoved(
+ mSettingsWrapper, "com.example.test3");
// Since the provider removed was not a primary provider then we should do nothing.
assertCredentialPropertyEquals(
@@ -176,12 +183,36 @@ public final class CredentialManagerServiceTest {
assertThat(actualValueSet).isEqualTo(newValueSet);
}
- private void setSettingsKey(String key, String value) {
- assertThat(Settings.Secure.putString(mContext.getContentResolver(), key, value)).isTrue();
+ private void setSettingsKey(String name, String value) {
+ assertThat(
+ mSettingsWrapper.putStringForUser(
+ name, value, UserHandle.myUserId(), true))
+ .isTrue();
}
- private String getSettingsKey(String key) {
- return Settings.Secure.getStringForUser(
- mContext.getContentResolver(), key, UserHandle.myUserId());
+ private String getSettingsKey(String name) {
+ return mSettingsWrapper.getStringForUser(name, UserHandle.myUserId());
+ }
+
+ private static final class MockSettingsWrapper
+ extends CredentialManagerService.SettingsWrapper {
+
+ MockSettingsWrapper(@NonNull Context context) {
+ super(context);
+ }
+
+ /** Updates the string value of a system setting */
+ @Override
+ public boolean putStringForUser(
+ String name,
+ String value,
+ int userHandle,
+ boolean overrideableByRestore) {
+ // This will ensure that when the settings putStringForUser method is called by
+ // CredentialManagerService that the overrideableByRestore bit is true.
+ assertThat(overrideableByRestore).isTrue();
+
+ return Settings.Secure.putStringForUser(getContentResolver(), name, value, userHandle);
+ }
}
}
diff --git a/services/tests/servicestests/src/com/android/server/media/projection/MediaProjectionManagerServiceTest.java b/services/tests/servicestests/src/com/android/server/media/projection/MediaProjectionManagerServiceTest.java
index 097cc5177a83..abd3abee82fb 100644
--- a/services/tests/servicestests/src/com/android/server/media/projection/MediaProjectionManagerServiceTest.java
+++ b/services/tests/servicestests/src/com/android/server/media/projection/MediaProjectionManagerServiceTest.java
@@ -49,6 +49,7 @@ import static org.mockito.Mockito.when;
import static org.testng.Assert.assertThrows;
import android.app.ActivityManagerInternal;
+import android.app.ActivityOptions.LaunchCookie;
import android.content.Context;
import android.content.ContextWrapper;
import android.content.pm.ApplicationInfo;
@@ -784,7 +785,7 @@ public class MediaProjectionManagerServiceTest {
@RecordContent int recordedContent)
throws NameNotFoundException {
MediaProjectionManagerService.MediaProjection projection = startProjectionPreconditions();
- projection.setLaunchCookie(mock(IBinder.class));
+ projection.setLaunchCookie(new LaunchCookie());
projection.start(mIMediaProjectionCallback);
projection.notifyVirtualDisplayCreated(10);
// Waiting for user to review consent.
@@ -825,7 +826,7 @@ public class MediaProjectionManagerServiceTest {
public void testSetUserReviewGrantedConsentResult_displayMirroring_noPriorSession()
throws NameNotFoundException {
MediaProjectionManagerService.MediaProjection projection = startProjectionPreconditions();
- projection.setLaunchCookie(mock(IBinder.class));
+ projection.setLaunchCookie(new LaunchCookie());
projection.start(mIMediaProjectionCallback);
// Skip setting the prior session details.
@@ -844,7 +845,7 @@ public class MediaProjectionManagerServiceTest {
public void testSetUserReviewGrantedConsentResult_displayMirroring_sessionNotWaiting()
throws NameNotFoundException {
MediaProjectionManagerService.MediaProjection projection = startProjectionPreconditions();
- projection.setLaunchCookie(mock(IBinder.class));
+ projection.setLaunchCookie(new LaunchCookie());
projection.start(mIMediaProjectionCallback);
// Session is not waiting for user's consent.
doReturn(true).when(mWindowManagerInternal).setContentRecordingSession(
diff --git a/services/tests/servicestests/src/com/android/server/pm/parsing/AndroidPackageParsingValidationTest.kt b/services/tests/servicestests/src/com/android/server/pm/parsing/AndroidPackageParsingValidationTest.kt
index 757abde2041e..e3ee21a450c7 100644
--- a/services/tests/servicestests/src/com/android/server/pm/parsing/AndroidPackageParsingValidationTest.kt
+++ b/services/tests/servicestests/src/com/android/server/pm/parsing/AndroidPackageParsingValidationTest.kt
@@ -436,6 +436,13 @@ class AndroidPackageParsingValidationTest {
validateTagCount("action", 20000, tag)
validateTagCount("category", 40000, tag)
validateTagCount("data", 40000, tag)
+ validateTagCount("uri-relative-filter-group", 100, tag)
+ }
+
+ @Test
+ fun parseUriRelativeFilterGroupTag() {
+ val tag = "uri-relative-filter-group"
+ validateTagCount("data", 100, tag)
}
@Test
@@ -465,6 +472,54 @@ class AndroidPackageParsingValidationTest {
R.styleable.AndroidManifestData_pathAdvancedPattern,
4000
)
+ validateTagAttr(tag, "query", R.styleable.AndroidManifestData_query, 4000)
+ validateTagAttr(
+ tag,
+ "queryPattern",
+ R.styleable.AndroidManifestData_queryPattern,
+ 4000
+ )
+ validateTagAttr(
+ tag,
+ "queryPrefix",
+ R.styleable.AndroidManifestData_queryPrefix,
+ 4000
+ )
+ validateTagAttr(tag,
+ "querySuffix",
+ R.styleable.AndroidManifestData_querySuffix,
+ 4000
+ )
+ validateTagAttr(
+ tag,
+ "queryAdvancedPattern",
+ R.styleable.AndroidManifestData_queryAdvancedPattern,
+ 4000
+ )
+ validateTagAttr(tag, "fragment", R.styleable.AndroidManifestData_query, 4000)
+ validateTagAttr(
+ tag,
+ "fragmentPattern",
+ R.styleable.AndroidManifestData_fragmentPattern,
+ 4000
+ )
+ validateTagAttr(
+ tag,
+ "fragmentPrefix",
+ R.styleable.AndroidManifestData_fragmentPrefix,
+ 4000
+ )
+ validateTagAttr(tag,
+ "fragmentSuffix",
+ R.styleable.AndroidManifestData_fragmentSuffix,
+ 4000
+ )
+ validateTagAttr(
+ tag,
+ "fragmentAdvancedPattern",
+ R.styleable.AndroidManifestData_fragmentAdvancedPattern,
+ 4000
+ )
validateTagAttr(tag, "mimeType", R.styleable.AndroidManifestData_mimeType, 255)
validateTagAttr(tag, "mimeGroup", R.styleable.AndroidManifestData_mimeGroup, 1024)
}
diff --git a/tools/aapt2/cmd/Link.cpp b/tools/aapt2/cmd/Link.cpp
index f3f183815d0b..642a5618b6ad 100644
--- a/tools/aapt2/cmd/Link.cpp
+++ b/tools/aapt2/cmd/Link.cpp
@@ -1988,6 +1988,8 @@ class Linker {
context_->SetNameManglerPolicy(NameManglerPolicy{context_->GetCompilationPackage()});
context_->SetSplitNameDependencies(app_info_.split_name_dependencies);
+ std::unique_ptr<xml::XmlResource> pre_flags_filter_manifest_xml = manifest_xml->Clone();
+
FeatureFlagsFilterOptions flags_filter_options;
if (context_->GetMinSdkVersion() > SDK_UPSIDE_DOWN_CAKE) {
// For API version > U, PackageManager will dynamically read the flag values and disable
@@ -2297,7 +2299,12 @@ class Linker {
}
if (options_.generate_java_class_path) {
- if (!WriteManifestJavaFile(manifest_xml.get())) {
+ // The FeatureFlagsFilter may remove <permission> and <permission-group> elements that
+ // generate constants in the Manifest Java file. While we want those permissions and
+ // permission groups removed in the SDK (i.e., if a feature flag is disabled), the
+ // constants should still remain so that code referencing it (e.g., within a feature
+ // flag check) will still compile. Therefore we use the manifest XML before the filter.
+ if (!WriteManifestJavaFile(pre_flags_filter_manifest_xml.get())) {
error = true;
}
}
diff --git a/tools/aapt2/cmd/Link_test.cpp b/tools/aapt2/cmd/Link_test.cpp
index 9323f3b95eac..6cc42f17c0a1 100644
--- a/tools/aapt2/cmd/Link_test.cpp
+++ b/tools/aapt2/cmd/Link_test.cpp
@@ -1021,9 +1021,11 @@ TEST_F(LinkTest, FeatureFlagDisabled_SdkAtMostUDC) {
.AddContents(manifest_contents)
.Build();
+ const std::string app_java = GetTestPath("app-java");
auto app_link_args = LinkCommandBuilder(this)
.SetManifestFile(app_manifest)
.AddParameter("-I", android_apk)
+ .AddParameter("--java", app_java)
.AddParameter("--feature-flags", "flag=false");
const std::string app_apk = GetTestPath("app.apk");
@@ -1038,6 +1040,12 @@ TEST_F(LinkTest, FeatureFlagDisabled_SdkAtMostUDC) {
ASSERT_THAT(root, NotNull());
auto maybe_removed = root->FindChild({}, "permission");
ASSERT_THAT(maybe_removed, IsNull());
+
+ // Code for the permission should be generated even if the element is removed
+ const std::string manifest_java = app_java + "/com/example/app/Manifest.java";
+ std::string manifest_java_contents;
+ ASSERT_TRUE(android::base::ReadFileToString(manifest_java, &manifest_java_contents));
+ EXPECT_THAT(manifest_java_contents, HasSubstr(" public static final String FOO=\"FOO\";"));
}
TEST_F(LinkTest, FeatureFlagEnabled_SdkAtMostUDC) {
diff --git a/tools/hoststubgen/hoststubgen/helper-framework-runtime-src/framework/com/android/hoststubgen/nativesubstitution/MessageQueue_host.java b/tools/hoststubgen/hoststubgen/helper-framework-runtime-src/framework/com/android/hoststubgen/nativesubstitution/MessageQueue_host.java
index 2e47d48f4fa0..65da4a144160 100644
--- a/tools/hoststubgen/hoststubgen/helper-framework-runtime-src/framework/com/android/hoststubgen/nativesubstitution/MessageQueue_host.java
+++ b/tools/hoststubgen/hoststubgen/helper-framework-runtime-src/framework/com/android/hoststubgen/nativesubstitution/MessageQueue_host.java
@@ -28,6 +28,7 @@ public class MessageQueue_host {
private final Object mPoller = new Object();
private volatile boolean mPolling;
+ private volatile boolean mPendingWake;
private void validate() {
if (mDeleted) {
@@ -62,7 +63,9 @@ public class MessageQueue_host {
synchronized (q.mPoller) {
q.mPolling = true;
try {
- if (timeoutMillis == 0) {
+ if (q.mPendingWake) {
+ // Calling with pending wake returns immediately
+ } else if (timeoutMillis == 0) {
// Calling epoll_wait() with 0 returns immediately
} else if (timeoutMillis == -1) {
q.mPoller.wait();
@@ -72,6 +75,8 @@ public class MessageQueue_host {
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
}
+ // Any reason for returning counts as a "wake", so clear pending
+ q.mPendingWake = false;
q.mPolling = false;
}
}
@@ -79,6 +84,7 @@ public class MessageQueue_host {
public static void nativeWake(long ptr) {
var q = getInstance(ptr);
synchronized (q.mPoller) {
+ q.mPendingWake = true;
q.mPoller.notifyAll();
}
}