Merge "Moved tests/**/systemui/[t-z] to multivalentTests/**/systemui" into main
diff --git a/TEST_MAPPING b/TEST_MAPPING
index dfacbc4..e469f16 100644
--- a/TEST_MAPPING
+++ b/TEST_MAPPING
@@ -1,44 +1,17 @@
{
"presubmit-large": [
{
- "name": "FrameworksServicesTests",
- "options": [
- {
- "include-annotation": "android.platform.test.annotations.Presubmit"
- },
- {
- "exclude-annotation": "androidx.test.filters.FlakyTest"
- },
- {
- "exclude-annotation": "org.junit.Ignore"
- }
- ]
+ "name": "FrameworksServicesTests_Presubmit"
}
],
"presubmit-pm": [
{
- "name": "PackageManagerServiceServerTests",
- "options": [
- {
- "include-annotation": "android.platform.test.annotations.Presubmit"
- },
- {
- "exclude-annotation": "androidx.test.filters.FlakyTest"
- },
- {
- "exclude-annotation": "org.junit.Ignore"
- }
- ]
+ "name": "PackageManagerServiceServerTests_Presubmit"
}
],
"presubmit": [
{
- "name": "ManagedProvisioningTests",
- "options": [
- {
- "exclude-annotation": "androidx.test.filters.FlakyTest"
- }
- ]
+ "name": "ManagedProvisioningTests"
},
{
"file_patterns": [
@@ -46,86 +19,28 @@
"SystemServer\\.java",
"services/tests/apexsystemservices/.*"
],
- "name": "ApexSystemServicesTestCases",
- "options": [
- {
- "exclude-annotation": "androidx.test.filters.FlakyTest"
- },
- {
- "exclude-annotation": "org.junit.Ignore"
- }
- ]
+ "name": "ApexSystemServicesTestCases"
},
{
- "name": "FrameworksUiServicesTests",
- "options": [
- {
- "exclude-annotation": "androidx.test.filters.FlakyTest"
- }
- ]
+ "name": "FrameworksUiServicesTests"
},
{
- "name": "FrameworksInputMethodSystemServerTests",
- "options": [
- {"include-filter": "com.android.server.inputmethod"},
- {"exclude-annotation": "androidx.test.filters.FlakyTest"},
- {"exclude-annotation": "org.junit.Ignore"}
- ]
+ "name": "FrameworksInputMethodSystemServerTests_server_inputmethod"
},
{
- "name": "ExtServicesUnitTests-tplus",
- "options": [
- {
- "exclude-annotation": "androidx.test.filters.FlakyTest"
- }
- ]
+ "name": "ExtServicesUnitTests-tplus"
},
{
- "name": "ExtServicesUnitTests-sminus",
- "options": [
- {
- "exclude-annotation": "androidx.test.filters.FlakyTest"
- }
- ]
+ "name": "ExtServicesUnitTests-sminus"
},
{
- "name": "FrameworksCoreTests",
- "options": [
- {
- "include-annotation": "android.platform.test.annotations.Presubmit"
- },
- {
- "exclude-annotation": "androidx.test.filters.FlakyTest"
- },
- {
- "exclude-annotation": "org.junit.Ignore"
- }
- ]
+ "name": "FrameworksCoreTests_Presubmit"
},
{
- "name": "FrameworkPermissionTests",
- "options": [
- {
- "include-annotation": "android.platform.test.annotations.Presubmit"
- },
- {
- "exclude-annotation": "androidx.test.filters.FlakyTest"
- },
- {
- "exclude-annotation": "org.junit.Ignore"
- }
- ]
+ "name": "FrameworkPermissionTests_Presubmit"
},
{
- "name": "FrameworksInProcessTests",
- "options": [
- {
- "exclude-annotation": "androidx.test.filters.FlakyTest"
- },
- {
- "exclude-annotation": "org.junit.Ignore"
- }
- ]
+ "name": "FrameworksInProcessTests"
},
{
"name": "vts_treble_vintf_framework_test"
@@ -166,78 +81,25 @@
// infra during the hardening phase.
// TODO: this tag to be removed once the above is no longer an issue.
{
- "name": "FrameworksUiServicesTests",
- "options": [
- {
- "exclude-annotation": "androidx.test.filters.FlakyTest"
- }
- ]
+ "name": "FrameworksUiServicesTests"
},
{
- "name": "ExtServicesUnitTests-tplus",
- "options": [
- {
- "exclude-annotation": "androidx.test.filters.FlakyTest"
- }
- ]
+ "name": "ExtServicesUnitTests-tplus"
},
{
- "name": "ExtServicesUnitTests-sminus",
- "options": [
- {
- "exclude-annotation": "androidx.test.filters.FlakyTest"
- }
- ]
+ "name": "ExtServicesUnitTests-sminus"
},
{
- "name": "TestablesTests",
- "options": [
- {
- "exclude-annotation": "androidx.test.filters.FlakyTest"
- }
- ]
+ "name": "TestablesTests"
},
{
- "name": "FrameworksCoreTests",
- "options": [
- {
- "include-annotation": "android.platform.test.annotations.Presubmit"
- },
- {
- "exclude-annotation": "androidx.test.filters.FlakyTest"
- },
- {
- "exclude-annotation": "org.junit.Ignore"
- }
- ]
+ "name": "FrameworksCoreTests_Presubmit"
},
{
- "name": "FrameworksServicesTests",
- "options": [
- {
- "include-annotation": "android.platform.test.annotations.Presubmit"
- },
- {
- "exclude-annotation": "androidx.test.filters.FlakyTest"
- },
- {
- "exclude-annotation": "org.junit.Ignore"
- }
- ]
+ "name": "FrameworksServicesTests_presubmit"
},
{
- "name": "PackageManagerServiceServerTests",
- "options": [
- {
- "include-annotation": "android.platform.test.annotations.Presubmit"
- },
- {
- "exclude-annotation": "androidx.test.filters.FlakyTest"
- },
- {
- "exclude-annotation": "org.junit.Ignore"
- }
- ]
+ "name": "PackageManagerServiceServerTests_Presubmit"
}
]
}
diff --git a/apex/jobscheduler/service/java/com/android/server/TEST_MAPPING b/apex/jobscheduler/service/java/com/android/server/TEST_MAPPING
index b58cb88..e3e72f4 100644
--- a/apex/jobscheduler/service/java/com/android/server/TEST_MAPPING
+++ b/apex/jobscheduler/service/java/com/android/server/TEST_MAPPING
@@ -11,10 +11,7 @@
],
"postsubmit": [
{
- "name": "FrameworksMockingServicesTests",
- "options": [
- {"include-filter": "com.android.server"}
- ]
+ "name": "FrameworksMockingServicesTests_android_server"
}
]
}
diff --git a/apex/jobscheduler/service/java/com/android/server/deviceidle/TEST_MAPPING b/apex/jobscheduler/service/java/com/android/server/deviceidle/TEST_MAPPING
index afa509c..ed8851c 100644
--- a/apex/jobscheduler/service/java/com/android/server/deviceidle/TEST_MAPPING
+++ b/apex/jobscheduler/service/java/com/android/server/deviceidle/TEST_MAPPING
@@ -6,10 +6,7 @@
],
"postsubmit": [
{
- "name": "FrameworksMockingServicesTests",
- "options": [
- {"include-filter": "com.android.server"}
- ]
+ "name": "FrameworksMockingServicesTests_android_server"
}
]
}
diff --git a/apex/jobscheduler/service/java/com/android/server/job/TEST_MAPPING b/apex/jobscheduler/service/java/com/android/server/job/TEST_MAPPING
index a0bf78f..d198bfd 100644
--- a/apex/jobscheduler/service/java/com/android/server/job/TEST_MAPPING
+++ b/apex/jobscheduler/service/java/com/android/server/job/TEST_MAPPING
@@ -1,11 +1,7 @@
{
"presubmit": [
{
- "name": "CtsJobSchedulerTestCases",
- "options": [
- {"exclude-annotation": "androidx.test.filters.FlakyTest"},
- {"exclude-annotation": "androidx.test.filters.LargeTest"}
- ]
+ "name": "CtsJobSchedulerTestCases_com_android_server_job"
},
{
"name": "FrameworksMockingServicesTests_com_android_server_job_Presubmit"
@@ -19,26 +15,16 @@
"name": "CtsJobSchedulerTestCases"
},
{
- "name": "FrameworksMockingServicesTests",
- "options": [
- {"include-filter": "com.android.server.job"}
- ]
+ "name": "FrameworksMockingServicesTests_com_android_server_job"
},
{
"name": "FrameworksServicesTests_com_android_server_job"
},
{
- "name": "CtsHostsideNetworkPolicyTests",
- "options": [
- {"include-filter": "com.android.cts.netpolicy.HostsideRestrictBackgroundNetworkTests#testMeteredNetworkAccess_expeditedJob"},
- {"include-filter": "com.android.cts.netpolicy.HostsideRestrictBackgroundNetworkTests#testNonMeteredNetworkAccess_expeditedJob"}
- ]
+ "name": "CtsHostsideNetworkPolicyTests_com_android_server_job"
},
{
- "name": "CtsStatsdAtomHostTestCases",
- "options": [
- {"include-filter": "android.cts.statsdatom.jobscheduler"}
- ]
+ "name": "CtsStatsdAtomHostTestCases_statsdatom_jobscheduler"
}
]
}
diff --git a/apex/jobscheduler/service/java/com/android/server/usage/TEST_MAPPING b/apex/jobscheduler/service/java/com/android/server/usage/TEST_MAPPING
index f56c14d..1a2013d 100644
--- a/apex/jobscheduler/service/java/com/android/server/usage/TEST_MAPPING
+++ b/apex/jobscheduler/service/java/com/android/server/usage/TEST_MAPPING
@@ -1,13 +1,7 @@
{
"presubmit": [
{
- "name": "CtsUsageStatsTestCases",
- "options": [
- {"include-filter": "android.app.usage.cts.UsageStatsTest"},
- {"exclude-annotation": "androidx.test.filters.FlakyTest"},
- {"exclude-annotation": "androidx.test.filters.MediumTest"},
- {"exclude-annotation": "androidx.test.filters.LargeTest"}
- ]
+ "name": "CtsUsageStatsTestCases_cts_usagestatstest"
},
{
"name": "CtsBRSTestCases"
diff --git a/cmds/locksettings/TEST_MAPPING b/cmds/locksettings/TEST_MAPPING
index af54a2d..0f502c9 100644
--- a/cmds/locksettings/TEST_MAPPING
+++ b/cmds/locksettings/TEST_MAPPING
@@ -1,15 +1,7 @@
{
"presubmit-large": [
{
- "name": "CtsDevicePolicyManagerTestCases",
- "options": [
- {
- "include-annotation": "com.android.cts.devicepolicy.annotations.LockSettingsTest"
- },
- {
- "exclude-annotation": "android.platform.test.annotations.FlakyTest"
- }
- ]
+ "name": "CtsDevicePolicyManagerTestCases_LockSettingsTest"
}
],
"postsubmit": [
diff --git a/core/api/current.txt b/core/api/current.txt
index 0972f41..520c7d1 100644
--- a/core/api/current.txt
+++ b/core/api/current.txt
@@ -19170,7 +19170,7 @@
method @NonNull public java.util.List<android.hardware.camera2.CaptureRequest.Key<?>> getAvailableCaptureRequestKeys();
method @NonNull public java.util.List<android.hardware.camera2.CaptureResult.Key<?>> getAvailableCaptureResultKeys();
method public java.util.List<android.hardware.camera2.CaptureRequest.Key<?>> getAvailablePhysicalCameraRequestKeys();
- method @FlaggedApi("com.android.internal.camera.flags.feature_combination_query") @NonNull public java.util.List<android.hardware.camera2.CameraCharacteristics.Key<?>> getAvailableSessionCharacteristicsKeys();
+ method @NonNull public java.util.List<android.hardware.camera2.CameraCharacteristics.Key<?>> getAvailableSessionCharacteristicsKeys();
method public java.util.List<android.hardware.camera2.CaptureRequest.Key<?>> getAvailableSessionKeys();
method @NonNull public java.util.List<android.hardware.camera2.CameraCharacteristics.Key<?>> getKeys();
method @NonNull public java.util.List<android.hardware.camera2.CameraCharacteristics.Key<?>> getKeysNeedingPermission();
@@ -19213,7 +19213,7 @@
field @FlaggedApi("com.android.internal.camera.flags.camera_manual_flash_strength_control") @NonNull public static final android.hardware.camera2.CameraCharacteristics.Key<java.lang.Integer> FLASH_TORCH_STRENGTH_MAX_LEVEL;
field @NonNull public static final android.hardware.camera2.CameraCharacteristics.Key<int[]> HOT_PIXEL_AVAILABLE_HOT_PIXEL_MODES;
field @NonNull public static final android.hardware.camera2.CameraCharacteristics.Key<android.hardware.camera2.params.DeviceStateSensorOrientationMap> INFO_DEVICE_STATE_SENSOR_ORIENTATION_MAP;
- field @FlaggedApi("com.android.internal.camera.flags.feature_combination_query") @NonNull public static final android.hardware.camera2.CameraCharacteristics.Key<java.lang.Integer> INFO_SESSION_CONFIGURATION_QUERY_VERSION;
+ field @NonNull public static final android.hardware.camera2.CameraCharacteristics.Key<java.lang.Integer> INFO_SESSION_CONFIGURATION_QUERY_VERSION;
field @NonNull public static final android.hardware.camera2.CameraCharacteristics.Key<java.lang.Integer> INFO_SUPPORTED_HARDWARE_LEVEL;
field @NonNull public static final android.hardware.camera2.CameraCharacteristics.Key<java.lang.String> INFO_VERSION;
field @NonNull public static final android.hardware.camera2.CameraCharacteristics.Key<android.util.Size[]> JPEG_AVAILABLE_THUMBNAIL_SIZES;
@@ -20083,14 +20083,14 @@
public final class ExtensionSessionConfiguration {
ctor public ExtensionSessionConfiguration(int, @NonNull java.util.List<android.hardware.camera2.params.OutputConfiguration>, @NonNull java.util.concurrent.Executor, @NonNull android.hardware.camera2.CameraExtensionSession.StateCallback);
- method @FlaggedApi("com.android.internal.camera.flags.extension_10_bit") public void clearColorSpace();
- method @FlaggedApi("com.android.internal.camera.flags.extension_10_bit") @Nullable public android.graphics.ColorSpace getColorSpace();
+ method public void clearColorSpace();
+ method @Nullable public android.graphics.ColorSpace getColorSpace();
method @NonNull public java.util.concurrent.Executor getExecutor();
method public int getExtension();
method @NonNull public java.util.List<android.hardware.camera2.params.OutputConfiguration> getOutputConfigurations();
method @Nullable public android.hardware.camera2.params.OutputConfiguration getPostviewOutputConfiguration();
method @NonNull public android.hardware.camera2.CameraExtensionSession.StateCallback getStateCallback();
- method @FlaggedApi("com.android.internal.camera.flags.extension_10_bit") public void setColorSpace(@NonNull android.graphics.ColorSpace.Named);
+ method public void setColorSpace(@NonNull android.graphics.ColorSpace.Named);
method public void setPostviewOutputConfiguration(@Nullable android.hardware.camera2.params.OutputConfiguration);
}
diff --git a/core/api/system-current.txt b/core/api/system-current.txt
index 475b1e2..9c807af 100644
--- a/core/api/system-current.txt
+++ b/core/api/system-current.txt
@@ -4972,12 +4972,12 @@
@FlaggedApi("com.android.internal.camera.flags.concert_mode") public final class CameraOutputSurface {
ctor @FlaggedApi("com.android.internal.camera.flags.concert_mode") public CameraOutputSurface(@NonNull android.view.Surface, @NonNull android.util.Size);
- method @FlaggedApi("com.android.internal.camera.flags.extension_10_bit") public int getColorSpace();
- method @FlaggedApi("com.android.internal.camera.flags.extension_10_bit") public long getDynamicRangeProfile();
+ method public int getColorSpace();
+ method public long getDynamicRangeProfile();
method @FlaggedApi("com.android.internal.camera.flags.concert_mode") public int getImageFormat();
method @FlaggedApi("com.android.internal.camera.flags.concert_mode") @NonNull public android.util.Size getSize();
method @FlaggedApi("com.android.internal.camera.flags.concert_mode") @NonNull public android.view.Surface getSurface();
- method @FlaggedApi("com.android.internal.camera.flags.extension_10_bit") public void setDynamicRangeProfile(long);
+ method public void setDynamicRangeProfile(long);
}
@FlaggedApi("com.android.internal.camera.flags.concert_mode") public class CharacteristicsMap {
@@ -4987,7 +4987,7 @@
@FlaggedApi("com.android.internal.camera.flags.concert_mode") public class ExtensionConfiguration {
ctor @FlaggedApi("com.android.internal.camera.flags.concert_mode") public ExtensionConfiguration(int, int, @NonNull java.util.List<android.hardware.camera2.extension.ExtensionOutputConfiguration>, @Nullable android.hardware.camera2.CaptureRequest);
- method @FlaggedApi("com.android.internal.camera.flags.extension_10_bit") public void setColorSpace(int);
+ method public void setColorSpace(int);
}
@FlaggedApi("com.android.internal.camera.flags.concert_mode") public class ExtensionOutputConfiguration {
diff --git a/core/java/android/app/Instrumentation.java b/core/java/android/app/Instrumentation.java
index 45852c7..93a9489 100644
--- a/core/java/android/app/Instrumentation.java
+++ b/core/java/android/app/Instrumentation.java
@@ -2408,9 +2408,9 @@
* @hide
*/
@android.ravenwood.annotation.RavenwoodKeep
- public final void basicInit(Context context) {
- mInstrContext = context;
- mAppContext = context;
+ public final void basicInit(Context instrContext, Context appContext) {
+ mInstrContext = instrContext;
+ mAppContext = appContext;
}
/** @hide */
diff --git a/core/java/android/app/SystemServiceRegistry.java b/core/java/android/app/SystemServiceRegistry.java
index 5147f12..337939f 100644
--- a/core/java/android/app/SystemServiceRegistry.java
+++ b/core/java/android/app/SystemServiceRegistry.java
@@ -593,6 +593,11 @@
@Override
public TextServicesManager createService(ContextImpl ctx)
throws ServiceNotFoundException {
+ if (ctx.getPackageManager().hasSystemFeature(PackageManager.FEATURE_WATCH)
+ && ServiceManager.getService(Context.TEXT_SERVICES_MANAGER_SERVICE) == null
+ && android.server.Flags.removeTextService()) {
+ return null;
+ }
return TextServicesManager.createInstance(ctx);
}});
@@ -1887,6 +1892,12 @@
return null;
}
break;
+ case Context.TEXT_SERVICES_MANAGER_SERVICE:
+ if (android.server.Flags.removeTextService()
+ && hasSystemFeatureOpportunistic(ctx, PackageManager.FEATURE_WATCH)) {
+ return null;
+ }
+ break;
}
Slog.wtf(TAG, "Manager wrapper not available: " + name);
return null;
diff --git a/core/java/android/app/TEST_MAPPING b/core/java/android/app/TEST_MAPPING
index 2358d67..5ed1f4e 100644
--- a/core/java/android/app/TEST_MAPPING
+++ b/core/java/android/app/TEST_MAPPING
@@ -16,12 +16,7 @@
},
{
"file_patterns": ["(/|^)AppOpsManager.java"],
- "name": "CtsAppOpsTestCases",
- "options": [
- {
- "exclude-annotation": "androidx.test.filters.FlakyTest"
- }
- ]
+ "name": "CtsAppOpsTestCases"
},
{
"file_patterns": ["(/|^)AppOpsManager.java"],
@@ -54,12 +49,7 @@
"file_patterns": ["INotificationManager\\.aidl"]
},
{
- "name": "CtsWindowManagerDeviceWindow",
- "options": [
- {
- "include-filter": "android.server.wm.window.ToastWindowTest"
- }
- ],
+ "name": "CtsWindowManagerDeviceWindow_window_toastwindowtest",
"file_patterns": ["INotificationManager\\.aidl"]
},
{
@@ -67,42 +57,15 @@
"file_patterns": ["(/|^)InstantAppResolve[^/]*"]
},
{
- "name": "CtsAutoFillServiceTestCases",
- "options": [
- {
- "include-filter": "android.autofillservice.cts.saveui.AutofillSaveDialogTest"
- },
- {
- "exclude-annotation": "androidx.test.filters.FlakyTest"
- }
- ],
+ "name": "CtsAutoFillServiceTestCases_saveui_autofillsavedialogtest",
"file_patterns": ["(/|^)Activity.java"]
},
{
- "name": "CtsAutoFillServiceTestCases",
- "options": [
- {
- "include-filter": "android.autofillservice.cts.saveui.PreSimpleSaveActivityTest"
- },
- {
- "exclude-annotation": "androidx.test.filters.FlakyTest"
- }
- ],
+ "name": "CtsAutoFillServiceTestCases_saveui_presimplesaveactivitytest",
"file_patterns": ["(/|^)Activity.java"]
},
{
- "name": "CtsAutoFillServiceTestCases",
- "options": [
- {
- "include-filter": "android.autofillservice.cts.saveui.SimpleSaveActivityTest"
- },
- {
- "exclude-annotation": "androidx.test.filters.FlakyTest"
- },
- {
- "exclude-annotation": "android.platform.test.annotations.AppModeFull"
- }
- ],
+ "name": "CtsAutoFillServiceTestCases_saveui_simplesaveactivitytest",
"file_patterns": ["(/|^)Activity.java"]
},
{
@@ -119,32 +82,10 @@
},
{
"name": "CtsLocalVoiceInteraction",
- "options": [
- {
- "exclude-annotation": "androidx.test.filters.FlakyTest"
- }
- ],
"file_patterns": ["(/|^)VoiceInteract[^/]*"]
},
{
- "name": "CtsOsTestCases",
- "options": [
- {
- "include-annotation": "android.platform.test.annotations.Presubmit"
- },
- {
- "exclude-annotation": "androidx.test.filters.LargeTest"
- },
- {
- "exclude-annotation": "androidx.test.filters.FlakyTest"
- },
- {
- "exclude-annotation": "org.junit.Ignore"
- },
- {
- "include-filter": "android.os.cts.StrictModeTest"
- }
- ],
+ "name": "CtsOsTestCases_cts_strictmodetest_Presubmit",
"file_patterns": ["(/|^)ContextImpl.java"]
},
{
@@ -153,12 +94,7 @@
},
{
"file_patterns": ["(/|^)LocaleManager.java"],
- "name": "CtsLocaleManagerTestCases",
- "options": [
- {
- "exclude-annotation": "androidx.test.filters.FlakyTest"
- }
- ]
+ "name": "CtsLocaleManagerTestCases"
},
{
"name": "FrameworksCoreTests_keyguard_manager",
@@ -173,172 +109,51 @@
]
},
{
- "name": "FrameworksCoreGameManagerTests",
- "options": [
- {
- "exclude-annotation": "androidx.test.filters.FlakyTest"
- },
- {
- "exclude-annotation": "org.junit.Ignore"
- },
- {
- "include-filter": "android.app"
- }
- ],
+ "name": "FrameworksCoreGameManagerTests_android_app",
"file_patterns": [
"(/|^)GameManager[^/]*", "(/|^)GameMode[^/]*"
]
},
{
- "name": "HdmiCecTests",
- "options": [
- {
- "exclude-annotation": "androidx.test.filters.FlakyTest"
- },
- {
- "exclude-annotation": "org.junit.Ignore"
- },
- {
- "include-filter": "android.hardware.hdmi"
- }
- ],
+ "name": "HdmiCecTests_hardware_hdmi",
"file_patterns": [
"(/|^)DeviceFeature[^/]*", "(/|^)Hdmi[^/]*"
]
},
{
- "name": "CtsWindowManagerDeviceActivity",
- "options": [
- {
- "exclude-annotation": "androidx.test.filters.FlakyTest"
- },
- {
- "exclude-annotation": "org.junit.Ignore"
- },
- {
- "include-filter": "android.content.wm.cts"
- }
- ],
+ "name": "CtsWindowManagerDeviceActivity_wm_cts",
"file_patterns": ["(/|^)ContextImpl.java"]
},
{
- "name": "CtsWindowManagerDeviceAm",
- "options": [
- {
- "exclude-annotation": "androidx.test.filters.FlakyTest"
- },
- {
- "exclude-annotation": "org.junit.Ignore"
- },
- {
- "include-filter": "android.content.wm.cts"
- }
- ],
+ "name": "CtsWindowManagerDeviceAm_wm_cts",
"file_patterns": ["(/|^)ContextImpl.java"]
},
{
- "name": "CtsWindowManagerDeviceBackNavigation",
- "options": [
- {
- "exclude-annotation": "androidx.test.filters.FlakyTest"
- },
- {
- "exclude-annotation": "org.junit.Ignore"
- },
- {
- "include-filter": "android.content.wm.cts"
- }
- ],
+ "name": "CtsWindowManagerDeviceBackNavigation_wm_cts",
"file_patterns": ["(/|^)ContextImpl.java"]
},
{
- "name": "CtsWindowManagerDeviceDisplay",
- "options": [
- {
- "exclude-annotation": "androidx.test.filters.FlakyTest"
- },
- {
- "exclude-annotation": "org.junit.Ignore"
- },
- {
- "include-filter": "android.content.wm.cts"
- }
- ],
+ "name": "CtsWindowManagerDeviceDisplay_wm_cts",
"file_patterns": ["(/|^)ContextImpl.java"]
},
{
- "name": "CtsWindowManagerDeviceKeyguard",
- "options": [
- {
- "exclude-annotation": "androidx.test.filters.FlakyTest"
- },
- {
- "exclude-annotation": "org.junit.Ignore"
- },
- {
- "include-filter": "android.content.wm.cts"
- }
- ],
+ "name": "CtsWindowManagerDeviceKeyguard_wm_cts",
"file_patterns": ["(/|^)ContextImpl.java"]
},
{
- "name": "CtsWindowManagerDeviceInsets",
- "options": [
- {
- "exclude-annotation": "androidx.test.filters.FlakyTest"
- },
- {
- "exclude-annotation": "org.junit.Ignore"
- },
- {
- "include-filter": "android.content.wm.cts"
- }
- ],
+ "name": "CtsWindowManagerDeviceInsets_wm_cts",
"file_patterns": ["(/|^)ContextImpl.java"]
},
{
- "name": "CtsWindowManagerDeviceTaskFragment",
- "options": [
- {
- "exclude-annotation": "androidx.test.filters.FlakyTest"
- },
- {
- "exclude-annotation": "org.junit.Ignore"
- },
- {
- "include-filter": "android.content.wm.cts"
- }
- ],
+ "name": "CtsWindowManagerDeviceTaskFragment_wm_cts",
"file_patterns": ["(/|^)ContextImpl.java"]
},
{
- "name": "CtsWindowManagerDeviceWindow",
- "options": [
- {
- "exclude-annotation": "androidx.test.filters.FlakyTest"
- },
- {
- "exclude-annotation": "org.junit.Ignore"
- },
- {
- "include-filter": "android.content.wm.cts"
- }
- ],
+ "name": "CtsWindowManagerDeviceWindow_wm_cts",
"file_patterns": ["(/|^)ContextImpl.java"]
},
{
- "name": "CtsWindowManagerDeviceOther",
- "options": [
- {
- "exclude-annotation": "androidx.test.filters.FlakyTest"
- },
- {
- "exclude-annotation": "org.junit.Ignore"
- },
- {
- "include-filter": "android.content.wm.cts"
- }
- ],
+ "name": "CtsWindowManagerDeviceOther_wm_cts",
"file_patterns": ["(/|^)ContextImpl.java"]
},
{
diff --git a/core/java/android/app/admin/flags/flags.aconfig b/core/java/android/app/admin/flags/flags.aconfig
index 081dfe6..48f0af4 100644
--- a/core/java/android/app/admin/flags/flags.aconfig
+++ b/core/java/android/app/admin/flags/flags.aconfig
@@ -323,3 +323,13 @@
purpose: PURPOSE_BUGFIX
}
}
+
+flag {
+ name: "user_provisioning_same_state"
+ namespace: "enterprise"
+ description: "Handle exceptions while setting same provisioning state."
+ bug: "326441417"
+ metadata {
+ purpose: PURPOSE_BUGFIX
+ }
+}
diff --git a/core/java/android/app/appfunctions/AppFunctionRuntimeMetadata.java b/core/java/android/app/appfunctions/AppFunctionRuntimeMetadata.java
index f5c5a11..36daaab 100644
--- a/core/java/android/app/appfunctions/AppFunctionRuntimeMetadata.java
+++ b/core/java/android/app/appfunctions/AppFunctionRuntimeMetadata.java
@@ -180,13 +180,8 @@
*
* @param packageName the name of the package that owns the function.
* @param functionId the id of the function.
- * @param staticMetadataQualifiedId the qualified static metadata id that this runtime
- * metadata refers to.
*/
- public Builder(
- @NonNull String packageName,
- @NonNull String functionId,
- @NonNull String staticMetadataQualifiedId) {
+ public Builder(@NonNull String packageName, @NonNull String functionId) {
super(
APP_FUNCTION_RUNTIME_NAMESPACE,
getDocumentIdForAppFunction(
@@ -198,7 +193,9 @@
// Set qualified id automatically
setPropertyString(
- PROPERTY_APP_FUNCTION_STATIC_METADATA_QUALIFIED_ID, staticMetadataQualifiedId);
+ PROPERTY_APP_FUNCTION_STATIC_METADATA_QUALIFIED_ID,
+ AppFunctionStaticMetadataHelper.getStaticMetadataQualifiedId(
+ packageName, functionId));
}
/**
diff --git a/core/java/android/app/time/TEST_MAPPING b/core/java/android/app/time/TEST_MAPPING
index 7673aca..9e41638 100644
--- a/core/java/android/app/time/TEST_MAPPING
+++ b/core/java/android/app/time/TEST_MAPPING
@@ -1,31 +1,13 @@
{
"presubmit": [
{
- "name": "FrameworksTimeCoreTests",
- "options": [
- {
- "include-filter": "android.app."
- }
- ]
+ "name": "FrameworksTimeCoreTests_android_app"
},
{
- "name": "CtsTimeTestCases",
- "options": [
- {
- "exclude-annotation": "androidx.test.filters.FlakyTest"
- }
- ]
+ "name": "CtsTimeTestCases"
},
{
- "name": "FrameworksTimeServicesTests",
- "options": [
- {
- "include-filter": "com.android.server.timezonedetector."
- },
- {
- "include-filter": "com.android.server.timedetector."
- }
- ]
+ "name": "FrameworksTimeServicesTests_time"
}
]
}
diff --git a/core/java/android/app/timedetector/TEST_MAPPING b/core/java/android/app/timedetector/TEST_MAPPING
index c7ca6a2..d876308 100644
--- a/core/java/android/app/timedetector/TEST_MAPPING
+++ b/core/java/android/app/timedetector/TEST_MAPPING
@@ -1,28 +1,13 @@
{
"presubmit": [
{
- "name": "FrameworksTimeCoreTests",
- "options": [
- {
- "include-filter": "android.app."
- }
- ]
+ "name": "FrameworksTimeCoreTests_android_app"
},
{
- "name": "CtsTimeTestCases",
- "options": [
- {
- "exclude-annotation": "androidx.test.filters.FlakyTest"
- }
- ]
+ "name": "CtsTimeTestCases"
},
{
- "name": "FrameworksTimeServicesTests",
- "options": [
- {
- "include-filter": "com.android.server.timedetector."
- }
- ]
+ "name": "FrameworksTimeServicesTests_server_timedetector"
}
]
}
diff --git a/core/java/android/app/timezonedetector/TEST_MAPPING b/core/java/android/app/timezonedetector/TEST_MAPPING
index c8d0bb2..dca7bbf 100644
--- a/core/java/android/app/timezonedetector/TEST_MAPPING
+++ b/core/java/android/app/timezonedetector/TEST_MAPPING
@@ -1,28 +1,13 @@
{
"presubmit": [
{
- "name": "FrameworksTimeCoreTests",
- "options": [
- {
- "include-filter": "android.app."
- }
- ]
+ "name": "FrameworksTimeCoreTests_android_app"
},
{
- "name": "CtsTimeTestCases",
- "options": [
- {
- "exclude-annotation": "androidx.test.filters.FlakyTest"
- }
- ]
+ "name": "CtsTimeTestCases"
},
{
- "name": "FrameworksTimeServicesTests",
- "options": [
- {
- "include-filter": "com.android.server.timezonedetector."
- }
- ]
+ "name": "FrameworksTimeServicesTests_server_timezonedetector"
}
]
}
diff --git a/core/java/android/app/trust/TEST_MAPPING b/core/java/android/app/trust/TEST_MAPPING
index 23923ee..b0dd551 100644
--- a/core/java/android/app/trust/TEST_MAPPING
+++ b/core/java/android/app/trust/TEST_MAPPING
@@ -1,28 +1,12 @@
{
"presubmit": [
{
- "name": "TrustTests",
- "options": [
- {
- "include-filter": "android.trust.test"
- },
- {
- "exclude-annotation": "androidx.test.filters.FlakyTest"
- }
- ]
+ "name": "TrustTests_trust_test"
}
],
"trust-tablet": [
{
- "name": "TrustTests",
- "options": [
- {
- "include-filter": "android.trust.test"
- },
- {
- "exclude-annotation": "androidx.test.filters.FlakyTest"
- }
- ]
+ "name": "TrustTests_trust_test"
}
]
}
\ No newline at end of file
diff --git a/core/java/android/content/TEST_MAPPING b/core/java/android/content/TEST_MAPPING
index e353a01..8d90b02 100644
--- a/core/java/android/content/TEST_MAPPING
+++ b/core/java/android/content/TEST_MAPPING
@@ -1,24 +1,7 @@
{
"presubmit": [
{
- "name": "CtsOsTestCases",
- "options": [
- {
- "include-annotation": "android.platform.test.annotations.Presubmit"
- },
- {
- "exclude-annotation": "androidx.test.filters.LargeTest"
- },
- {
- "exclude-annotation": "androidx.test.filters.FlakyTest"
- },
- {
- "exclude-annotation": "org.junit.Ignore"
- },
- {
- "include-filter": "android.os.cts.StrictModeTest"
- }
- ],
+ "name": "CtsOsTestCases_cts_strictmodetest_Presubmit",
"file_patterns": ["(/|^)Context.java", "(/|^)ContextWrapper.java"]
},
{
diff --git a/core/java/android/content/om/TEST_MAPPING b/core/java/android/content/om/TEST_MAPPING
index 82c47a0..b36c895 100644
--- a/core/java/android/content/om/TEST_MAPPING
+++ b/core/java/android/content/om/TEST_MAPPING
@@ -1,12 +1,7 @@
{
"presubmit": [
{
- "name": "FrameworksServicesTests",
- "options": [
- {
- "include-filter": "com.android.server.om"
- }
- ]
+ "name": "FrameworksServicesTests_server_om"
},
{
"name": "OverlayDeviceTests"
diff --git a/core/java/android/content/pm/verify/domain/TEST_MAPPING b/core/java/android/content/pm/verify/domain/TEST_MAPPING
index 8a1982a..db98c40 100644
--- a/core/java/android/content/pm/verify/domain/TEST_MAPPING
+++ b/core/java/android/content/pm/verify/domain/TEST_MAPPING
@@ -1,12 +1,7 @@
{
"presubmit": [
{
- "name": "PackageManagerServiceUnitTests",
- "options": [
- {
- "include-filter": "com.android.server.pm.test.verify.domain"
- }
- ]
+ "name": "PackageManagerServiceUnitTests_verify_domain"
},
{
"name": "CtsDomainVerificationDeviceStandaloneTestCases"
diff --git a/core/java/android/hardware/camera2/CameraCharacteristics.java b/core/java/android/hardware/camera2/CameraCharacteristics.java
index 056ca93..7a8a16f 100644
--- a/core/java/android/hardware/camera2/CameraCharacteristics.java
+++ b/core/java/android/hardware/camera2/CameraCharacteristics.java
@@ -567,7 +567,6 @@
* @see #INFO_SESSION_CONFIGURATION_QUERY_VERSION
*/
@NonNull
- @FlaggedApi(Flags.FLAG_FEATURE_COMBINATION_QUERY)
public List<CameraCharacteristics.Key<?>> getAvailableSessionCharacteristicsKeys() {
if (mAvailableSessionCharacteristicsKeys != null) {
return mAvailableSessionCharacteristicsKeys;
@@ -5210,7 +5209,6 @@
*/
@PublicKey
@NonNull
- @FlaggedApi(Flags.FLAG_FEATURE_COMBINATION_QUERY)
public static final Key<Integer> INFO_SESSION_CONFIGURATION_QUERY_VERSION =
new Key<Integer>("android.info.sessionConfigurationQueryVersion", int.class);
diff --git a/core/java/android/hardware/camera2/extension/CameraOutputSurface.java b/core/java/android/hardware/camera2/extension/CameraOutputSurface.java
index 001b794..32139b8 100644
--- a/core/java/android/hardware/camera2/extension/CameraOutputSurface.java
+++ b/core/java/android/hardware/camera2/extension/CameraOutputSurface.java
@@ -107,7 +107,6 @@
* {@link android.hardware.camera2.params.DynamicRangeProfiles.STANDARD}
* unless specified by CameraOutputSurface.setDynamicRangeProfile.
*/
- @FlaggedApi(Flags.FLAG_EXTENSION_10_BIT)
public @DynamicRangeProfiles.Profile long getDynamicRangeProfile() {
return mOutputSurface.dynamicRangeProfile;
}
@@ -118,7 +117,6 @@
* unless specified by CameraOutputSurface.setColorSpace.
*/
@SuppressLint("MethodNameUnits")
- @FlaggedApi(Flags.FLAG_EXTENSION_10_BIT)
public int getColorSpace() {
return mOutputSurface.colorSpace;
}
@@ -128,7 +126,6 @@
* will be {@link android.hardware.camera2.params.DynamicRangeProfiles.STANDARD}
* unless explicitly set using this method.
*/
- @FlaggedApi(Flags.FLAG_EXTENSION_10_BIT)
public void setDynamicRangeProfile(
@DynamicRangeProfiles.Profile long dynamicRangeProfile) {
mOutputSurface.dynamicRangeProfile = dynamicRangeProfile;
diff --git a/core/java/android/hardware/camera2/extension/ExtensionConfiguration.java b/core/java/android/hardware/camera2/extension/ExtensionConfiguration.java
index 84b7a7f..32de1ce 100644
--- a/core/java/android/hardware/camera2/extension/ExtensionConfiguration.java
+++ b/core/java/android/hardware/camera2/extension/ExtensionConfiguration.java
@@ -83,7 +83,6 @@
* The default will be -1, indicating an unspecified ColorSpace,
* unless explicitly set using this method.
*/
- @FlaggedApi(Flags.FLAG_EXTENSION_10_BIT)
public void setColorSpace(int colorSpace) {
mColorSpace = colorSpace;
}
@@ -98,11 +97,7 @@
ret.sessionTemplateId = mSessionTemplateId;
ret.sessionType = mSessionType;
ret.outputConfigs = new ArrayList<>(mOutputs.size());
- if (Flags.extension10Bit()) {
- ret.colorSpace = mColorSpace;
- } else {
- ret.colorSpace = ColorSpaceProfiles.UNSPECIFIED;
- }
+ ret.colorSpace = mColorSpace;
for (ExtensionOutputConfiguration outputConfig : mOutputs) {
ret.outputConfigs.add(outputConfig.getOutputConfig());
}
diff --git a/core/java/android/hardware/camera2/extension/ExtensionOutputConfiguration.java b/core/java/android/hardware/camera2/extension/ExtensionOutputConfiguration.java
index 3a67d61..8a47430 100644
--- a/core/java/android/hardware/camera2/extension/ExtensionOutputConfiguration.java
+++ b/core/java/android/hardware/camera2/extension/ExtensionOutputConfiguration.java
@@ -80,11 +80,7 @@
config.outputId = new OutputConfigId();
config.outputId.id = mOutputConfigId;
config.surfaceGroupId = mSurfaceGroupId;
- if (Flags.extension10Bit()) {
- config.dynamicRangeProfile = surface.getDynamicRangeProfile();
- } else {
- config.dynamicRangeProfile = DynamicRangeProfiles.STANDARD;
- }
+ config.dynamicRangeProfile = surface.getDynamicRangeProfile();
}
@Nullable CameraOutputConfig getOutputConfig() {
diff --git a/core/java/android/hardware/camera2/impl/CameraAdvancedExtensionSessionImpl.java b/core/java/android/hardware/camera2/impl/CameraAdvancedExtensionSessionImpl.java
index 2e1e90c..323712d 100644
--- a/core/java/android/hardware/camera2/impl/CameraAdvancedExtensionSessionImpl.java
+++ b/core/java/android/hardware/camera2/impl/CameraAdvancedExtensionSessionImpl.java
@@ -148,7 +148,7 @@
for (OutputConfiguration c : config.getOutputConfigurations()) {
if (c.getDynamicRangeProfile() != DynamicRangeProfiles.STANDARD) {
- if (Flags.extension10Bit() && Flags.cameraExtensionsCharacteristicsGet()) {
+ if (Flags.cameraExtensionsCharacteristicsGet()) {
DynamicRangeProfiles dynamicProfiles = extensionChars.get(
config.getExtension(),
CameraCharacteristics.REQUEST_AVAILABLE_DYNAMIC_RANGE_PROFILES);
@@ -190,9 +190,7 @@
new IntArray(CameraExtensionUtils.SUPPORTED_CAPTURE_OUTPUT_FORMATS.length);
supportedCaptureOutputFormats.addAll(
CameraExtensionUtils.SUPPORTED_CAPTURE_OUTPUT_FORMATS);
- if (Flags.extension10Bit()) {
- supportedCaptureOutputFormats.add(ImageFormat.YCBCR_P010);
- }
+ supportedCaptureOutputFormats.add(ImageFormat.YCBCR_P010);
for (int format : supportedCaptureOutputFormats.toArray()) {
List<Size> supportedSizes = extensionChars.getExtensionSupportedSizes(
config.getExtension(), format);
@@ -359,22 +357,20 @@
cameraOutput.setTimestampBase(OutputConfiguration.TIMESTAMP_BASE_SENSOR);
cameraOutput.setReadoutTimestampEnabled(false);
cameraOutput.setPhysicalCameraId(output.physicalCameraId);
- if (Flags.extension10Bit()) {
- boolean validDynamicRangeProfile = false;
- for (long profile = DynamicRangeProfiles.STANDARD;
- profile < DynamicRangeProfiles.PUBLIC_MAX; profile <<= 1) {
- if (output.dynamicRangeProfile == profile) {
- validDynamicRangeProfile = true;
- break;
- }
+ boolean validDynamicRangeProfile = false;
+ for (long profile = DynamicRangeProfiles.STANDARD;
+ profile < DynamicRangeProfiles.PUBLIC_MAX; profile <<= 1) {
+ if (output.dynamicRangeProfile == profile) {
+ validDynamicRangeProfile = true;
+ break;
}
- if (validDynamicRangeProfile) {
- cameraOutput.setDynamicRangeProfile(output.dynamicRangeProfile);
- } else {
- Log.e(TAG, "Extension configured dynamic range profile "
- + output.dynamicRangeProfile
- + " is not valid, using default DynamicRangeProfile.STANDARD");
- }
+ }
+ if (validDynamicRangeProfile) {
+ cameraOutput.setDynamicRangeProfile(output.dynamicRangeProfile);
+ } else {
+ Log.e(TAG, "Extension configured dynamic range profile "
+ + output.dynamicRangeProfile
+ + " is not valid, using default DynamicRangeProfile.STANDARD");
}
outputList.add(cameraOutput);
mCameraConfigMap.put(cameraOutput.getSurface(), output);
@@ -390,15 +386,13 @@
SessionConfiguration sessionConfiguration = new SessionConfiguration(sessionType,
outputList, new CameraExtensionUtils.HandlerExecutor(mHandler),
new SessionStateHandler());
- if (Flags.extension10Bit()) {
- if (sessionConfig.colorSpace >= 0
- && sessionConfig.colorSpace < ColorSpace.Named.values().length) {
- sessionConfiguration.setColorSpace(
- ColorSpace.Named.values()[sessionConfig.colorSpace]);
- } else {
- Log.e(TAG, "Extension configured color space " + sessionConfig.colorSpace
- + " is not valid, using default unspecified color space");
- }
+ if (sessionConfig.colorSpace >= 0
+ && sessionConfig.colorSpace < ColorSpace.Named.values().length) {
+ sessionConfiguration.setColorSpace(
+ ColorSpace.Named.values()[sessionConfig.colorSpace]);
+ } else {
+ Log.e(TAG, "Extension configured color space " + sessionConfig.colorSpace
+ + " is not valid, using default unspecified color space");
}
if ((sessionConfig.sessionParameter != null) &&
(!sessionConfig.sessionParameter.isEmpty())) {
@@ -459,16 +453,11 @@
ret.size.height = surfaceSize.getHeight();
ret.imageFormat = SurfaceUtils.getSurfaceFormat(s);
- if (Flags.extension10Bit()) {
- ret.dynamicRangeProfile = o.getDynamicRangeProfile();
- ColorSpace colorSpace = o.getColorSpace();
- if (colorSpace != null) {
- ret.colorSpace = colorSpace.getId();
- } else {
- ret.colorSpace = ColorSpaceProfiles.UNSPECIFIED;
- }
+ ret.dynamicRangeProfile = o.getDynamicRangeProfile();
+ ColorSpace colorSpace = o.getColorSpace();
+ if (colorSpace != null) {
+ ret.colorSpace = colorSpace.getId();
} else {
- ret.dynamicRangeProfile = DynamicRangeProfiles.STANDARD;
ret.colorSpace = ColorSpaceProfiles.UNSPECIFIED;
}
} else {
diff --git a/core/java/android/hardware/camera2/impl/CameraExtensionJpegProcessor.java b/core/java/android/hardware/camera2/impl/CameraExtensionJpegProcessor.java
index a10e250..ab4ff72 100644
--- a/core/java/android/hardware/camera2/impl/CameraExtensionJpegProcessor.java
+++ b/core/java/android/hardware/camera2/impl/CameraExtensionJpegProcessor.java
@@ -208,10 +208,6 @@
}
public void onOutputSurface(Surface surface, int format) throws RemoteException {
- if (!Flags.extension10Bit() && format != ImageFormat.JPEG) {
- Log.e(TAG, "Unsupported output format: " + format);
- return;
- }
CameraExtensionUtils.SurfaceInfo surfaceInfo = CameraExtensionUtils.querySurface(surface);
mCaptureFormat = surfaceInfo.mFormat;
mOutputSurface = surface;
@@ -221,10 +217,6 @@
public void onPostviewOutputSurface(Surface surface) throws RemoteException {
CameraExtensionUtils.SurfaceInfo postviewSurfaceInfo =
CameraExtensionUtils.querySurface(surface);
- if (!Flags.extension10Bit() && postviewSurfaceInfo.mFormat != ImageFormat.JPEG) {
- Log.e(TAG, "Unsupported output format: " + postviewSurfaceInfo.mFormat);
- return;
- }
mPostviewFormat = postviewSurfaceInfo.mFormat;
mPostviewOutputSurface = surface;
initializePostviewPipeline();
@@ -240,10 +232,6 @@
}
public void onImageFormatUpdate(int format) throws RemoteException {
- if (!Flags.extension10Bit() && format != ImageFormat.YUV_420_888) {
- Log.e(TAG, "Unsupported input format: " + format);
- return;
- }
mFormat = format;
initializePipeline();
}
@@ -251,7 +239,7 @@
private void initializePipeline() throws RemoteException {
if ((mFormat != -1) && (mOutputSurface != null) && (mResolution != null) &&
(mYuvReader == null)) {
- if (Flags.extension10Bit() && mCaptureFormat == ImageFormat.YUV_420_888) {
+ if (mCaptureFormat == ImageFormat.YUV_420_888) {
// For the case when postview is JPEG and capture is YUV
mProcessor.onOutputSurface(mOutputSurface, mCaptureFormat);
} else {
@@ -274,7 +262,7 @@
private void initializePostviewPipeline() throws RemoteException {
if ((mFormat != -1) && (mPostviewOutputSurface != null) && (mPostviewResolution != null)
&& (mPostviewYuvReader == null)) {
- if (Flags.extension10Bit() && mPostviewFormat == ImageFormat.YUV_420_888) {
+ if (mPostviewFormat == ImageFormat.YUV_420_888) {
// For the case when postview is YUV and capture is JPEG
mProcessor.onPostviewOutputSurface(mPostviewOutputSurface);
} else {
diff --git a/core/java/android/hardware/camera2/impl/CameraExtensionSessionImpl.java b/core/java/android/hardware/camera2/impl/CameraExtensionSessionImpl.java
index a4ae398..ce1609d 100644
--- a/core/java/android/hardware/camera2/impl/CameraExtensionSessionImpl.java
+++ b/core/java/android/hardware/camera2/impl/CameraExtensionSessionImpl.java
@@ -190,9 +190,7 @@
new IntArray(CameraExtensionUtils.SUPPORTED_CAPTURE_OUTPUT_FORMATS.length);
supportedCaptureOutputFormats.addAll(
CameraExtensionUtils.SUPPORTED_CAPTURE_OUTPUT_FORMATS);
- if (Flags.extension10Bit()) {
- supportedCaptureOutputFormats.add(ImageFormat.YCBCR_P010);
- }
+ supportedCaptureOutputFormats.add(ImageFormat.YCBCR_P010);
for (int format : supportedCaptureOutputFormats.toArray()) {
List<Size> supportedSizes = extensionChars.getExtensionSupportedSizes(
config.getExtension(), format);
@@ -401,7 +399,7 @@
if (surfaceInfo.mFormat == ImageFormat.JPEG) {
mImageJpegProcessor = new CameraExtensionJpegProcessor(mImageProcessor);
mImageProcessor = mImageJpegProcessor;
- } else if (Flags.extension10Bit() && mClientPostviewSurface != null) {
+ } else if (mClientPostviewSurface != null) {
// Handles case when postview is JPEG and capture is YUV
CameraExtensionUtils.SurfaceInfo postviewSurfaceInfo =
CameraExtensionUtils.querySurface(mClientPostviewSurface);
diff --git a/core/java/android/hardware/camera2/impl/CameraExtensionUtils.java b/core/java/android/hardware/camera2/impl/CameraExtensionUtils.java
index 40f0477..f91d277 100644
--- a/core/java/android/hardware/camera2/impl/CameraExtensionUtils.java
+++ b/core/java/android/hardware/camera2/impl/CameraExtensionUtils.java
@@ -113,32 +113,13 @@
SurfaceInfo surfaceInfo = querySurface(outputConfig.getSurface());
- if (Flags.extension10Bit()) {
- Size postviewSize = new Size(surfaceInfo.mWidth, surfaceInfo.mHeight);
- if (supportedPostviewSizes.get(surfaceInfo.mFormat)
- .contains(postviewSize)) {
- return outputConfig.getSurface();
- } else {
- throw new IllegalArgumentException("Postview size not supported!");
- }
+ Size postviewSize = new Size(surfaceInfo.mWidth, surfaceInfo.mHeight);
+ if (supportedPostviewSizes.get(surfaceInfo.mFormat)
+ .contains(postviewSize)) {
+ return outputConfig.getSurface();
} else {
- if (surfaceInfo.mFormat == captureFormat) {
- if (supportedPostviewSizes.containsKey(captureFormat)) {
- Size postviewSize = new Size(surfaceInfo.mWidth, surfaceInfo.mHeight);
- if (supportedPostviewSizes.get(surfaceInfo.mFormat)
- .contains(postviewSize)) {
- return outputConfig.getSurface();
- } else {
- throw new IllegalArgumentException("Postview size not supported!");
- }
- }
- } else {
- throw new IllegalArgumentException("Postview format should be equivalent to "
- + " the capture format!");
- }
+ throw new IllegalArgumentException("Postview size not supported!");
}
-
- return null;
}
public static Surface getBurstCaptureSurface(
@@ -148,9 +129,7 @@
new IntArray(CameraExtensionUtils.SUPPORTED_CAPTURE_OUTPUT_FORMATS.length);
supportedCaptureOutputFormats.addAll(
CameraExtensionUtils.SUPPORTED_CAPTURE_OUTPUT_FORMATS);
- if (Flags.extension10Bit()) {
- supportedCaptureOutputFormats.add(ImageFormat.YCBCR_P010);
- }
+ supportedCaptureOutputFormats.add(ImageFormat.YCBCR_P010);
for (OutputConfiguration config : outputConfigs) {
SurfaceInfo surfaceInfo = querySurface(config.getSurface());
for (int supportedFormat : supportedCaptureOutputFormats.toArray()) {
diff --git a/core/java/android/hardware/camera2/params/ExtensionSessionConfiguration.java b/core/java/android/hardware/camera2/params/ExtensionSessionConfiguration.java
index bf3f59f..73f4ff4 100644
--- a/core/java/android/hardware/camera2/params/ExtensionSessionConfiguration.java
+++ b/core/java/android/hardware/camera2/params/ExtensionSessionConfiguration.java
@@ -136,7 +136,6 @@
* or the color space implied by the dataSpace passed into an {@link ImageReader}'s
* constructor.</p>
*/
- @FlaggedApi(Flags.FLAG_EXTENSION_10_BIT)
public void setColorSpace(@NonNull ColorSpace.Named colorSpace) {
mColorSpace = colorSpace.ordinal();
for (OutputConfiguration outputConfiguration : mOutputs) {
@@ -150,7 +149,6 @@
/**
* Clear the color space, such that the default color space will be used.
*/
- @FlaggedApi(Flags.FLAG_EXTENSION_10_BIT)
public void clearColorSpace() {
mColorSpace = ColorSpaceProfiles.UNSPECIFIED;
for (OutputConfiguration outputConfiguration : mOutputs) {
@@ -167,7 +165,6 @@
* @return the currently set color space, or null
* if not set
*/
- @FlaggedApi(Flags.FLAG_EXTENSION_10_BIT)
@SuppressLint("MethodNameUnits")
public @Nullable ColorSpace getColorSpace() {
if (mColorSpace != ColorSpaceProfiles.UNSPECIFIED) {
diff --git a/core/java/android/net/TEST_MAPPING b/core/java/android/net/TEST_MAPPING
index 3df5616..ea509bb 100644
--- a/core/java/android/net/TEST_MAPPING
+++ b/core/java/android/net/TEST_MAPPING
@@ -19,21 +19,7 @@
],
"presubmit": [
{
- "name": "FrameworksCoreTests",
- "options": [
- {
- "include-filter": "android.net"
- },
- {
- "include-annotation": "android.platform.test.annotations.Presubmit"
- },
- {
- "exclude-annotation": "androidx.test.filters.FlakyTest"
- },
- {
- "exclude-annotation": "org.junit.Ignore"
- }
- ]
+ "name": "FrameworksCoreTests_android_net"
}
]
}
diff --git a/core/java/android/os/TEST_MAPPING b/core/java/android/os/TEST_MAPPING
index 728db27..effe555 100644
--- a/core/java/android/os/TEST_MAPPING
+++ b/core/java/android/os/TEST_MAPPING
@@ -38,33 +38,15 @@
},
{
"file_patterns": ["Bugreport[^/]*\\.java"],
- "name": "BugreportManagerTestCases",
- "options": [
- {
- "exclude-annotation": "androidx.test.filters.LargeTest"
- }
- ]
+ "name": "BugreportManagerTestCases_android_server_os"
},
{
"file_patterns": ["Bugreport[^/]*\\.java"],
- "name": "CtsBugreportTestCases",
- "options": [
- {
- "exclude-annotation": "androidx.test.filters.LargeTest"
- }
- ]
+ "name": "CtsBugreportTestCases_android_server_os"
},
{
"file_patterns": ["Bugreport[^/]*\\.java"],
- "name": "ShellTests",
- "options": [
- {
- "exclude-annotation": "androidx.test.filters.LargeTest"
- },
- {
- "exclude-annotation": "androidx.test.filters.FlakyTest"
- }
- ]
+ "name": "ShellTests_android_server_os"
},
{
"file_patterns": [
@@ -99,12 +81,7 @@
"Parcel\\.java",
"[^/]*Bundle[^/]*\\.java"
],
- "name": "FrameworksMockingCoreTests",
- "options": [
- { "include-filter": "android.os.BundleRecyclingTest"},
- { "exclude-annotation": "androidx.test.filters.FlakyTest" },
- { "exclude-annotation": "org.junit.Ignore" }
- ]
+ "name": "FrameworksMockingCoreTests_os_bundlerecyclingtest"
},
{
"file_patterns": [
@@ -116,12 +93,7 @@
},
{
"file_patterns": ["SharedMemory[^/]*\\.java"],
- "name": "CtsOsTestCases",
- "options": [
- {
- "include-filter": "android.os.cts.SharedMemoryTest"
- }
- ]
+ "name": "CtsOsTestCases_cts_sharedmemorytest"
},
{
"file_patterns": ["Environment[^/]*\\.java"],
diff --git a/core/java/android/permission/TEST_MAPPING b/core/java/android/permission/TEST_MAPPING
index b317b80..3e5a131 100644
--- a/core/java/android/permission/TEST_MAPPING
+++ b/core/java/android/permission/TEST_MAPPING
@@ -6,26 +6,10 @@
],
"postsubmit": [
{
- "name": "CtsVirtualDevicesAudioTestCases",
- "options": [
- {
- "exclude-annotation": "androidx.test.filters.FlakyTest"
- },
- {
- "include-filter": "android.virtualdevice.cts.audio.VirtualAudioPermissionTest"
- }
- ]
+ "name": "CtsVirtualDevicesAudioTestCases_audio_virtualaudiopermissiontest"
},
{
- "name": "CtsVirtualDevicesAppLaunchTestCases",
- "options": [
- {
- "exclude-annotation": "androidx.test.filters.FlakyTest"
- },
- {
- "include-filter": "android.virtualdevice.cts.applaunch.VirtualDevicePermissionTest"
- }
- ]
+ "name": "CtsVirtualDevicesAppLaunchTestCases_applaunch_virtualdevicepermissiontest"
}
]
}
diff --git a/core/java/android/print/TEST_MAPPING b/core/java/android/print/TEST_MAPPING
index 4fa8822..1033b1a 100644
--- a/core/java/android/print/TEST_MAPPING
+++ b/core/java/android/print/TEST_MAPPING
@@ -1,12 +1,7 @@
{
"presubmit": [
{
- "name": "CtsPrintTestCases",
- "options": [
- {
- "include-annotation": "android.platform.test.annotations.Presubmit"
- }
- ]
+ "name": "CtsPrintTestCases_Presubmit"
}
]
}
diff --git a/core/java/android/provider/TEST_MAPPING b/core/java/android/provider/TEST_MAPPING
index 2eb285d..a6fe301 100644
--- a/core/java/android/provider/TEST_MAPPING
+++ b/core/java/android/provider/TEST_MAPPING
@@ -24,12 +24,7 @@
"name": "SettingsProviderTest"
},
{
- "name": "CtsPackageManagerHostTestCases",
- "options": [
- {
- "include-filter": "android.appsecurity.cts.ReadableSettingsFieldsTest"
- }
- ]
+ "name": "CtsPackageManagerHostTestCases_cts_readablesettingsfieldstest"
}
],
"postsubmit": [
diff --git a/core/java/android/security/TEST_MAPPING b/core/java/android/security/TEST_MAPPING
index 5a679b1..e1c7f3c 100644
--- a/core/java/android/security/TEST_MAPPING
+++ b/core/java/android/security/TEST_MAPPING
@@ -1,12 +1,7 @@
{
"presubmit": [
{
- "name": "CtsSecurityTestCases",
- "options": [
- {
- "include-filter": "android.security.cts.FileIntegrityManagerTest"
- }
- ],
+ "name": "CtsSecurityTestCases_cts_fileintegritymanagertest",
"file_patterns": [
"FileIntegrityManager\\.java",
"IFileIntegrityService\\.aidl"
diff --git a/core/java/android/security/attestationverification/AttestationVerificationManager.java b/core/java/android/security/attestationverification/AttestationVerificationManager.java
index 2e61db1..acf3382 100644
--- a/core/java/android/security/attestationverification/AttestationVerificationManager.java
+++ b/core/java/android/security/attestationverification/AttestationVerificationManager.java
@@ -322,6 +322,10 @@
/** Requirements bundle parameter for a challenge. */
public static final String PARAM_CHALLENGE = "localbinding.challenge";
+ /** Requirements bundle parameter for max patch level diff (int) for a peer device. **/
+ public static final String PARAM_MAX_PATCH_LEVEL_DIFF_MONTHS =
+ "param_max_patch_level_diff_months";
+
/** @hide */
public static String localBindingTypeToString(@LocalBindingType int localBindingType) {
final String text;
diff --git a/core/java/android/security/attestationverification/OWNERS b/core/java/android/security/attestationverification/OWNERS
index 80a1f44..15b9ce4 100644
--- a/core/java/android/security/attestationverification/OWNERS
+++ b/core/java/android/security/attestationverification/OWNERS
@@ -2,3 +2,6 @@
dlm@google.com
dkrahn@google.com
+guojing@google.com
+raphk@google.com
+yukl@google.com
\ No newline at end of file
diff --git a/core/java/android/service/notification/TEST_MAPPING b/core/java/android/service/notification/TEST_MAPPING
index 468c451..dc7129cd 100644
--- a/core/java/android/service/notification/TEST_MAPPING
+++ b/core/java/android/service/notification/TEST_MAPPING
@@ -1,32 +1,10 @@
{
"presubmit": [
{
- "name": "CtsNotificationTestCases",
- "options": [
- {
- "exclude-annotation": "androidx.test.filters.FlakyTest"
- },
- {
- "exclude-annotation": "org.junit.Ignore"
- },
- {
- "exclude-annotation": "androidx.test.filters.LargeTest"
- }
- ]
+ "name": "CtsNotificationTestCases_notification"
},
{
- "name": "FrameworksUiServicesTests",
- "options": [
- {
- "exclude-annotation": "androidx.test.filters.FlakyTest"
- },
- {
- "exclude-annotation": "org.junit.Ignore"
- },
- {
- "exclude-annotation": "androidx.test.filters.LargeTest"
- }
- ]
+ "name": "FrameworksUiServicesTests_notification"
}
],
"postsubmit": [
diff --git a/core/java/android/service/quicksettings/TEST_MAPPING b/core/java/android/service/quicksettings/TEST_MAPPING
index 2d45c5b2..986dc5f 100644
--- a/core/java/android/service/quicksettings/TEST_MAPPING
+++ b/core/java/android/service/quicksettings/TEST_MAPPING
@@ -1,15 +1,7 @@
{
"presubmit": [
{
- "name": "CtsTileServiceTestCases",
- "options": [
- {
- "exclude-annotation": "org.junit.Ignore"
- },
- {
- "exclude-annotation": "androidx.test.filters.FlakyTest"
- }
- ]
+ "name": "CtsTileServiceTestCases"
}
]
}
\ No newline at end of file
diff --git a/core/java/android/service/timezone/TEST_MAPPING b/core/java/android/service/timezone/TEST_MAPPING
index bf46ff2..2071717 100644
--- a/core/java/android/service/timezone/TEST_MAPPING
+++ b/core/java/android/service/timezone/TEST_MAPPING
@@ -1,12 +1,7 @@
{
"presubmit": [
{
- "name": "FrameworksTimeCoreTests",
- "options": [
- {
- "include-filter": "android.service."
- }
- ]
+ "name": "FrameworksTimeCoreTests_android_service"
},
{
"name": "CtsLocationTimeZoneManagerHostTest"
diff --git a/core/java/android/speech/TEST_MAPPING b/core/java/android/speech/TEST_MAPPING
index 7b125c2..cb490f5b 100644
--- a/core/java/android/speech/TEST_MAPPING
+++ b/core/java/android/speech/TEST_MAPPING
@@ -1,15 +1,7 @@
{
"presubmit": [
{
- "name": "CtsVoiceRecognitionTestCases",
- "options": [
- {
- "exclude-annotation": "org.junit.Ignore"
- },
- {
- "exclude-annotation": "androidx.test.filters.FlakyTest"
- }
- ]
+ "name": "CtsVoiceRecognitionTestCases"
}
]
}
diff --git a/core/java/android/text/TEST_MAPPING b/core/java/android/text/TEST_MAPPING
index c9bd2ca..9f8a72c 100644
--- a/core/java/android/text/TEST_MAPPING
+++ b/core/java/android/text/TEST_MAPPING
@@ -1,15 +1,7 @@
{
"presubmit": [
{
- "name": "CtsTextTestCases",
- "options": [
- {
- "exclude-annotation": "androidx.test.filters.FlakyTest"
- },
- {
- "exclude-annotation": "androidx.test.filters.LargeTest"
- }
- ]
+ "name": "CtsTextTestCases_text"
}
]
}
diff --git a/core/java/android/view/TEST_MAPPING b/core/java/android/view/TEST_MAPPING
index db35908..ac6cd02 100644
--- a/core/java/android/view/TEST_MAPPING
+++ b/core/java/android/view/TEST_MAPPING
@@ -4,39 +4,11 @@
"name": "CtsAccelerationTestCases"
},
{
- "name": "CtsOsTestCases",
- "options": [
- {
- "include-annotation": "android.platform.test.annotations.Presubmit"
- },
- {
- "exclude-annotation": "androidx.test.filters.LargeTest"
- },
- {
- "exclude-annotation": "androidx.test.filters.FlakyTest"
- },
- {
- "exclude-annotation": "org.junit.Ignore"
- },
- {
- "include-filter": "android.os.cts.StrictModeTest"
- }
- ],
+ "name": "CtsOsTestCases_cts_strictmodetest_Presubmit",
"file_patterns": ["(/|^)ViewConfiguration.java", "(/|^)GestureDetector.java"]
},
{
- "name": "CtsViewReceiveContentTestCases",
- "options": [
- {
- "include-annotation": "android.platform.test.annotations.Presubmit"
- },
- {
- "exclude-annotation": "androidx.test.filters.FlakyTest"
- },
- {
- "exclude-annotation": "org.junit.Ignore"
- }
- ],
+ "name": "CtsViewReceiveContentTestCases_Presubmit",
"file_patterns": ["ContentInfo\\.java", "OnReceiveContentListener\\.java", "View\\.java"]
}
],
diff --git a/core/java/android/view/WindowlessWindowManager.java b/core/java/android/view/WindowlessWindowManager.java
index d2747e4..5129461 100644
--- a/core/java/android/view/WindowlessWindowManager.java
+++ b/core/java/android/view/WindowlessWindowManager.java
@@ -587,7 +587,14 @@
@Override
public void updateRequestedVisibleTypes(IWindow window,
- @InsetsType int requestedVisibleTypes, @Nullable ImeTracker.Token imeStatsToken) {
+ @InsetsType int requestedVisibleTypes, @Nullable ImeTracker.Token imeStatsToken)
+ throws RemoteException {
+ if (android.view.inputmethod.Flags.refactorInsetsController()) {
+ // Embedded windows do not control insets (except for IME). The host window is
+ // responsible for controlling the insets.
+ mRealWm.updateRequestedVisibleTypes(window,
+ requestedVisibleTypes & WindowInsets.Type.ime(), imeStatsToken);
+ }
}
@Override
diff --git a/core/java/android/view/flags/scroll_feedback_flags.aconfig b/core/java/android/view/flags/scroll_feedback_flags.aconfig
index e9c85684..658aa29 100644
--- a/core/java/android/view/flags/scroll_feedback_flags.aconfig
+++ b/core/java/android/view/flags/scroll_feedback_flags.aconfig
@@ -21,4 +21,5 @@
name: "enable_touch_scroll_feedback"
description: "Enables touchscreen haptic scroll feedback"
bug: "331830899"
+ is_fixed_read_only: true
}
diff --git a/core/java/android/view/inputmethod/TEST_MAPPING b/core/java/android/view/inputmethod/TEST_MAPPING
index ad59463..989b686 100644
--- a/core/java/android/view/inputmethod/TEST_MAPPING
+++ b/core/java/android/view/inputmethod/TEST_MAPPING
@@ -1,21 +1,7 @@
{
"presubmit": [
{
- "name": "CtsAutoFillServiceTestCases",
- "options": [
- {
- "include-filter": "android.autofillservice.cts.inline"
- },
- {
- "exclude-annotation": "androidx.test.filters.FlakyTest"
- },
- {
- "exclude-annotation": "android.platform.test.annotations.AppModeFull"
- },
- {
- "exclude-annotation": "androidx.test.filters.LargeTest"
- }
- ]
+ "name": "CtsAutoFillServiceTestCases_cts_inline_ExcludeAppModeFull"
}
]
}
diff --git a/core/java/android/view/textclassifier/TEST_MAPPING b/core/java/android/view/textclassifier/TEST_MAPPING
index 050c651..bc7f3b0 100644
--- a/core/java/android/view/textclassifier/TEST_MAPPING
+++ b/core/java/android/view/textclassifier/TEST_MAPPING
@@ -4,20 +4,10 @@
"name": "FrameworksCoreTests_textclassifier"
},
{
- "name": "CtsTextClassifierTestCases",
- "options": [
- {
- "exclude-annotation": "androidx.test.filters.FlakyTest"
- }
- ]
+ "name": "CtsTextClassifierTestCases"
},
{
- "name": "TextClassifierServiceTest",
- "options": [
- {
- "exclude-annotation": "androidx.test.filters.FlakyTest"
- }
- ]
+ "name": "TextClassifierServiceTest"
}
]
}
diff --git a/core/java/android/webkit/TEST_MAPPING b/core/java/android/webkit/TEST_MAPPING
index 07f4383..3858059 100644
--- a/core/java/android/webkit/TEST_MAPPING
+++ b/core/java/android/webkit/TEST_MAPPING
@@ -1,28 +1,13 @@
{
"presubmit": [
{
- "name": "CtsWebkitTestCases",
- "options": [
- {
- "exclude-annotation": "androidx.test.filters.FlakyTest"
- }
- ]
+ "name": "CtsWebkitTestCases"
},
{
- "name": "CtsSdkSandboxWebkitTestCases",
- "options": [
- {
- "exclude-annotation": "androidx.test.filters.FlakyTest"
- }
- ]
+ "name": "CtsSdkSandboxWebkitTestCases"
},
{
- "name": "CtsHostsideWebViewTests",
- "options": [
- {
- "exclude-annotation": "androidx.test.filters.FlakyTest"
- }
- ]
+ "name": "CtsHostsideWebViewTests"
},
{
"name": "GtsWebViewTestCases",
diff --git a/core/java/android/webkit/WebViewZygote.java b/core/java/android/webkit/WebViewZygote.java
index c7900e4..668cd01 100644
--- a/core/java/android/webkit/WebViewZygote.java
+++ b/core/java/android/webkit/WebViewZygote.java
@@ -22,6 +22,7 @@
import android.os.Build;
import android.os.ChildZygoteProcess;
import android.os.Process;
+import android.os.UserHandle;
import android.os.ZygoteProcess;
import android.text.TextUtils;
import android.util.Log;
@@ -141,12 +142,14 @@
String abi = sPackage.applicationInfo.primaryCpuAbi;
int runtimeFlags = Zygote.getMemorySafetyRuntimeFlagsForSecondaryZygote(
sPackage.applicationInfo, null);
+ final int[] sharedAppGid = {
+ UserHandle.getSharedAppGid(UserHandle.getAppId(sPackage.applicationInfo.uid)) };
sZygote = Process.ZYGOTE_PROCESS.startChildZygote(
"com.android.internal.os.WebViewZygoteInit",
"webview_zygote",
Process.WEBVIEW_ZYGOTE_UID,
Process.WEBVIEW_ZYGOTE_UID,
- null, // gids
+ sharedAppGid, // Access to shared app GID for ART profiles
runtimeFlags,
"webview_zygote", // seInfo
abi, // abi
diff --git a/core/java/android/widget/TEST_MAPPING b/core/java/android/widget/TEST_MAPPING
index bc71bee..624fa86 100644
--- a/core/java/android/widget/TEST_MAPPING
+++ b/core/java/android/widget/TEST_MAPPING
@@ -10,52 +10,17 @@
"file_patterns": ["Toast\\.java"]
},
{
- "name": "CtsWindowManagerDeviceWindow",
- "options": [
- {
- "include-filter": "android.server.wm.window.ToastWindowTest"
- }
- ],
+ "name": "CtsWindowManagerDeviceWindow_window_toastwindowtest",
"file_patterns": ["Toast\\.java"]
},
{
- "name": "CtsAutoFillServiceTestCases",
- "options": [
- {
- "include-filter": "android.autofillservice.cts.dropdown.LoginActivityTest"
- },
- {
- "exclude-annotation": "androidx.test.filters.FlakyTest"
- },
- {
- "exclude-annotation": "android.platform.test.annotations.AppModeFull"
- }
- ]
+ "name": "CtsAutoFillServiceTestCases_dropdown_loginactivitytest"
},
{
- "name": "CtsAutoFillServiceTestCases",
- "options": [
- {
- "include-filter": "android.autofillservice.cts.dropdown.CheckoutActivityTest"
- },
- {
- "exclude-annotation": "androidx.test.filters.FlakyTest"
- },
- {
- "exclude-annotation": "android.platform.test.annotations.AppModeFull"
- }
- ]
+ "name": "CtsAutoFillServiceTestCases_dropdown_checkoutactivitytest"
},
{
- "name": "CtsTextTestCases",
- "options": [
- {
- "exclude-annotation": "androidx.test.filters.FlakyTest"
- },
- {
- "exclude-annotation": "androidx.test.filters.LargeTest"
- }
- ]
+ "name": "CtsTextTestCases_text"
}
]
}
diff --git a/core/java/android/widget/inline/TEST_MAPPING b/core/java/android/widget/inline/TEST_MAPPING
index 82c6f61..eb412f1 100644
--- a/core/java/android/widget/inline/TEST_MAPPING
+++ b/core/java/android/widget/inline/TEST_MAPPING
@@ -1,18 +1,7 @@
{
"presubmit-large": [
{
- "name": "CtsAutoFillServiceTestCases",
- "options": [
- {
- "include-filter": "android.autofillservice.cts.inline"
- },
- {
- "exclude-annotation": "androidx.test.filters.FlakyTest"
- },
- {
- "exclude-annotation": "androidx.test.filters.LargeTest"
- }
- ]
+ "name": "CtsAutoFillServiceTestCases_cts_inline"
}
]
}
diff --git a/core/java/android/window/flags/windowing_frontend.aconfig b/core/java/android/window/flags/windowing_frontend.aconfig
index 69b91fd..e1402f8 100644
--- a/core/java/android/window/flags/windowing_frontend.aconfig
+++ b/core/java/android/window/flags/windowing_frontend.aconfig
@@ -246,15 +246,6 @@
}
flag {
- name: "custom_animations_behind_translucent"
- namespace: "windowing_frontend"
- description: "A change can use its own layer parameters to animate behind a translucent activity"
- bug: "327332488"
- metadata {
- purpose: PURPOSE_BUGFIX
- }
-}
-flag {
name: "migrate_predictive_back_transition"
namespace: "windowing_frontend"
description: "Create transition when visibility change from predictive back"
@@ -274,4 +265,4 @@
metadata {
purpose: PURPOSE_BUGFIX
}
-}
\ No newline at end of file
+}
diff --git a/core/java/com/android/internal/infra/TEST_MAPPING b/core/java/com/android/internal/infra/TEST_MAPPING
index 35f0553..092aa20 100644
--- a/core/java/com/android/internal/infra/TEST_MAPPING
+++ b/core/java/com/android/internal/infra/TEST_MAPPING
@@ -1,12 +1,7 @@
{
"presubmit": [
{
- "name": "CtsRoleTestCases",
- "options": [
- {
- "exclude-annotation": "androidx.test.filters.FlakyTest"
- }
- ]
+ "name": "CtsRoleTestCases"
},
{
"name": "CtsPermissionTestCases_Platform"
diff --git a/core/java/com/android/internal/os/TEST_MAPPING b/core/java/com/android/internal/os/TEST_MAPPING
index 258f402..4400ed1 100644
--- a/core/java/com/android/internal/os/TEST_MAPPING
+++ b/core/java/com/android/internal/os/TEST_MAPPING
@@ -49,12 +49,7 @@
],
"postsubmit": [
{
- "name": "PowerStatsTests",
- "options": [
- {
- "include-filter": "com.android.server.power.stats.BstatsCpuTimesValidationTest"
- }
- ],
+ "name": "PowerStatsTests_stats_bstatscputimesvalidationtest",
"file_patterns": [
"Kernel[^/]*\\.java"
]
diff --git a/core/tests/coretests/src/android/content/pm/TEST_MAPPING b/core/tests/coretests/src/android/content/pm/TEST_MAPPING
index 9ab438e..b350d7d 100644
--- a/core/tests/coretests/src/android/content/pm/TEST_MAPPING
+++ b/core/tests/coretests/src/android/content/pm/TEST_MAPPING
@@ -6,21 +6,7 @@
],
"postsubmit": [
{
- "name": "FrameworksCoreTests",
- "options": [
- {
- "include-filter": "android.content.pm."
- },
- {
- "include-annotation": "android.platform.test.annotations.Postsubmit"
- },
- {
- "exclude-annotation": "androidx.test.filters.FlakyTest"
- },
- {
- "exclude-annotation": "org.junit.Ignore"
- }
- ]
+ "name": "FrameworksCoreTests_android_content_pm_PostSubmit"
}
]
}
diff --git a/core/tests/vibrator/TEST_MAPPING b/core/tests/vibrator/TEST_MAPPING
index 54a5ff1..d91b883 100644
--- a/core/tests/vibrator/TEST_MAPPING
+++ b/core/tests/vibrator/TEST_MAPPING
@@ -1,12 +1,7 @@
{
"presubmit": [
{
- "name": "FrameworksVibratorCoreTests",
- "options": [
- {"exclude-annotation": "androidx.test.filters.LargeTest"},
- {"exclude-annotation": "androidx.test.filters.FlakyTest"},
- {"exclude-annotation": "org.junit.Ignore"}
- ]
+ "name": "FrameworksVibratorCoreTests"
}
],
"postsubmit": [
diff --git a/graphics/TEST_MAPPING b/graphics/TEST_MAPPING
index 8afc30d..75cb87c 100644
--- a/graphics/TEST_MAPPING
+++ b/graphics/TEST_MAPPING
@@ -1,23 +1,10 @@
{
"presubmit": [
{
- "name": "CtsGraphicsTestCases",
- "options": [
- {
- "exclude-annotation": "androidx.test.filters.FlakyTest"
- }
- ]
+ "name": "CtsGraphicsTestCases"
},
{
- "name": "CtsTextTestCases",
- "options": [
- {
- "exclude-annotation": "androidx.test.filters.FlakyTest"
- },
- {
- "exclude-annotation": "androidx.test.filters.LargeTest"
- }
- ],
+ "name": "CtsTextTestCases_text",
"file_patterns": ["(/|^)Typeface\\.java", "(/|^)Paint\\.java"]
}
]
diff --git a/graphics/java/android/graphics/TEST_MAPPING b/graphics/java/android/graphics/TEST_MAPPING
index df91222..5cc31ba 100644
--- a/graphics/java/android/graphics/TEST_MAPPING
+++ b/graphics/java/android/graphics/TEST_MAPPING
@@ -1,15 +1,7 @@
{
"presubmit": [
{
- "name": "CtsTextTestCases",
- "options": [
- {
- "exclude-annotation": "androidx.test.filters.FlakyTest"
- },
- {
- "exclude-annotation": "androidx.test.filters.LargeTest"
- }
- ],
+ "name": "CtsTextTestCases_text",
"file_patterns": [
"Typeface\\.java",
"Paint\\.java",
diff --git a/graphics/java/android/graphics/drawable/TEST_MAPPING b/graphics/java/android/graphics/drawable/TEST_MAPPING
index 4f06452..da0a721 100644
--- a/graphics/java/android/graphics/drawable/TEST_MAPPING
+++ b/graphics/java/android/graphics/drawable/TEST_MAPPING
@@ -1,14 +1,8 @@
{
"presubmit": [
{
-
- "name": "CtsGraphicsTestCases",
- "file_patterns": ["(/|^)Icon\\.java"],
- "options" : [
- {
- "include-filter": "android.graphics.drawable.cts.IconTest"
- }
- ]
+ "name": "CtsGraphicsTestCases_cts_icontest",
+ "file_patterns": ["(/|^)Icon\\.java"]
},
{
diff --git a/graphics/java/android/graphics/fonts/TEST_MAPPING b/graphics/java/android/graphics/fonts/TEST_MAPPING
index 99cbfe7..9f8a72c 100644
--- a/graphics/java/android/graphics/fonts/TEST_MAPPING
+++ b/graphics/java/android/graphics/fonts/TEST_MAPPING
@@ -1,15 +1,7 @@
{
"presubmit": [
{
- "name": "CtsTextTestCases",
- "options": [
- {
- "exclude-annotation": "androidx.test.filters.FlakyTest"
- },
- {
- "exclude-annotation": "androidx.test.filters.LargeTest"
- }
- ]
+ "name": "CtsTextTestCases_text"
}
]
}
diff --git a/graphics/java/android/graphics/pdf/TEST_MAPPING b/graphics/java/android/graphics/pdf/TEST_MAPPING
index afec35c..8720b95 100644
--- a/graphics/java/android/graphics/pdf/TEST_MAPPING
+++ b/graphics/java/android/graphics/pdf/TEST_MAPPING
@@ -1,12 +1,7 @@
{
"presubmit": [
{
- "name": "CtsPdfTestCases",
- "options": [
- {
- "include-filter": "android.graphics.pdf.cts.PdfDocumentTest"
- }
- ]
+ "name": "CtsPdfTestCases_cts_pdfdocumenttest"
}
]
}
diff --git a/graphics/java/android/graphics/text/TEST_MAPPING b/graphics/java/android/graphics/text/TEST_MAPPING
index 99cbfe7..9f8a72c 100644
--- a/graphics/java/android/graphics/text/TEST_MAPPING
+++ b/graphics/java/android/graphics/text/TEST_MAPPING
@@ -1,15 +1,7 @@
{
"presubmit": [
{
- "name": "CtsTextTestCases",
- "options": [
- {
- "exclude-annotation": "androidx.test.filters.FlakyTest"
- },
- {
- "exclude-annotation": "androidx.test.filters.LargeTest"
- }
- ]
+ "name": "CtsTextTestCases_text"
}
]
}
diff --git a/libs/WindowManager/Jetpack/src/TEST_MAPPING b/libs/WindowManager/Jetpack/src/TEST_MAPPING
index f8f6400..600c79b 100644
--- a/libs/WindowManager/Jetpack/src/TEST_MAPPING
+++ b/libs/WindowManager/Jetpack/src/TEST_MAPPING
@@ -1,32 +1,10 @@
{
"presubmit": [
{
- "name": "WMJetpackUnitTests",
- "options": [
- {
- "include-annotation": "android.platform.test.annotations.Presubmit"
- },
- {
- "exclude-annotation": "androidx.test.filters.FlakyTest"
- },
- {
- "exclude-annotation": "org.junit.Ignore"
- }
- ]
+ "name": "WMJetpackUnitTests_Presubmit"
},
{
- "name": "CtsWindowManagerJetpackTestCases",
- "options": [
- {
- "include-annotation": "android.platform.test.annotations.Presubmit"
- },
- {
- "exclude-annotation": "androidx.test.filters.FlakyTest"
- },
- {
- "exclude-annotation": "org.junit.Ignore"
- }
- ]
+ "name": "CtsWindowManagerJetpackTestCases_Presubmit"
}
],
"imports": [
diff --git a/libs/WindowManager/Shell/OWNERS b/libs/WindowManager/Shell/OWNERS
index c6044a4..394093c6 100644
--- a/libs/WindowManager/Shell/OWNERS
+++ b/libs/WindowManager/Shell/OWNERS
@@ -1,4 +1,6 @@
xutan@google.com
+pbdr@google.com
+pragyabajoria@google.com
# Give submodule owners in shell resource approval
per-file res*/*/*.xml = atsjenk@google.com, hwwang@google.com, jorgegil@google.com, lbill@google.com, madym@google.com, vaniadesmonda@google.com, pbdr@google.com, tkachenkoi@google.com, mpodolian@google.com, liranb@google.com, pragyabajoria@google.com, uysalorhan@google.com, gsennton@google.com, mattsziklay@google.com, mdehaini@google.com
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/back/TEST_MAPPING b/libs/WindowManager/Shell/src/com/android/wm/shell/back/TEST_MAPPING
index f02559f..df3a369 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/back/TEST_MAPPING
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/back/TEST_MAPPING
@@ -1,32 +1,10 @@
{
"presubmit": [
{
- "name": "WMShellUnitTests",
- "options": [
- {
- "exclude-annotation": "androidx.test.filters.FlakyTest"
- },
- {
- "include-filter": "com.android.wm.shell.back"
- }
- ]
+ "name": "WMShellUnitTests_shell_back"
},
{
- "name": "CtsWindowManagerDeviceBackNavigation",
- "options": [
- {
- "exclude-annotation": "androidx.test.filters.FlakyTest"
- },
- {
- "include-filter": "android.server.wm.backnavigation.BackGestureInvokedTest"
- },
- {
- "include-filter": "android.server.wm.backnavigation.BackNavigationTests"
- },
- {
- "include-filter": "android.server.wm.backnavigation.OnBackInvokedCallbackGestureTest"
- }
- ]
+ "name": "CtsWindowManagerDeviceBackNavigation_com_android_wm_shell_back"
}
]
}
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/common/DisplayImeController.java b/libs/WindowManager/Shell/src/com/android/wm/shell/common/DisplayImeController.java
index f03daad..c4082d9 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/common/DisplayImeController.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/common/DisplayImeController.java
@@ -303,21 +303,29 @@
lastSurfacePosition);
} else {
if (!haveSameLeash(mImeSourceControl, imeSourceControl)) {
- applyVisibilityToLeash(imeSourceControl);
-
if (android.view.inputmethod.Flags.refactorInsetsController()) {
pendingImeStartAnimation = true;
+ // The starting point for the IME should be it's previous state
+ // (whether it is initiallyVisible or not)
+ updateImeVisibility(imeSourceControl.isInitiallyVisible());
}
+ applyVisibilityToLeash(imeSourceControl);
}
if (!mImeShowing) {
removeImeSurface(mDisplayId);
}
}
- } else if (!android.view.inputmethod.Flags.refactorInsetsController()
- && mAnimation != null) {
- // we don"t want to cancel the hide animation, when the control is lost, but
- // continue the bar to slide to the end (even without visible IME)
- mAnimation.cancel();
+ } else {
+ if (!android.view.inputmethod.Flags.refactorInsetsController()
+ && mAnimation != null) {
+ // we don't want to cancel the hide animation, when the control is lost, but
+ // continue the bar to slide to the end (even without visible IME)
+ mAnimation.cancel();
+ } else if (android.view.inputmethod.Flags.refactorInsetsController() && mImeShowing
+ && mAnimation == null) {
+ // There is no leash, so the IME cannot be in a showing state
+ updateImeVisibility(false);
+ }
}
// Make mImeSourceControl point to the new control before starting the animation.
@@ -341,7 +349,7 @@
if (android.view.inputmethod.Flags.refactorInsetsController()) {
if (pendingImeStartAnimation) {
- startAnimation(true, true /* forceRestart */);
+ startAnimation(mImeRequestedVisible, true /* forceRestart */);
}
}
}
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DragToDesktopTransitionHandler.kt b/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DragToDesktopTransitionHandler.kt
index d72ec90..dfc5ab3 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DragToDesktopTransitionHandler.kt
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DragToDesktopTransitionHandler.kt
@@ -629,15 +629,20 @@
finishTransaction: SurfaceControl.Transaction?
) {
val state = transitionState ?: return
- if (aborted && state.startTransitionToken == transition) {
+ if (!aborted) {
+ return
+ }
+ if (state.startTransitionToken == transition) {
ProtoLog.v(
ShellProtoLogGroup.WM_SHELL_DESKTOP_MODE,
"DragToDesktop: onTransitionConsumed() start transition aborted"
)
state.startAborted = true
- // Cancel CUJ interaction if the transition is aborted.
+ // The start-transition (DRAG_HOLD) is aborted, cancel its jank interaction.
interactionJankMonitor.cancel(CUJ_DESKTOP_MODE_ENTER_APP_HANDLE_DRAG_HOLD)
} else if (state.cancelTransitionToken != transition) {
+ // This transition being aborted is neither the start, nor the cancel transition, so
+ // it must be the finish transition (DRAG_RELEASE); cancel its jank interaction.
interactionJankMonitor.cancel(CUJ_DESKTOP_MODE_ENTER_APP_HANDLE_DRAG_RELEASE)
}
}
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/draganddrop/DragAndDropController.java b/libs/WindowManager/Shell/src/com/android/wm/shell/draganddrop/DragAndDropController.java
index cf02fb5..22e8dc1 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/draganddrop/DragAndDropController.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/draganddrop/DragAndDropController.java
@@ -26,7 +26,6 @@
import static android.view.WindowManager.LayoutParams.FLAG_HARDWARE_ACCELERATED;
import static android.view.WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE;
import static android.view.WindowManager.LayoutParams.LAYOUT_IN_DISPLAY_CUTOUT_MODE_ALWAYS;
-import static android.view.WindowManager.LayoutParams.MATCH_PARENT;
import static android.view.WindowManager.LayoutParams.PRIVATE_FLAG_INTERCEPT_GLOBAL_DRAG_AND_DROP;
import static android.view.WindowManager.LayoutParams.PRIVATE_FLAG_NO_MOVE_ANIMATION;
import static android.view.WindowManager.LayoutParams.SYSTEM_FLAG_SHOW_FOR_ALL_USERS;
@@ -247,9 +246,8 @@
R.layout.global_drop_target, null);
rootView.setOnDragListener(this);
rootView.setVisibility(View.INVISIBLE);
- DragLayout dragLayout = new DragLayout(context, mSplitScreen, mIconProvider);
- rootView.addView(dragLayout,
- new FrameLayout.LayoutParams(MATCH_PARENT, MATCH_PARENT));
+ DragLayoutProvider dragLayout = new DragLayout(context, mSplitScreen, mIconProvider);
+ dragLayout.addDraggingView(rootView);
try {
wm.addView(rootView, layoutParams);
addDisplayDropTarget(displayId, context, wm, rootView, dragLayout);
@@ -261,7 +259,7 @@
@VisibleForTesting
void addDisplayDropTarget(int displayId, Context context, WindowManager wm,
- FrameLayout rootView, DragLayout dragLayout) {
+ FrameLayout rootView, DragLayoutProvider dragLayout) {
mDisplayDropTargets.put(displayId,
new PerDisplay(displayId, context, wm, rootView, dragLayout));
}
@@ -564,7 +562,7 @@
final Context context;
final WindowManager wm;
final FrameLayout rootView;
- final DragLayout dragLayout;
+ final DragLayoutProvider dragLayout;
// Tracks whether the window has fully drawn since it was last made visible
boolean hasDrawn;
@@ -575,7 +573,7 @@
// The active drag session
DragSession dragSession;
- PerDisplay(int dispId, Context c, WindowManager w, FrameLayout rv, DragLayout dl) {
+ PerDisplay(int dispId, Context c, WindowManager w, FrameLayout rv, DragLayoutProvider dl) {
displayId = dispId;
context = c;
wm = w;
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/draganddrop/DragLayout.java b/libs/WindowManager/Shell/src/com/android/wm/shell/draganddrop/DragLayout.java
index 3fecbe7..dfa2437 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/draganddrop/DragLayout.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/draganddrop/DragLayout.java
@@ -23,10 +23,10 @@
import static android.view.ViewGroup.LayoutParams.MATCH_PARENT;
import static android.view.ViewTreeObserver.InternalInsetsInfo.TOUCHABLE_INSETS_REGION;
-import static com.android.wm.shell.draganddrop.DragAndDropPolicy.Target.TYPE_SPLIT_BOTTOM;
-import static com.android.wm.shell.draganddrop.DragAndDropPolicy.Target.TYPE_SPLIT_LEFT;
-import static com.android.wm.shell.draganddrop.DragAndDropPolicy.Target.TYPE_SPLIT_RIGHT;
-import static com.android.wm.shell.draganddrop.DragAndDropPolicy.Target.TYPE_SPLIT_TOP;
+import static com.android.wm.shell.draganddrop.SplitDragPolicy.Target.TYPE_SPLIT_BOTTOM;
+import static com.android.wm.shell.draganddrop.SplitDragPolicy.Target.TYPE_SPLIT_LEFT;
+import static com.android.wm.shell.draganddrop.SplitDragPolicy.Target.TYPE_SPLIT_RIGHT;
+import static com.android.wm.shell.draganddrop.SplitDragPolicy.Target.TYPE_SPLIT_TOP;
import static com.android.wm.shell.shared.split.SplitScreenConstants.SPLIT_POSITION_BOTTOM_OR_RIGHT;
import static com.android.wm.shell.shared.split.SplitScreenConstants.SPLIT_POSITION_TOP_OR_LEFT;
@@ -47,6 +47,7 @@
import android.graphics.drawable.Drawable;
import android.view.DragEvent;
import android.view.SurfaceControl;
+import android.view.ViewGroup;
import android.view.ViewTreeObserver;
import android.view.WindowInsets;
import android.view.WindowInsets.Type;
@@ -66,13 +67,13 @@
import com.android.wm.shell.splitscreen.SplitScreenController;
import java.io.PrintWriter;
-import java.util.ArrayList;
+import java.util.List;
/**
* Coordinates the visible drop targets for the current drag within a single display.
*/
public class DragLayout extends LinearLayout
- implements ViewTreeObserver.OnComputeInternalInsetsListener {
+ implements ViewTreeObserver.OnComputeInternalInsetsListener, DragLayoutProvider {
// While dragging the status bar is hidden.
private static final int HIDE_STATUS_BAR_FLAGS = StatusBarManager.DISABLE_NOTIFICATION_ICONS
@@ -80,7 +81,7 @@
| StatusBarManager.DISABLE_CLOCK
| StatusBarManager.DISABLE_SYSTEM_INFO;
- private final DragAndDropPolicy mPolicy;
+ private final DropTarget mPolicy;
private final SplitScreenController mSplitScreenController;
private final IconProvider mIconProvider;
private final StatusBarManager mStatusBarManager;
@@ -91,7 +92,7 @@
// Whether the device is currently in left/right split mode
private boolean mIsLeftRightSplit;
- private DragAndDropPolicy.Target mCurrentTarget = null;
+ private SplitDragPolicy.Target mCurrentTarget = null;
private DropZoneView mDropZoneView1;
private DropZoneView mDropZoneView2;
@@ -113,7 +114,7 @@
super(context);
mSplitScreenController = splitScreenController;
mIconProvider = iconProvider;
- mPolicy = new DragAndDropPolicy(context, splitScreenController);
+ mPolicy = new SplitDragPolicy(context, splitScreenController);
mStatusBarManager = context.getSystemService(StatusBarManager.class);
mLastConfiguration.setTo(context.getResources().getConfiguration());
@@ -387,6 +388,13 @@
recomputeDropTargets();
}
+ @NonNull
+ @Override
+ public void addDraggingView(ViewGroup rootView) {
+ // TODO(b/349828130) We need to separate out view + logic here
+ rootView.addView(this, new ViewGroup.LayoutParams(MATCH_PARENT, MATCH_PARENT));
+ }
+
/**
* Recalculates the drop targets based on the current policy.
*/
@@ -394,9 +402,9 @@
if (!mIsShowing) {
return;
}
- final ArrayList<DragAndDropPolicy.Target> targets = mPolicy.getTargets(mInsets);
+ final List<SplitDragPolicy.Target> targets = mPolicy.getTargets(mInsets);
for (int i = 0; i < targets.size(); i++) {
- final DragAndDropPolicy.Target target = targets.get(i);
+ final SplitDragPolicy.Target target = targets.get(i);
ProtoLog.v(ShellProtoLogGroup.WM_SHELL_DRAG_AND_DROP, "Add target: %s", target);
// Inset the draw region by a little bit
target.drawRegion.inset(mDisplayMargin, mDisplayMargin);
@@ -419,7 +427,7 @@
}
// Find containing region, if the same as mCurrentRegion, then skip, otherwise, animate the
// visibility of the current region
- DragAndDropPolicy.Target target = mPolicy.getTargetAtLocation(x, y);
+ SplitDragPolicy.Target target = mPolicy.getTargetAtLocation(x, y);
if (mCurrentTarget != target) {
ProtoLog.v(ShellProtoLogGroup.WM_SHELL_DRAG_AND_DROP, "Current target: %s", target);
if (target == null) {
@@ -493,7 +501,7 @@
mHasDropped = true;
// Process the drop
- mPolicy.handleDrop(mCurrentTarget, hideTaskToken);
+ mPolicy.onDropped(mCurrentTarget, hideTaskToken);
// Start animating the drop UI out with the drag surface
hide(event, dropCompleteCallback);
@@ -576,7 +584,7 @@
}
}
- private void animateHighlight(DragAndDropPolicy.Target target) {
+ private void animateHighlight(SplitDragPolicy.Target target) {
if (target.type == TYPE_SPLIT_LEFT || target.type == TYPE_SPLIT_TOP) {
mDropZoneView1.setShowingHighlight(true);
mDropZoneView2.setShowingHighlight(false);
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/draganddrop/DragLayoutProvider.kt b/libs/WindowManager/Shell/src/com/android/wm/shell/draganddrop/DragLayoutProvider.kt
new file mode 100644
index 0000000..3d40824
--- /dev/null
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/draganddrop/DragLayoutProvider.kt
@@ -0,0 +1,80 @@
+/*
+ * 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 com.android.wm.shell.draganddrop
+
+import android.content.res.Configuration
+import android.view.DragEvent
+import android.view.SurfaceControl
+import android.view.ViewGroup
+import android.window.WindowContainerToken
+import com.android.internal.logging.InstanceId
+import java.io.PrintWriter
+
+/** Interface to be implemented by any controllers providing a layout for DragAndDrop in Shell */
+interface DragLayoutProvider {
+ /**
+ * Updates the drag layout based on the given drag session.
+ */
+ fun updateSession(session: DragSession)
+ /**
+ * Called when a new drag is started.
+ */
+ fun prepare(session: DragSession, loggerSessionId: InstanceId?)
+
+ /**
+ * Shows the drag layout.
+ */
+ fun show()
+
+ /**
+ * Updates the visible drop target as the user drags.
+ */
+ fun update(event: DragEvent?)
+
+ /**
+ * Hides the drag layout and animates out the visible drop targets.
+ */
+ fun hide(event: DragEvent?, hideCompleteCallback: Runnable?)
+
+ /**
+ * Whether target has already been dropped or not
+ */
+ fun hasDropped(): Boolean
+
+ /**
+ * Handles the drop onto a target and animates out the visible drop targets.
+ */
+ fun drop(
+ event: DragEvent?, dragSurface: SurfaceControl,
+ hideTaskToken: WindowContainerToken?, dropCompleteCallback: Runnable?
+ ): Boolean
+
+ /**
+ * Dumps information about this drag layout.
+ */
+ fun dump(pw: PrintWriter, prefix: String?)
+
+ /**
+ * @return a View which will be added to the global root view for drag and drop
+ */
+ fun addDraggingView(viewGroup: ViewGroup)
+
+ /**
+ * Called when the configuration changes.
+ */
+ fun onConfigChanged(newConfig: Configuration?)
+}
\ No newline at end of file
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/draganddrop/DropTarget.kt b/libs/WindowManager/Shell/src/com/android/wm/shell/draganddrop/DropTarget.kt
new file mode 100644
index 0000000..122a105
--- /dev/null
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/draganddrop/DropTarget.kt
@@ -0,0 +1,56 @@
+/*
+ * 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 com.android.wm.shell.draganddrop
+
+import android.graphics.Insets
+import android.window.WindowContainerToken
+import com.android.internal.logging.InstanceId
+
+/**
+ * Interface to be implemented by classes which want to provide drop targets
+ * for DragAndDrop in Shell
+ */
+interface DropTarget {
+ // TODO(b/349828130) Delete after flexible split launches
+ /**
+ * Called at the start of a Drag, before input events are processed.
+ */
+ fun start(dragSession: DragSession, logSessionId: InstanceId)
+ /**
+ * @return [SplitDragPolicy.Target] corresponding to the given coords in display bounds.
+ */
+ fun getTargetAtLocation(x: Int, y: Int) : SplitDragPolicy.Target
+ /**
+ * @return total number of drop targets for the current drag session.
+ */
+ fun getNumTargets() : Int
+ // TODO(b/349828130)
+
+ /**
+ * @return [List<SplitDragPolicy.Target>] to show for the current drag session.
+ */
+ fun getTargets(insets: Insets) : List<SplitDragPolicy.Target>
+ /**
+ * Called when user is hovering Drag object over the given Target
+ */
+ fun onHoveringOver(target: SplitDragPolicy.Target) {}
+ /**
+ * Called when the user has dropped the provided target (need not be the same target as
+ * [onHoveringOver])
+ */
+ fun onDropped(target: SplitDragPolicy.Target, hideTaskToken: WindowContainerToken)
+}
\ No newline at end of file
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/draganddrop/DragAndDropPolicy.java b/libs/WindowManager/Shell/src/com/android/wm/shell/draganddrop/SplitDragPolicy.java
similarity index 93%
rename from libs/WindowManager/Shell/src/com/android/wm/shell/draganddrop/DragAndDropPolicy.java
rename to libs/WindowManager/Shell/src/com/android/wm/shell/draganddrop/SplitDragPolicy.java
index 6fec0c1..2a19d65 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/draganddrop/DragAndDropPolicy.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/draganddrop/SplitDragPolicy.java
@@ -32,11 +32,11 @@
import static android.content.Intent.FLAG_ACTIVITY_MULTIPLE_TASK;
import static android.content.Intent.FLAG_ACTIVITY_NEW_TASK;
-import static com.android.wm.shell.draganddrop.DragAndDropPolicy.Target.TYPE_FULLSCREEN;
-import static com.android.wm.shell.draganddrop.DragAndDropPolicy.Target.TYPE_SPLIT_BOTTOM;
-import static com.android.wm.shell.draganddrop.DragAndDropPolicy.Target.TYPE_SPLIT_LEFT;
-import static com.android.wm.shell.draganddrop.DragAndDropPolicy.Target.TYPE_SPLIT_RIGHT;
-import static com.android.wm.shell.draganddrop.DragAndDropPolicy.Target.TYPE_SPLIT_TOP;
+import static com.android.wm.shell.draganddrop.SplitDragPolicy.Target.TYPE_FULLSCREEN;
+import static com.android.wm.shell.draganddrop.SplitDragPolicy.Target.TYPE_SPLIT_BOTTOM;
+import static com.android.wm.shell.draganddrop.SplitDragPolicy.Target.TYPE_SPLIT_LEFT;
+import static com.android.wm.shell.draganddrop.SplitDragPolicy.Target.TYPE_SPLIT_RIGHT;
+import static com.android.wm.shell.draganddrop.SplitDragPolicy.Target.TYPE_SPLIT_TOP;
import static com.android.wm.shell.shared.draganddrop.DragAndDropConstants.EXTRA_DISALLOW_HIT_REGION;
import static com.android.wm.shell.shared.split.SplitScreenConstants.SPLIT_POSITION_BOTTOM_OR_RIGHT;
import static com.android.wm.shell.shared.split.SplitScreenConstants.SPLIT_POSITION_TOP_OR_LEFT;
@@ -80,9 +80,9 @@
/**
* The policy for handling drag and drop operations to shell.
*/
-public class DragAndDropPolicy {
+public class SplitDragPolicy implements DropTarget {
- private static final String TAG = DragAndDropPolicy.class.getSimpleName();
+ private static final String TAG = SplitDragPolicy.class.getSimpleName();
private final Context mContext;
// Used only for launching a fullscreen task (or as a fallback if there is no split starter)
@@ -90,18 +90,18 @@
// Used for launching tasks into splitscreen
private final Starter mSplitscreenStarter;
private final SplitScreenController mSplitScreen;
- private final ArrayList<DragAndDropPolicy.Target> mTargets = new ArrayList<>();
+ private final ArrayList<SplitDragPolicy.Target> mTargets = new ArrayList<>();
private final RectF mDisallowHitRegion = new RectF();
private InstanceId mLoggerSessionId;
private DragSession mSession;
- public DragAndDropPolicy(Context context, SplitScreenController splitScreen) {
+ public SplitDragPolicy(Context context, SplitScreenController splitScreen) {
this(context, splitScreen, new DefaultStarter(context));
}
@VisibleForTesting
- DragAndDropPolicy(Context context, SplitScreenController splitScreen,
+ SplitDragPolicy(Context context, SplitScreenController splitScreen,
Starter fullscreenStarter) {
mContext = context;
mSplitScreen = splitScreen;
@@ -112,7 +112,7 @@
/**
* Starts a new drag session with the given initial drag data.
*/
- void start(DragSession session, InstanceId loggerSessionId) {
+ public void start(DragSession session, InstanceId loggerSessionId) {
mLoggerSessionId = loggerSessionId;
mSession = session;
RectF disallowHitRegion = mSession.appData != null
@@ -128,7 +128,8 @@
/**
* Returns the number of targets.
*/
- int getNumTargets() {
+ @Override
+ public int getNumTargets() {
return mTargets.size();
}
@@ -136,7 +137,8 @@
* Returns the target's regions based on the current state of the device and display.
*/
@NonNull
- ArrayList<Target> getTargets(Insets insets) {
+ @Override
+ public ArrayList<Target> getTargets(@NonNull Insets insets) {
mTargets.clear();
if (mSession == null) {
// Return early if this isn't an app drag
@@ -222,12 +224,12 @@
* Returns the target at the given position based on the targets previously calculated.
*/
@Nullable
- Target getTargetAtLocation(int x, int y) {
+ public Target getTargetAtLocation(int x, int y) {
if (mDisallowHitRegion.contains(x, y)) {
return null;
}
for (int i = mTargets.size() - 1; i >= 0; i--) {
- DragAndDropPolicy.Target t = mTargets.get(i);
+ SplitDragPolicy.Target t = mTargets.get(i);
if (t.hitRegion.contains(x, y)) {
return t;
}
@@ -241,7 +243,7 @@
* container transaction if possible.
*/
@VisibleForTesting
- void handleDrop(Target target, @Nullable WindowContainerToken hideTaskToken) {
+ public void onDropped(Target target, @Nullable WindowContainerToken hideTaskToken) {
if (target == null || !mTargets.contains(target)) {
return;
}
@@ -419,8 +421,9 @@
/**
* Represents a drop target.
+ * TODO(b/349828130): Move this into {@link DropTarget}
*/
- static class Target {
+ public static class Target {
static final int TYPE_FULLSCREEN = 0;
static final int TYPE_SPLIT_LEFT = 1;
static final int TYPE_SPLIT_TOP = 2;
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipTaskOrganizer.java b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipTaskOrganizer.java
index ab222c9..b4e0329 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipTaskOrganizer.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipTaskOrganizer.java
@@ -2033,7 +2033,10 @@
tx.apply();
}
- private void cancelCurrentAnimator() {
+ /**
+ * Cancels the currently running animator if there is one and removes an overlay if present.
+ */
+ public void cancelCurrentAnimator() {
final PipAnimationController.PipTransitionAnimator<?> animator =
mPipAnimationController.getCurrentAnimator();
// remove any overlays if present
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PipController.java b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PipController.java
index 755e958..deb7691 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PipController.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PipController.java
@@ -324,7 +324,7 @@
return;
}
onDisplayChanged(mDisplayController.getDisplayLayout(displayId),
- false /* saveRestoreSnapFraction */);
+ true /* saveRestoreSnapFraction */);
}
@Override
@@ -652,9 +652,11 @@
// there's a keyguard present
return;
}
- onDisplayChangedUncheck(mDisplayController
- .getDisplayLayout(mPipDisplayLayoutState.getDisplayId()),
- false /* saveRestoreSnapFraction */);
+ mMainExecutor.executeDelayed(() -> {
+ onDisplayChangedUncheck(mDisplayController.getDisplayLayout(
+ mPipDisplayLayoutState.getDisplayId()),
+ false /* saveRestoreSnapFraction */);
+ }, PIP_KEEP_CLEAR_AREAS_DELAY);
}
});
@@ -800,7 +802,7 @@
}
};
- if (mPipTaskOrganizer.isInPip() && saveRestoreSnapFraction) {
+ if (mPipTransitionState.hasEnteredPip() && saveRestoreSnapFraction) {
mMenuController.attachPipMenuView();
// Calculate the snap fraction of the current stack along the old movement bounds
final PipSnapAlgorithm pipSnapAlgorithm = mPipBoundsAlgorithm.getSnapAlgorithm();
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/SplitScreenController.java b/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/SplitScreenController.java
index 793e2aa..87b661d 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/SplitScreenController.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/SplitScreenController.java
@@ -92,7 +92,7 @@
import com.android.wm.shell.common.split.SplitScreenUtils;
import com.android.wm.shell.desktopmode.DesktopTasksController;
import com.android.wm.shell.draganddrop.DragAndDropController;
-import com.android.wm.shell.draganddrop.DragAndDropPolicy;
+import com.android.wm.shell.draganddrop.SplitDragPolicy;
import com.android.wm.shell.protolog.ShellProtoLogGroup;
import com.android.wm.shell.recents.RecentTasksController;
import com.android.wm.shell.shared.TransactionPool;
@@ -121,7 +121,7 @@
* @see StageCoordinator
*/
// TODO(b/198577848): Implement split screen flicker test to consolidate CUJ of split screen.
-public class SplitScreenController implements DragAndDropPolicy.Starter,
+public class SplitScreenController implements SplitDragPolicy.Starter,
RemoteCallable<SplitScreenController>, KeyguardChangeListener {
private static final String TAG = SplitScreenController.class.getSimpleName();
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/transition/DefaultTransitionHandler.java b/libs/WindowManager/Shell/src/com/android/wm/shell/transition/DefaultTransitionHandler.java
index f40e0ba..1573291 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/transition/DefaultTransitionHandler.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/transition/DefaultTransitionHandler.java
@@ -358,9 +358,12 @@
if (mode == TRANSIT_CHANGE && change.hasFlags(FLAG_IS_DISPLAY)) {
if (info.getType() == TRANSIT_CHANGE) {
- final int anim = getRotationAnimationHint(change, info, mDisplayController);
+ int anim = getRotationAnimationHint(change, info, mDisplayController);
isSeamlessDisplayChange = anim == ROTATION_ANIMATION_SEAMLESS;
if (!(isSeamlessDisplayChange || anim == ROTATION_ANIMATION_JUMPCUT)) {
+ if (wallpaperTransit != WALLPAPER_TRANSITION_NONE) {
+ anim |= ScreenRotationAnimation.ANIMATION_HINT_HAS_WALLPAPER;
+ }
startRotationAnimation(startTransaction, change, info, anim, animations,
onAnimFinish);
isDisplayRotationAnimationStarted = true;
@@ -826,24 +829,26 @@
@NonNull Runnable finishCallback, @NonNull TransactionPool pool,
@NonNull ShellExecutor mainExecutor, @Nullable Point position, float cornerRadius,
@Nullable Rect clipRect, boolean isActivity) {
+ final DefaultAnimationAdapter adapter = new DefaultAnimationAdapter(anim, leash,
+ position, clipRect, cornerRadius, isActivity);
+ buildSurfaceAnimation(animations, anim, finishCallback, pool, mainExecutor, adapter);
+ }
+
+ /** Builds an animator for the surface and adds it to the `animations` list. */
+ static void buildSurfaceAnimation(@NonNull ArrayList<Animator> animations,
+ @NonNull Animation anim, @NonNull Runnable finishCallback,
+ @NonNull TransactionPool pool, @NonNull ShellExecutor mainExecutor,
+ @NonNull AnimationAdapter updateListener) {
final SurfaceControl.Transaction transaction = pool.acquire();
+ updateListener.setTransaction(transaction);
final ValueAnimator va = ValueAnimator.ofFloat(0f, 1f);
- final Transformation transformation = new Transformation();
- final float[] matrix = new float[9];
// Animation length is already expected to be scaled.
va.overrideDurationScale(1.0f);
va.setDuration(anim.computeDurationHint());
- final ValueAnimator.AnimatorUpdateListener updateListener = animation -> {
- final long currentPlayTime = Math.min(va.getDuration(), va.getCurrentPlayTime());
-
- applyTransformation(currentPlayTime, transaction, leash, anim, transformation, matrix,
- position, cornerRadius, clipRect, isActivity);
- };
va.addUpdateListener(updateListener);
final Runnable finisher = () -> {
- applyTransformation(va.getDuration(), transaction, leash, anim, transformation, matrix,
- position, cornerRadius, clipRect, isActivity);
+ updateListener.onAnimationUpdate(va);
pool.release(transaction);
mainExecutor.execute(() -> {
@@ -1007,37 +1012,88 @@
|| animType == ANIM_FROM_STYLE;
}
- private static void applyTransformation(long time, SurfaceControl.Transaction t,
- SurfaceControl leash, Animation anim, Transformation tmpTransformation, float[] matrix,
- Point position, float cornerRadius, @Nullable Rect immutableClipRect,
- boolean isActivity) {
- tmpTransformation.clear();
- anim.getTransformation(time, tmpTransformation);
- if (com.android.graphics.libgui.flags.Flags.edgeExtensionShader()
- && anim.getExtensionEdges() != 0x0 && isActivity) {
- t.setEdgeExtensionEffect(leash, anim.getExtensionEdges());
- }
- if (position != null) {
- tmpTransformation.getMatrix().postTranslate(position.x, position.y);
- }
- t.setMatrix(leash, tmpTransformation.getMatrix(), matrix);
- t.setAlpha(leash, tmpTransformation.getAlpha());
+ /** The animation adapter for buildSurfaceAnimation. */
+ abstract static class AnimationAdapter implements ValueAnimator.AnimatorUpdateListener {
+ @NonNull final SurfaceControl mLeash;
+ @NonNull SurfaceControl.Transaction mTransaction;
+ private Choreographer mChoreographer;
- final Rect clipRect = immutableClipRect == null ? null : new Rect(immutableClipRect);
- Insets extensionInsets = Insets.min(tmpTransformation.getInsets(), Insets.NONE);
- if (!extensionInsets.equals(Insets.NONE) && clipRect != null && !clipRect.isEmpty()) {
- // Clip out any overflowing edge extension
- clipRect.inset(extensionInsets);
- t.setCrop(leash, clipRect);
+ AnimationAdapter(@NonNull SurfaceControl leash) {
+ mLeash = leash;
}
- if (anim.hasRoundedCorners() && cornerRadius > 0 && clipRect != null) {
- // We can only apply rounded corner if a crop is set
- t.setCrop(leash, clipRect);
- t.setCornerRadius(leash, cornerRadius);
+ void setTransaction(@NonNull SurfaceControl.Transaction transaction) {
+ mTransaction = transaction;
}
- t.setFrameTimelineVsync(Choreographer.getInstance().getVsyncId());
- t.apply();
+ @Override
+ public void onAnimationUpdate(@NonNull ValueAnimator animator) {
+ applyTransformation(animator);
+ if (mChoreographer == null) {
+ mChoreographer = Choreographer.getInstance();
+ }
+ mTransaction.setFrameTimelineVsync(mChoreographer.getVsyncId());
+ mTransaction.apply();
+ }
+
+ abstract void applyTransformation(@NonNull ValueAnimator animator);
+ }
+
+ private static class DefaultAnimationAdapter extends AnimationAdapter {
+ final Transformation mTransformation = new Transformation();
+ final float[] mMatrix = new float[9];
+ @NonNull final Animation mAnim;
+ @Nullable final Point mPosition;
+ @Nullable final Rect mClipRect;
+ final float mCornerRadius;
+ final boolean mIsActivity;
+
+ DefaultAnimationAdapter(@NonNull Animation anim, @NonNull SurfaceControl leash,
+ @Nullable Point position, @Nullable Rect clipRect, float cornerRadius,
+ boolean isActivity) {
+ super(leash);
+ mAnim = anim;
+ mPosition = (position != null && (position.x != 0 || position.y != 0))
+ ? position : null;
+ mClipRect = (clipRect != null && !clipRect.isEmpty()) ? clipRect : null;
+ mCornerRadius = cornerRadius;
+ mIsActivity = isActivity;
+ }
+
+ @Override
+ void applyTransformation(@NonNull ValueAnimator animator) {
+ final long currentPlayTime = Math.min(animator.getDuration(),
+ animator.getCurrentPlayTime());
+ final Transformation transformation = mTransformation;
+ final SurfaceControl.Transaction t = mTransaction;
+ final SurfaceControl leash = mLeash;
+ transformation.clear();
+ mAnim.getTransformation(currentPlayTime, transformation);
+ if (com.android.graphics.libgui.flags.Flags.edgeExtensionShader()
+ && mIsActivity && mAnim.getExtensionEdges() != 0) {
+ t.setEdgeExtensionEffect(leash, mAnim.getExtensionEdges());
+ }
+ if (mPosition != null) {
+ transformation.getMatrix().postTranslate(mPosition.x, mPosition.y);
+ }
+ t.setMatrix(leash, transformation.getMatrix(), mMatrix);
+ t.setAlpha(leash, transformation.getAlpha());
+
+ if (mClipRect != null) {
+ Rect clipRect = mClipRect;
+ final Insets extensionInsets = Insets.min(transformation.getInsets(), Insets.NONE);
+ if (!extensionInsets.equals(Insets.NONE)) {
+ // Clip out any overflowing edge extension.
+ clipRect = new Rect(mClipRect);
+ clipRect.inset(extensionInsets);
+ t.setCrop(leash, clipRect);
+ }
+ if (mCornerRadius > 0 && mAnim.hasRoundedCorners()) {
+ // Rounded corner can only be applied if a crop is set.
+ t.setCrop(leash, clipRect);
+ t.setCornerRadius(leash, mCornerRadius);
+ }
+ }
+ }
}
}
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/transition/ScreenRotationAnimation.java b/libs/WindowManager/Shell/src/com/android/wm/shell/transition/ScreenRotationAnimation.java
index 5802e2c..b9d11a3 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/transition/ScreenRotationAnimation.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/transition/ScreenRotationAnimation.java
@@ -25,12 +25,9 @@
import static com.android.wm.shell.transition.Transitions.TAG;
import android.animation.Animator;
-import android.animation.AnimatorListenerAdapter;
-import android.animation.ArgbEvaluator;
import android.animation.ValueAnimator;
import android.annotation.NonNull;
import android.content.Context;
-import android.graphics.Color;
import android.graphics.Matrix;
import android.graphics.Rect;
import android.hardware.HardwareBuffer;
@@ -38,6 +35,7 @@
import android.view.Surface;
import android.view.SurfaceControl;
import android.view.SurfaceControl.Transaction;
+import android.view.animation.AccelerateInterpolator;
import android.view.animation.Animation;
import android.view.animation.AnimationUtils;
import android.window.ScreenCapture;
@@ -74,6 +72,9 @@
*/
class ScreenRotationAnimation {
static final int MAX_ANIMATION_DURATION = 10 * 1000;
+ static final int ANIMATION_HINT_HAS_WALLPAPER = 1 << 8;
+ /** It must cover all WindowManager#ROTATION_ANIMATION_*. */
+ private static final int ANIMATION_TYPE_MASK = 0xff;
private final Context mContext;
private final TransactionPool mTransactionPool;
@@ -81,7 +82,7 @@
/** The leash of the changing window container. */
private final SurfaceControl mSurfaceControl;
- private final int mAnimHint;
+ private final int mAnimType;
private final int mStartWidth;
private final int mStartHeight;
private final int mEndWidth;
@@ -98,6 +99,12 @@
private SurfaceControl mBackColorSurface;
/** The leash using to animate screenshot layer. */
private final SurfaceControl mAnimLeash;
+ /**
+ * The container with background color for {@link #mSurfaceControl}. It is only created if
+ * {@link #mSurfaceControl} may be translucent. E.g. visible wallpaper with alpha < 1 (dimmed).
+ * That prevents flickering of alpha blending.
+ */
+ private SurfaceControl mBackEffectSurface;
// The current active animation to move from the old to the new rotated
// state. Which animation is run here will depend on the old and new
@@ -115,7 +122,7 @@
Transaction t, TransitionInfo.Change change, SurfaceControl rootLeash, int animHint) {
mContext = context;
mTransactionPool = pool;
- mAnimHint = animHint;
+ mAnimType = animHint & ANIMATION_TYPE_MASK;
mSurfaceControl = change.getLeash();
mStartWidth = change.getStartAbsBounds().width();
@@ -170,11 +177,20 @@
}
hardwareBuffer.close();
}
+ if ((animHint & ANIMATION_HINT_HAS_WALLPAPER) != 0) {
+ mBackEffectSurface = new SurfaceControl.Builder()
+ .setCallsite("ShellRotationAnimation").setParent(rootLeash)
+ .setEffectLayer().setOpaque(true).setName("BackEffect").build();
+ t.reparent(mSurfaceControl, mBackEffectSurface)
+ .setColor(mBackEffectSurface,
+ new float[] {mStartLuma, mStartLuma, mStartLuma})
+ .show(mBackEffectSurface);
+ }
t.setLayer(mAnimLeash, SCREEN_FREEZE_LAYER_BASE);
t.show(mAnimLeash);
// Crop the real content in case it contains a larger child layer, e.g. wallpaper.
- t.setCrop(mSurfaceControl, new Rect(0, 0, mEndWidth, mEndHeight));
+ t.setCrop(getEnterSurface(), new Rect(0, 0, mEndWidth, mEndHeight));
if (!isCustomRotate()) {
mBackColorSurface = new SurfaceControl.Builder()
@@ -199,7 +215,12 @@
}
private boolean isCustomRotate() {
- return mAnimHint == ROTATION_ANIMATION_CROSSFADE || mAnimHint == ROTATION_ANIMATION_JUMPCUT;
+ return mAnimType == ROTATION_ANIMATION_CROSSFADE || mAnimType == ROTATION_ANIMATION_JUMPCUT;
+ }
+
+ /** Returns the surface which contains the real content to animate enter. */
+ private SurfaceControl getEnterSurface() {
+ return mBackEffectSurface != null ? mBackEffectSurface : mSurfaceControl;
}
private void setScreenshotTransform(SurfaceControl.Transaction t) {
@@ -260,7 +281,7 @@
final boolean customRotate = isCustomRotate();
if (customRotate) {
mRotateExitAnimation = AnimationUtils.loadAnimation(mContext,
- mAnimHint == ROTATION_ANIMATION_JUMPCUT ? R.anim.rotation_animation_jump_exit
+ mAnimType == ROTATION_ANIMATION_JUMPCUT ? R.anim.rotation_animation_jump_exit
: R.anim.rotation_animation_xfade_exit);
mRotateEnterAnimation = AnimationUtils.loadAnimation(mContext,
R.anim.rotation_animation_enter);
@@ -314,7 +335,11 @@
} else {
startDisplayRotation(animations, finishCallback, mainExecutor);
startScreenshotRotationAnimation(animations, finishCallback, mainExecutor);
- //startColorAnimation(mTransaction, animationScale);
+ if (mBackEffectSurface != null && mStartLuma > 0.1f) {
+ // Animate from the color of background to black for smooth alpha blending.
+ buildLumaAnimation(animations, mStartLuma, 0f /* endLuma */, mBackEffectSurface,
+ animationScale, finishCallback, mainExecutor);
+ }
}
return true;
@@ -322,7 +347,7 @@
private void startDisplayRotation(@NonNull ArrayList<Animator> animations,
@NonNull Runnable finishCallback, @NonNull ShellExecutor mainExecutor) {
- buildSurfaceAnimation(animations, mRotateEnterAnimation, mSurfaceControl, finishCallback,
+ buildSurfaceAnimation(animations, mRotateEnterAnimation, getEnterSurface(), finishCallback,
mTransactionPool, mainExecutor, null /* position */, 0 /* cornerRadius */,
null /* clipRect */, false /* isActivity */);
}
@@ -341,40 +366,17 @@
null /* clipRect */, false /* isActivity */);
}
- private void startColorAnimation(float animationScale, @NonNull ShellExecutor animExecutor) {
- int colorTransitionMs = mContext.getResources().getInteger(
- R.integer.config_screen_rotation_color_transition);
- final float[] rgbTmpFloat = new float[3];
- final int startColor = Color.rgb(mStartLuma, mStartLuma, mStartLuma);
- final int endColor = Color.rgb(mEndLuma, mEndLuma, mEndLuma);
- final long duration = colorTransitionMs * (long) animationScale;
- final Transaction t = mTransactionPool.acquire();
-
- final ValueAnimator va = ValueAnimator.ofFloat(0f, 1f);
- // Animation length is already expected to be scaled.
- va.overrideDurationScale(1.0f);
- va.setDuration(duration);
- va.addUpdateListener(animation -> {
- final long currentPlayTime = Math.min(va.getDuration(), va.getCurrentPlayTime());
- final float fraction = currentPlayTime / va.getDuration();
- applyColor(startColor, endColor, rgbTmpFloat, fraction, mBackColorSurface, t);
- });
- va.addListener(new AnimatorListenerAdapter() {
- @Override
- public void onAnimationCancel(Animator animation) {
- applyColor(startColor, endColor, rgbTmpFloat, 1f /* fraction */, mBackColorSurface,
- t);
- mTransactionPool.release(t);
- }
-
- @Override
- public void onAnimationEnd(Animator animation) {
- applyColor(startColor, endColor, rgbTmpFloat, 1f /* fraction */, mBackColorSurface,
- t);
- mTransactionPool.release(t);
- }
- });
- animExecutor.execute(va::start);
+ private void buildLumaAnimation(@NonNull ArrayList<Animator> animations,
+ float startLuma, float endLuma, SurfaceControl surface, float animationScale,
+ @NonNull Runnable finishCallback, @NonNull ShellExecutor mainExecutor) {
+ final long durationMillis = (long) (mContext.getResources().getInteger(
+ R.integer.config_screen_rotation_color_transition) * animationScale);
+ final LumaAnimation animation = new LumaAnimation(durationMillis);
+ // Align the end with the enter animation.
+ animation.setStartOffset(mRotateEnterAnimation.getDuration() - durationMillis);
+ final LumaAnimationAdapter adapter = new LumaAnimationAdapter(surface, startLuma, endLuma);
+ buildSurfaceAnimation(animations, animation, finishCallback, mTransactionPool,
+ mainExecutor, adapter);
}
public void kill() {
@@ -389,21 +391,47 @@
if (mBackColorSurface != null && mBackColorSurface.isValid()) {
t.remove(mBackColorSurface);
}
+ if (mBackEffectSurface != null && mBackEffectSurface.isValid()) {
+ t.remove(mBackEffectSurface);
+ }
t.apply();
mTransactionPool.release(t);
}
- private static void applyColor(int startColor, int endColor, float[] rgbFloat,
- float fraction, SurfaceControl surface, SurfaceControl.Transaction t) {
- final int color = (Integer) ArgbEvaluator.getInstance().evaluate(fraction, startColor,
- endColor);
- Color middleColor = Color.valueOf(color);
- rgbFloat[0] = middleColor.red();
- rgbFloat[1] = middleColor.green();
- rgbFloat[2] = middleColor.blue();
- if (surface.isValid()) {
- t.setColor(surface, rgbFloat);
+ /** A no-op wrapper to provide animation duration. */
+ private static class LumaAnimation extends Animation {
+ LumaAnimation(long durationMillis) {
+ setDuration(durationMillis);
}
- t.apply();
+ }
+
+ private static class LumaAnimationAdapter extends DefaultTransitionHandler.AnimationAdapter {
+ final float[] mColorArray = new float[3];
+ final float mStartLuma;
+ final float mEndLuma;
+ final AccelerateInterpolator mInterpolation;
+
+ LumaAnimationAdapter(@NonNull SurfaceControl leash, float startLuma, float endLuma) {
+ super(leash);
+ mStartLuma = startLuma;
+ mEndLuma = endLuma;
+ // Make the initial progress color lighter if the background is light. That avoids
+ // darker content when fading into the entering surface.
+ final float factor = Math.min(3f, (Math.max(0.5f, mStartLuma) - 0.5f) * 10);
+ Slog.d(TAG, "Luma=" + mStartLuma + " factor=" + factor);
+ mInterpolation = factor > 0.5f ? new AccelerateInterpolator(factor) : null;
+ }
+
+ @Override
+ void applyTransformation(ValueAnimator animator) {
+ final float fraction = mInterpolation != null
+ ? mInterpolation.getInterpolation(animator.getAnimatedFraction())
+ : animator.getAnimatedFraction();
+ final float luma = mStartLuma + fraction * (mEndLuma - mStartLuma);
+ mColorArray[0] = luma;
+ mColorArray[1] = luma;
+ mColorArray[2] = luma;
+ mTransaction.setColor(mLeash, mColorArray);
+ }
}
}
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 46fe68f..0caa8e9 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
@@ -55,6 +55,7 @@
import com.android.wm.shell.common.ShellExecutor;
import com.android.wm.shell.common.SyncTransactionQueue;
import com.android.wm.shell.shared.annotations.ShellBackgroundThread;
+import com.android.wm.shell.shared.desktopmode.DesktopModeFlags;
import com.android.wm.shell.windowdecor.extension.TaskInfoKt;
import com.android.wm.shell.windowdecor.viewhost.WindowDecorViewHostSupplier;
@@ -240,7 +241,8 @@
boolean applyStartTransactionOnDraw, boolean setTaskCropAndPosition) {
final boolean isFreeform =
taskInfo.getWindowingMode() == WindowConfiguration.WINDOWING_MODE_FREEFORM;
- final boolean isDragResizeable = isFreeform && taskInfo.isResizeable;
+ final boolean isDragResizeable = DesktopModeFlags.SCALED_RESIZING.isEnabled(mContext)
+ ? isFreeform : isFreeform && taskInfo.isResizeable;
final WindowDecorLinearLayout oldRootView = mResult.mRootView;
final SurfaceControl oldDecorationSurface = mDecorationContainerSurface;
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 2519ce4..b311359 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
@@ -1603,14 +1603,27 @@
Transitions transitions,
InteractionJankMonitor interactionJankMonitor,
Supplier<SurfaceControl.Transaction> transactionFactory) {
- if (!DesktopModeStatus.isVeiledResizeEnabled()) {
- return new FluidResizeTaskPositioner(
- taskOrganizer, transitions, windowDecoration, displayController,
- dragStartListener, transactionFactory);
+ final TaskPositioner taskPositioner = DesktopModeStatus.isVeiledResizeEnabled()
+ ? new VeiledResizeTaskPositioner(
+ taskOrganizer,
+ windowDecoration,
+ displayController,
+ dragStartListener,
+ transitions,
+ interactionJankMonitor)
+ : new FluidResizeTaskPositioner(
+ taskOrganizer,
+ transitions,
+ windowDecoration,
+ displayController,
+ dragStartListener,
+ transactionFactory);
+
+ if (DesktopModeFlags.SCALED_RESIZING.isEnabled(windowDecoration.mContext)) {
+ return new FixedAspectRatioTaskPositionerDecorator(windowDecoration,
+ taskPositioner);
}
- return new VeiledResizeTaskPositioner(
- taskOrganizer, windowDecoration, displayController,
- dragStartListener, transitions, interactionJankMonitor);
+ return taskPositioner;
}
}
}
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 5d16d97..5521c2e 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
@@ -455,7 +455,7 @@
}
private void updateDragResizeListener(SurfaceControl oldDecorationSurface) {
- if (!isDragResizable(mTaskInfo)) {
+ if (!isDragResizable(mTaskInfo, mContext)) {
if (!mTaskInfo.positionInParent.equals(mPositionInParent)) {
// We still want to track caption bar's exclusion region on a non-resizeable task.
updateExclusionRegion();
@@ -497,12 +497,16 @@
}
}
- private static boolean isDragResizable(ActivityManager.RunningTaskInfo taskInfo) {
+ private static boolean isDragResizable(ActivityManager.RunningTaskInfo taskInfo,
+ Context context) {
+ if (DesktopModeFlags.SCALED_RESIZING.isEnabled(context)) {
+ return taskInfo.isFreeform();
+ }
return taskInfo.isFreeform() && taskInfo.isResizeable;
}
private void updateMaximizeMenu(SurfaceControl.Transaction startT) {
- if (!isDragResizable(mTaskInfo) || !isMaximizeMenuActive()) {
+ if (!isDragResizable(mTaskInfo, mContext) || !isMaximizeMenuActive()) {
return;
}
if (!mTaskInfo.isVisible()) {
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/DragPositioningCallbackUtility.java b/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/DragPositioningCallbackUtility.java
index cb9781e..cad3462 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/DragPositioningCallbackUtility.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/DragPositioningCallbackUtility.java
@@ -84,22 +84,47 @@
repositionTaskBounds.set(taskBoundsAtDragStart);
+ boolean isAspectRatioMaintained = true;
// Make sure the new resizing destination in any direction falls within the stable bounds.
if ((ctrlType & CTRL_TYPE_LEFT) != 0) {
repositionTaskBounds.left = Math.max(repositionTaskBounds.left + (int) delta.x,
stableBounds.left);
+ if (repositionTaskBounds.left == stableBounds.left
+ && repositionTaskBounds.left + (int) delta.x != stableBounds.left) {
+ // If the task edge have been set to the stable bounds and not due to the users
+ // drag, the aspect ratio of the task will not be maintained.
+ isAspectRatioMaintained = false;
+ }
}
if ((ctrlType & CTRL_TYPE_RIGHT) != 0) {
repositionTaskBounds.right = Math.min(repositionTaskBounds.right + (int) delta.x,
stableBounds.right);
+ if (repositionTaskBounds.right == stableBounds.right
+ && repositionTaskBounds.right + (int) delta.x != stableBounds.right) {
+ // If the task edge have been set to the stable bounds and not due to the users
+ // drag, the aspect ratio of the task will not be maintained.
+ isAspectRatioMaintained = false;
+ }
}
if ((ctrlType & CTRL_TYPE_TOP) != 0) {
repositionTaskBounds.top = Math.max(repositionTaskBounds.top + (int) delta.y,
stableBounds.top);
+ if (repositionTaskBounds.top == stableBounds.top
+ && repositionTaskBounds.top + (int) delta.y != stableBounds.top) {
+ // If the task edge have been set to the stable bounds and not due to the users
+ // drag, the aspect ratio of the task will not be maintained.
+ isAspectRatioMaintained = false;
+ }
}
if ((ctrlType & CTRL_TYPE_BOTTOM) != 0) {
repositionTaskBounds.bottom = Math.min(repositionTaskBounds.bottom + (int) delta.y,
stableBounds.bottom);
+ if (repositionTaskBounds.bottom == stableBounds.bottom
+ && repositionTaskBounds.bottom + (int) delta.y != stableBounds.bottom) {
+ // If the task edge have been set to the stable bounds and not due to the users
+ // drag, the aspect ratio of the task will not be maintained.
+ isAspectRatioMaintained = false;
+ }
}
// If width or height are negative or exceeding the width or height constraints, revert the
@@ -108,11 +133,24 @@
windowDecoration)) {
repositionTaskBounds.right = oldRight;
repositionTaskBounds.left = oldLeft;
+ isAspectRatioMaintained = false;
}
if (isExceedingHeightConstraint(repositionTaskBounds, stableBounds, displayController,
windowDecoration)) {
repositionTaskBounds.top = oldTop;
repositionTaskBounds.bottom = oldBottom;
+ isAspectRatioMaintained = false;
+ }
+
+ // If the application is unresizeable and any bounds have been set back to their old
+ // location or to a stable bound edge, reset all the bounds to maintain the applications
+ // aspect ratio.
+ if (DesktopModeFlags.SCALED_RESIZING.isEnabled(windowDecoration.mDecorWindowContext)
+ && !isAspectRatioMaintained && !windowDecoration.mTaskInfo.isResizeable) {
+ repositionTaskBounds.top = oldTop;
+ repositionTaskBounds.bottom = oldBottom;
+ repositionTaskBounds.right = oldRight;
+ repositionTaskBounds.left = oldLeft;
}
// If there are no changes to the bounds after checking new bounds against minimum and
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/FixedAspectRatioTaskPositionerDecorator.kt b/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/FixedAspectRatioTaskPositionerDecorator.kt
index e8131a0..3885761 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/FixedAspectRatioTaskPositionerDecorator.kt
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/FixedAspectRatioTaskPositionerDecorator.kt
@@ -16,8 +16,10 @@
package com.android.wm.shell.windowdecor
+import android.app.ActivityManager.RunningTaskInfo
import android.graphics.PointF
import android.graphics.Rect
+import com.android.internal.annotations.VisibleForTesting
import com.android.wm.shell.windowdecor.DragPositioningCallback.CTRL_TYPE_BOTTOM
import com.android.wm.shell.windowdecor.DragPositioningCallback.CTRL_TYPE_LEFT
import com.android.wm.shell.windowdecor.DragPositioningCallback.CTRL_TYPE_RIGHT
@@ -51,8 +53,7 @@
return super.onDragPositioningStart(originalCtrlType, x, y)
}
- lastRepositionedBounds.set(
- windowDecoration.mTaskInfo.configuration.windowConfiguration.bounds)
+ lastRepositionedBounds.set(getBounds(windowDecoration.mTaskInfo))
startingPoint.set(x, y)
lastValidPoint.set(x, y)
val startingBoundWidth = lastRepositionedBounds.width()
@@ -255,4 +256,9 @@
private fun requiresFixedAspectRatio(): Boolean {
return originalCtrlType.isResizing() && !windowDecoration.mTaskInfo.isResizeable
}
+
+ @VisibleForTesting
+ fun getBounds(taskInfo: RunningTaskInfo): Rect {
+ return taskInfo.configuration.windowConfiguration.bounds
+ }
}
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/desktopmode/DragToDesktopTransitionHandlerTest.kt b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/desktopmode/DragToDesktopTransitionHandlerTest.kt
index 5b02837..497d0e5 100644
--- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/desktopmode/DragToDesktopTransitionHandlerTest.kt
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/desktopmode/DragToDesktopTransitionHandlerTest.kt
@@ -18,6 +18,8 @@
import android.window.WindowContainerTransaction
import androidx.test.filters.SmallTest
import com.android.dx.mockito.inline.extended.ExtendedMockito
+import com.android.internal.jank.Cuj.CUJ_DESKTOP_MODE_ENTER_APP_HANDLE_DRAG_HOLD
+import com.android.internal.jank.Cuj.CUJ_DESKTOP_MODE_ENTER_APP_HANDLE_DRAG_RELEASE
import com.android.internal.jank.InteractionJankMonitor
import com.android.wm.shell.RootTaskDisplayAreaOrganizer
import com.android.wm.shell.ShellTestCase
@@ -448,6 +450,42 @@
)
}
+ @Test
+ fun startDragToDesktop_aborted_logsDragHoldCancelled() {
+ val transition = startDragToDesktopTransition(defaultHandler, createTask(), dragAnimator)
+
+ defaultHandler.onTransitionConsumed(transition, aborted = true, mock())
+
+ verify(mockInteractionJankMonitor).cancel(eq(CUJ_DESKTOP_MODE_ENTER_APP_HANDLE_DRAG_HOLD))
+ verify(mockInteractionJankMonitor, times(0)).cancel(
+ eq(CUJ_DESKTOP_MODE_ENTER_APP_HANDLE_DRAG_RELEASE))
+ }
+
+ @Test
+ fun mergeEndDragToDesktop_aborted_logsDragReleaseCancelled() {
+ val task = createTask()
+ val startTransition = startDrag(defaultHandler, task)
+ val endTransition = mock<IBinder>()
+ defaultHandler.onTaskResizeAnimationListener = mock()
+ defaultHandler.mergeAnimation(
+ transition = endTransition,
+ info = createTransitionInfo(
+ type = TRANSIT_DESKTOP_MODE_END_DRAG_TO_DESKTOP,
+ draggedTask = task
+ ),
+ t = mock<SurfaceControl.Transaction>(),
+ mergeTarget = startTransition,
+ finishCallback = mock<Transitions.TransitionFinishCallback>()
+ )
+
+ defaultHandler.onTransitionConsumed(endTransition, aborted = true, mock())
+
+ verify(mockInteractionJankMonitor)
+ .cancel(eq(CUJ_DESKTOP_MODE_ENTER_APP_HANDLE_DRAG_RELEASE))
+ verify(mockInteractionJankMonitor, times(0))
+ .cancel(eq(CUJ_DESKTOP_MODE_ENTER_APP_HANDLE_DRAG_HOLD))
+ }
+
private fun startDrag(
handler: DragToDesktopTransitionHandler,
task: RunningTaskInfo = createTask(),
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/draganddrop/DragAndDropPolicyTest.java b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/draganddrop/SplitDragPolicyTest.java
similarity index 92%
rename from libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/draganddrop/DragAndDropPolicyTest.java
rename to libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/draganddrop/SplitDragPolicyTest.java
index 645b296..46b60499 100644
--- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/draganddrop/DragAndDropPolicyTest.java
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/draganddrop/SplitDragPolicyTest.java
@@ -30,11 +30,11 @@
import static com.android.wm.shell.shared.split.SplitScreenConstants.SPLIT_POSITION_BOTTOM_OR_RIGHT;
import static com.android.wm.shell.shared.split.SplitScreenConstants.SPLIT_POSITION_TOP_OR_LEFT;
import static com.android.wm.shell.shared.split.SplitScreenConstants.SPLIT_POSITION_UNDEFINED;
-import static com.android.wm.shell.draganddrop.DragAndDropPolicy.Target.TYPE_FULLSCREEN;
-import static com.android.wm.shell.draganddrop.DragAndDropPolicy.Target.TYPE_SPLIT_BOTTOM;
-import static com.android.wm.shell.draganddrop.DragAndDropPolicy.Target.TYPE_SPLIT_LEFT;
-import static com.android.wm.shell.draganddrop.DragAndDropPolicy.Target.TYPE_SPLIT_RIGHT;
-import static com.android.wm.shell.draganddrop.DragAndDropPolicy.Target.TYPE_SPLIT_TOP;
+import static com.android.wm.shell.draganddrop.SplitDragPolicy.Target.TYPE_FULLSCREEN;
+import static com.android.wm.shell.draganddrop.SplitDragPolicy.Target.TYPE_SPLIT_BOTTOM;
+import static com.android.wm.shell.draganddrop.SplitDragPolicy.Target.TYPE_SPLIT_LEFT;
+import static com.android.wm.shell.draganddrop.SplitDragPolicy.Target.TYPE_SPLIT_RIGHT;
+import static com.android.wm.shell.draganddrop.SplitDragPolicy.Target.TYPE_SPLIT_TOP;
import static junit.framework.Assert.assertTrue;
import static junit.framework.Assert.fail;
@@ -72,7 +72,7 @@
import com.android.internal.logging.InstanceId;
import com.android.wm.shell.ShellTestCase;
import com.android.wm.shell.common.DisplayLayout;
-import com.android.wm.shell.draganddrop.DragAndDropPolicy.Target;
+import com.android.wm.shell.draganddrop.SplitDragPolicy.Target;
import com.android.wm.shell.splitscreen.SplitScreenController;
import org.junit.After;
@@ -92,7 +92,7 @@
*/
@SmallTest
@RunWith(AndroidJUnit4.class)
-public class DragAndDropPolicyTest extends ShellTestCase {
+public class SplitDragPolicyTest extends ShellTestCase {
@Mock
private Context mContext;
@@ -104,7 +104,7 @@
@Mock
private SplitScreenController mSplitScreenStarter;
@Mock
- private DragAndDropPolicy.Starter mFullscreenStarter;
+ private SplitDragPolicy.Starter mFullscreenStarter;
@Mock
private InstanceId mLoggerSessionId;
@@ -112,7 +112,7 @@
private DisplayLayout mLandscapeDisplayLayout;
private DisplayLayout mPortraitDisplayLayout;
private Insets mInsets;
- private DragAndDropPolicy mPolicy;
+ private SplitDragPolicy mPolicy;
private ClipData mActivityClipData;
private PendingIntent mLaunchableIntentPendingIntent;
@@ -150,7 +150,7 @@
mPortraitDisplayLayout = new DisplayLayout(info2, res, false, false);
mInsets = Insets.of(0, 0, 0, 0);
- mPolicy = spy(new DragAndDropPolicy(mContext, mSplitScreenStarter, mFullscreenStarter));
+ mPolicy = spy(new SplitDragPolicy(mContext, mSplitScreenStarter, mFullscreenStarter));
mActivityClipData = createAppClipData(MIMETYPE_APPLICATION_ACTIVITY);
mLaunchableIntentPendingIntent = mock(PendingIntent.class);
when(mLaunchableIntentPendingIntent.getCreatorUserHandle())
@@ -289,7 +289,7 @@
ArrayList<Target> targets = assertExactTargetTypes(
mPolicy.getTargets(mInsets), TYPE_FULLSCREEN);
- mPolicy.handleDrop(filterTargetByType(targets, TYPE_FULLSCREEN), null /* hideTaskToken */);
+ mPolicy.onDropped(filterTargetByType(targets, TYPE_FULLSCREEN), null /* hideTaskToken */);
verify(mFullscreenStarter).startIntent(any(), anyInt(), any(),
eq(SPLIT_POSITION_UNDEFINED), any(), any());
}
@@ -304,12 +304,12 @@
ArrayList<Target> targets = assertExactTargetTypes(
mPolicy.getTargets(mInsets), TYPE_SPLIT_LEFT, TYPE_SPLIT_RIGHT);
- mPolicy.handleDrop(filterTargetByType(targets, TYPE_SPLIT_LEFT), null /* hideTaskToken */);
+ mPolicy.onDropped(filterTargetByType(targets, TYPE_SPLIT_LEFT), null /* hideTaskToken */);
verify(mSplitScreenStarter).startIntent(any(), anyInt(), any(),
eq(SPLIT_POSITION_TOP_OR_LEFT), any(), any());
reset(mSplitScreenStarter);
- mPolicy.handleDrop(filterTargetByType(targets, TYPE_SPLIT_RIGHT), null /* hideTaskToken */);
+ mPolicy.onDropped(filterTargetByType(targets, TYPE_SPLIT_RIGHT), null /* hideTaskToken */);
verify(mSplitScreenStarter).startIntent(any(), anyInt(), any(),
eq(SPLIT_POSITION_BOTTOM_OR_RIGHT), any(), any());
}
@@ -324,12 +324,12 @@
ArrayList<Target> targets = assertExactTargetTypes(
mPolicy.getTargets(mInsets), TYPE_SPLIT_TOP, TYPE_SPLIT_BOTTOM);
- mPolicy.handleDrop(filterTargetByType(targets, TYPE_SPLIT_TOP), null /* hideTaskToken */);
+ mPolicy.onDropped(filterTargetByType(targets, TYPE_SPLIT_TOP), null /* hideTaskToken */);
verify(mSplitScreenStarter).startIntent(any(), anyInt(), any(),
eq(SPLIT_POSITION_TOP_OR_LEFT), any(), any());
reset(mSplitScreenStarter);
- mPolicy.handleDrop(filterTargetByType(targets, TYPE_SPLIT_BOTTOM),
+ mPolicy.onDropped(filterTargetByType(targets, TYPE_SPLIT_BOTTOM),
null /* hideTaskToken */);
verify(mSplitScreenStarter).startIntent(any(), anyInt(), any(),
eq(SPLIT_POSITION_BOTTOM_OR_RIGHT), any(), any());
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/pip/phone/PipControllerTest.java b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/pip/phone/PipControllerTest.java
index 6ddb678..f3944d5 100644
--- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/pip/phone/PipControllerTest.java
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/pip/phone/PipControllerTest.java
@@ -256,7 +256,7 @@
when(mMockPipDisplayLayoutState.getDisplayLayout()).thenReturn(mMockDisplayLayout1);
when(mMockDisplayController.getDisplayLayout(displayId)).thenReturn(mMockDisplayLayout2);
- when(mMockPipTaskOrganizer.isInPip()).thenReturn(true);
+ when(mMockPipTransitionState.hasEnteredPip()).thenReturn(true);
mPipController.mDisplaysChangedListener.onDisplayConfigurationChanged(
displayId, new Configuration());
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/windowdecor/DesktopModeWindowDecorationTests.java b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/windowdecor/DesktopModeWindowDecorationTests.java
index 1741fe4..69efdb8 100644
--- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/windowdecor/DesktopModeWindowDecorationTests.java
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/windowdecor/DesktopModeWindowDecorationTests.java
@@ -107,6 +107,7 @@
import org.junit.After;
import org.junit.Before;
import org.junit.BeforeClass;
+import org.junit.Ignore;
import org.junit.Rule;
import org.junit.Test;
import org.junit.runner.RunWith;
@@ -563,6 +564,7 @@
}
@Test
+ @Ignore("TODO(b/367235906): Due to MONITOR_INPUT permission error")
public void relayout_freeformTask_appliesTransactionOnDraw() {
final ActivityManager.RunningTaskInfo taskInfo = createTaskInfo(/* visible= */ true);
final DesktopModeWindowDecoration spyWindowDecor = spy(createWindowDecoration(taskInfo));
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/windowdecor/DragPositioningCallbackUtilityTest.kt b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/windowdecor/DragPositioningCallbackUtilityTest.kt
index 1f33ae6..24f6bec 100644
--- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/windowdecor/DragPositioningCallbackUtilityTest.kt
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/windowdecor/DragPositioningCallbackUtilityTest.kt
@@ -39,6 +39,7 @@
import com.android.wm.shell.windowdecor.DragPositioningCallback.CTRL_TYPE_RIGHT
import com.android.wm.shell.windowdecor.DragPositioningCallback.CTRL_TYPE_TOP
import com.google.common.truth.Truth.assertThat
+import junit.framework.Assert.assertFalse
import junit.framework.Assert.assertTrue
import org.junit.After
import org.junit.Before
@@ -105,6 +106,7 @@
initializeTaskInfo()
mockWindowDecoration.mDisplay = mockDisplay
mockWindowDecoration.mDecorWindowContext = mockContext
+ mockWindowDecoration.mTaskInfo.isResizeable = true
whenever(mockContext.getResources()).thenReturn(mockResources)
whenever(mockWindowDecoration.mDecorWindowContext.resources).thenReturn(mockResources)
whenever(mockResources.getDimensionPixelSize(R.dimen.desktop_mode_minimum_window_width))
@@ -164,6 +166,60 @@
}
@Test
+ @EnableFlags(Flags.FLAG_ENABLE_WINDOWING_SCALED_RESIZING)
+ fun testChangeBounds_unresizeableApp_heightLessThanMin_resetToStartingBounds() {
+ mockWindowDecoration.mTaskInfo.isResizeable = false
+ val startingPoint = PointF(STARTING_BOUNDS.right.toFloat(), STARTING_BOUNDS.top.toFloat())
+ val repositionTaskBounds = Rect(STARTING_BOUNDS)
+
+ // Resize to width of 95px and height of 5px with min width of 10px
+ val newX = STARTING_BOUNDS.right.toFloat() - 5
+ val newY = STARTING_BOUNDS.top.toFloat() + 95
+ val delta = DragPositioningCallbackUtility.calculateDelta(newX, newY, startingPoint)
+
+ assertFalse(
+ DragPositioningCallbackUtility.changeBounds(
+ CTRL_TYPE_RIGHT or CTRL_TYPE_TOP,
+ repositionTaskBounds, STARTING_BOUNDS, STABLE_BOUNDS, delta, mockDisplayController,
+ mockWindowDecoration
+ )
+ )
+
+ assertThat(repositionTaskBounds.left).isEqualTo(STARTING_BOUNDS.left)
+ assertThat(repositionTaskBounds.top).isEqualTo(STARTING_BOUNDS.top)
+ assertThat(repositionTaskBounds.right).isEqualTo(STARTING_BOUNDS.right)
+ assertThat(repositionTaskBounds.bottom).isEqualTo(STARTING_BOUNDS.bottom)
+ }
+
+ @Test
+ @EnableFlags(Flags.FLAG_ENABLE_WINDOWING_SCALED_RESIZING)
+ fun testChangeBounds_unresizeableApp_widthLessThanMin_resetToStartingBounds() {
+ mockWindowDecoration.mTaskInfo.isResizeable = false
+ val startingPoint = PointF(STARTING_BOUNDS.right.toFloat(), STARTING_BOUNDS.top.toFloat())
+ val repositionTaskBounds = Rect(STARTING_BOUNDS)
+
+ // Resize to height of 95px and width of 5px with min width of 10px
+ val newX = STARTING_BOUNDS.right.toFloat() - 95
+ val newY = STARTING_BOUNDS.top.toFloat() + 5
+ val delta = DragPositioningCallbackUtility.calculateDelta(newX, newY, startingPoint)
+
+ assertFalse(
+ DragPositioningCallbackUtility.changeBounds(
+ CTRL_TYPE_RIGHT or CTRL_TYPE_TOP,
+ repositionTaskBounds, STARTING_BOUNDS, STABLE_BOUNDS, delta, mockDisplayController,
+ mockWindowDecoration
+ )
+ )
+
+
+ assertThat(repositionTaskBounds.left).isEqualTo(STARTING_BOUNDS.left)
+ assertThat(repositionTaskBounds.top).isEqualTo(STARTING_BOUNDS.top)
+ assertThat(repositionTaskBounds.right).isEqualTo(STARTING_BOUNDS.right)
+ assertThat(repositionTaskBounds.bottom).isEqualTo(STARTING_BOUNDS.bottom)
+ }
+
+
+ @Test
fun testChangeBoundsDoesNotChangeHeightWhenNegative() {
val startingPoint = PointF(STARTING_BOUNDS.right.toFloat(), STARTING_BOUNDS.top.toFloat())
val repositionTaskBounds = Rect(STARTING_BOUNDS)
@@ -317,6 +373,34 @@
}
@Test
+ @EnableFlags(Flags.FLAG_ENABLE_WINDOWING_SCALED_RESIZING)
+ fun testChangeBounds_unresizeableApp_beyondStableBounds_resetToStartingBounds() {
+ mockWindowDecoration.mTaskInfo.isResizeable = false
+ val startingPoint = PointF(
+ STARTING_BOUNDS.right.toFloat(),
+ STARTING_BOUNDS.bottom.toFloat()
+ )
+ val repositionTaskBounds = Rect(STARTING_BOUNDS)
+
+ // Resize to beyond stable bounds.
+ val newX = STARTING_BOUNDS.right.toFloat() + STABLE_BOUNDS.width()
+ val newY = STARTING_BOUNDS.bottom.toFloat() + STABLE_BOUNDS.height()
+
+ val delta = DragPositioningCallbackUtility.calculateDelta(newX, newY, startingPoint)
+ assertFalse(
+ DragPositioningCallbackUtility.changeBounds(
+ CTRL_TYPE_RIGHT or CTRL_TYPE_BOTTOM,
+ repositionTaskBounds, STARTING_BOUNDS, STABLE_BOUNDS, delta, mockDisplayController,
+ mockWindowDecoration
+ )
+ )
+ assertThat(repositionTaskBounds.left).isEqualTo(STARTING_BOUNDS.left)
+ assertThat(repositionTaskBounds.top).isEqualTo(STARTING_BOUNDS.top)
+ assertThat(repositionTaskBounds.right).isEqualTo(STARTING_BOUNDS.right)
+ assertThat(repositionTaskBounds.bottom).isEqualTo(STARTING_BOUNDS.bottom)
+ }
+
+ @Test
@EnableFlags(Flags.FLAG_ENABLE_DESKTOP_WINDOWING_SIZE_CONSTRAINTS)
fun taskMinWidthHeightUndefined_changeBoundsInDesktopModeLessThanMin_shouldNotChangeBounds() {
doReturn(true).`when` { DesktopModeStatus.canEnterDesktopMode(mockContext) }
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/windowdecor/FixedAspectRatioTaskPositionerDecoratorTests.kt b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/windowdecor/FixedAspectRatioTaskPositionerDecoratorTests.kt
new file mode 100644
index 0000000..ce17c1d
--- /dev/null
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/windowdecor/FixedAspectRatioTaskPositionerDecoratorTests.kt
@@ -0,0 +1,636 @@
+/*
+ * 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 com.android.wm.shell.windowdecor
+
+import android.app.ActivityManager
+import android.graphics.PointF
+import android.graphics.Rect
+import android.util.MathUtils.abs
+import android.util.MathUtils.max
+import androidx.test.filters.SmallTest
+import com.android.wm.shell.ShellTestCase
+import com.android.wm.shell.windowdecor.DragPositioningCallback.CTRL_TYPE_BOTTOM
+import com.android.wm.shell.windowdecor.DragPositioningCallback.CTRL_TYPE_LEFT
+import com.android.wm.shell.windowdecor.DragPositioningCallback.CTRL_TYPE_RIGHT
+import com.android.wm.shell.windowdecor.DragPositioningCallback.CTRL_TYPE_TOP
+import com.android.wm.shell.windowdecor.DragPositioningCallback.CTRL_TYPE_UNDEFINED
+import com.android.wm.shell.windowdecor.DragPositioningCallback.CtrlType
+import com.google.common.truth.Truth.assertThat
+import com.google.testing.junit.testparameterinjector.TestParameter
+import com.google.testing.junit.testparameterinjector.TestParameterInjector
+import kotlin.math.min
+import org.junit.Before
+import org.junit.Test
+import org.junit.runner.RunWith
+import org.mockito.Mock
+import org.mockito.Mockito.spy
+import org.mockito.Mockito.verify
+import org.mockito.kotlin.any
+import org.mockito.kotlin.argumentCaptor
+import org.mockito.kotlin.doReturn
+import org.mockito.kotlin.never
+
+/**
+ * Tests for the [FixedAspectRatioTaskPositionerDecorator], written in parameterized form to check
+ * decorators behaviour for different variations of drag actions.
+ *
+ * Build/Install/Run:
+ * atest WMShellUnitTests:FixedAspectRatioTaskPositionerDecoratorTests
+ */
+@SmallTest
+@RunWith(TestParameterInjector::class)
+class FixedAspectRatioTaskPositionerDecoratorTests : ShellTestCase(){
+ @Mock
+ private lateinit var mockDesktopWindowDecoration: DesktopModeWindowDecoration
+ @Mock
+ private lateinit var mockTaskPositioner: VeiledResizeTaskPositioner
+
+ private lateinit var decoratedTaskPositioner: FixedAspectRatioTaskPositionerDecorator
+
+ @Before
+ fun setUp() {
+ mockDesktopWindowDecoration.mTaskInfo = ActivityManager.RunningTaskInfo().apply {
+ isResizeable = false
+ configuration.windowConfiguration.setBounds(PORTRAIT_BOUNDS)
+ }
+ doReturn(PORTRAIT_BOUNDS).`when`(mockTaskPositioner).onDragPositioningStart(
+ any(), any(), any())
+ doReturn(Rect()).`when`(mockTaskPositioner).onDragPositioningMove(any(), any())
+ doReturn(Rect()).`when`(mockTaskPositioner).onDragPositioningEnd(any(), any())
+ decoratedTaskPositioner = spy(
+ FixedAspectRatioTaskPositionerDecorator(
+ mockDesktopWindowDecoration, mockTaskPositioner)
+ )
+ }
+
+ @Test
+ fun testOnDragPositioningStart_noAdjustment(
+ @TestParameter testCase: ResizeableOrNotResizingTestCases
+ ) {
+ val originalX = 0f
+ val originalY = 0f
+ mockDesktopWindowDecoration.mTaskInfo = ActivityManager.RunningTaskInfo().apply {
+ isResizeable = testCase.isResizeable
+ }
+
+ decoratedTaskPositioner.onDragPositioningStart(testCase.ctrlType, originalX, originalY)
+
+ val capturedValues = getLatestOnStartArguments()
+ assertThat(capturedValues.ctrlType).isEqualTo(testCase.ctrlType)
+ assertThat(capturedValues.x).isEqualTo(originalX)
+ assertThat(capturedValues.y).isEqualTo(originalY)
+ }
+
+ @Test
+ fun testOnDragPositioningStart_cornerResize_noAdjustment(
+ @TestParameter testCase: CornerResizeStartTestCases
+ ) {
+ val originalX = 0f
+ val originalY = 0f
+
+ decoratedTaskPositioner.onDragPositioningStart(testCase.ctrlType, originalX, originalY)
+
+ val capturedValues = getLatestOnStartArguments()
+ assertThat(capturedValues.ctrlType).isEqualTo(testCase.ctrlType)
+ assertThat(capturedValues.x).isEqualTo(originalX)
+ assertThat(capturedValues.y).isEqualTo(originalY)
+ }
+
+ @Test
+ fun testOnDragPositioningStart_edgeResize_ctrlTypeAdjusted(
+ @TestParameter testCase: EdgeResizeStartTestCases, @TestParameter orientation: Orientation
+ ) {
+ val startingBounds = getAndMockBounds(orientation)
+ val startingPoint = getEdgeStartingPoint(
+ testCase.ctrlType, testCase.additionalEdgeCtrlType, startingBounds)
+
+ decoratedTaskPositioner.onDragPositioningStart(
+ testCase.ctrlType, startingPoint.x, startingPoint.y)
+
+ val adjustedCtrlType = testCase.ctrlType + testCase.additionalEdgeCtrlType
+ val capturedValues = getLatestOnStartArguments()
+ assertThat(capturedValues.ctrlType).isEqualTo(adjustedCtrlType)
+ assertThat(capturedValues.x).isEqualTo(startingPoint.x)
+ assertThat(capturedValues.y).isEqualTo(startingPoint.y)
+ }
+
+ @Test
+ fun testOnDragPositioningMove_noAdjustment(
+ @TestParameter testCase: ResizeableOrNotResizingTestCases
+ ) {
+ val originalX = 0f
+ val originalY = 0f
+ decoratedTaskPositioner.onDragPositioningStart(testCase.ctrlType, originalX, originalX)
+ mockDesktopWindowDecoration.mTaskInfo = ActivityManager.RunningTaskInfo().apply {
+ isResizeable = testCase.isResizeable
+ }
+
+ decoratedTaskPositioner.onDragPositioningMove(
+ originalX + SMALL_DELTA, originalY + SMALL_DELTA)
+
+ val capturedValues = getLatestOnMoveArguments()
+ assertThat(capturedValues.x).isEqualTo(originalX + SMALL_DELTA)
+ assertThat(capturedValues.y).isEqualTo(originalY + SMALL_DELTA)
+ }
+
+ @Test
+ fun testOnDragPositioningMove_cornerResize_invalidRegion_noResize(
+ @TestParameter testCase: InvalidCornerResizeTestCases,
+ @TestParameter orientation: Orientation
+ ) {
+ val startingBounds = getAndMockBounds(orientation)
+ val startingPoint = getCornerStartingPoint(testCase.ctrlType, startingBounds)
+
+ decoratedTaskPositioner.onDragPositioningStart(
+ testCase.ctrlType, startingPoint.x, startingPoint.y)
+
+ val updatedBounds = decoratedTaskPositioner.onDragPositioningMove(
+ startingPoint.x + testCase.dragDelta.x,
+ startingPoint.y + testCase.dragDelta.y)
+
+ verify(mockTaskPositioner, never()).onDragPositioningMove(any(), any())
+ assertThat(updatedBounds).isEqualTo(startingBounds)
+ }
+
+
+ @Test
+ fun testOnDragPositioningMove_cornerResize_validRegion_resizeToAdjustedCoordinates(
+ @TestParameter testCase: ValidCornerResizeTestCases,
+ @TestParameter orientation: Orientation
+ ) {
+ val startingBounds = getAndMockBounds(orientation)
+ val startingPoint = getCornerStartingPoint(testCase.ctrlType, startingBounds)
+
+ decoratedTaskPositioner.onDragPositioningStart(
+ testCase.ctrlType, startingPoint.x, startingPoint.y)
+
+ decoratedTaskPositioner.onDragPositioningMove(
+ startingPoint.x + testCase.dragDelta.x, startingPoint.y + testCase.dragDelta.y)
+
+ val adjustedDragDelta = calculateAdjustedDelta(
+ testCase.ctrlType, testCase.dragDelta, orientation)
+ val capturedValues = getLatestOnMoveArguments()
+ val absChangeX = abs(capturedValues.x - startingPoint.x)
+ val absChangeY = abs(capturedValues.y - startingPoint.y)
+ val resultAspectRatio = max(absChangeX, absChangeY) / min(absChangeX, absChangeY)
+ assertThat(capturedValues.x).isEqualTo(startingPoint.x + adjustedDragDelta.x)
+ assertThat(capturedValues.y).isEqualTo(startingPoint.y + adjustedDragDelta.y)
+ assertThat(resultAspectRatio).isEqualTo(STARTING_ASPECT_RATIO)
+ }
+
+ @Test
+ fun testOnDragPositioningMove_edgeResize_resizeToAdjustedCoordinates(
+ @TestParameter testCase: EdgeResizeTestCases,
+ @TestParameter orientation: Orientation
+ ) {
+ val startingBounds = getAndMockBounds(orientation)
+ val startingPoint = getEdgeStartingPoint(
+ testCase.ctrlType, testCase.additionalEdgeCtrlType, startingBounds)
+
+ decoratedTaskPositioner.onDragPositioningStart(
+ testCase.ctrlType, startingPoint.x, startingPoint.y)
+
+ decoratedTaskPositioner.onDragPositioningMove(
+ startingPoint.x + testCase.dragDelta.x,
+ startingPoint.y + testCase.dragDelta.y)
+
+ val adjustedDragDelta = calculateAdjustedDelta(
+ testCase.ctrlType + testCase.additionalEdgeCtrlType,
+ testCase.dragDelta,
+ orientation)
+ val capturedValues = getLatestOnMoveArguments()
+ val absChangeX = abs(capturedValues.x - startingPoint.x)
+ val absChangeY = abs(capturedValues.y - startingPoint.y)
+ val resultAspectRatio = max(absChangeX, absChangeY) / min(absChangeX, absChangeY)
+ assertThat(capturedValues.x).isEqualTo(startingPoint.x + adjustedDragDelta.x)
+ assertThat(capturedValues.y).isEqualTo(startingPoint.y + adjustedDragDelta.y)
+ assertThat(resultAspectRatio).isEqualTo(STARTING_ASPECT_RATIO)
+ }
+
+ @Test
+ fun testOnDragPositioningEnd_noAdjustment(
+ @TestParameter testCase: ResizeableOrNotResizingTestCases
+ ) {
+ val originalX = 0f
+ val originalY = 0f
+ decoratedTaskPositioner.onDragPositioningStart(testCase.ctrlType, originalX, originalX)
+ mockDesktopWindowDecoration.mTaskInfo = ActivityManager.RunningTaskInfo().apply {
+ isResizeable = testCase.isResizeable
+ }
+
+ decoratedTaskPositioner.onDragPositioningEnd(
+ originalX + SMALL_DELTA, originalY + SMALL_DELTA)
+
+ val capturedValues = getLatestOnEndArguments()
+ assertThat(capturedValues.x).isEqualTo(originalX + SMALL_DELTA)
+ assertThat(capturedValues.y).isEqualTo(originalY + SMALL_DELTA)
+ }
+
+ @Test
+ fun testOnDragPositioningEnd_cornerResize_invalidRegion_endsAtPreviousValidPoint(
+ @TestParameter testCase: InvalidCornerResizeTestCases,
+ @TestParameter orientation: Orientation
+ ) {
+ val startingBounds = getAndMockBounds(orientation)
+ val startingPoint = getCornerStartingPoint(testCase.ctrlType, startingBounds)
+
+ decoratedTaskPositioner.onDragPositioningStart(
+ testCase.ctrlType, startingPoint.x, startingPoint.y)
+
+ decoratedTaskPositioner.onDragPositioningEnd(
+ startingPoint.x + testCase.dragDelta.x,
+ startingPoint.y + testCase.dragDelta.y)
+
+ val capturedValues = getLatestOnEndArguments()
+ assertThat(capturedValues.x).isEqualTo(startingPoint.x)
+ assertThat(capturedValues.y).isEqualTo(startingPoint.y)
+ }
+
+ @Test
+ fun testOnDragPositioningEnd_cornerResize_validRegion_endAtAdjustedCoordinates(
+ @TestParameter testCase: ValidCornerResizeTestCases,
+ @TestParameter orientation: Orientation
+ ) {
+ val startingBounds = getAndMockBounds(orientation)
+ val startingPoint = getCornerStartingPoint(testCase.ctrlType, startingBounds)
+
+ decoratedTaskPositioner.onDragPositioningStart(
+ testCase.ctrlType, startingPoint.x, startingPoint.y)
+
+ decoratedTaskPositioner.onDragPositioningEnd(
+ startingPoint.x + testCase.dragDelta.x, startingPoint.y + testCase.dragDelta.y)
+
+ val adjustedDragDelta = calculateAdjustedDelta(
+ testCase.ctrlType, testCase.dragDelta, orientation)
+ val capturedValues = getLatestOnEndArguments()
+ val absChangeX = abs(capturedValues.x - startingPoint.x)
+ val absChangeY = abs(capturedValues.y - startingPoint.y)
+ val resultAspectRatio = max(absChangeX, absChangeY) / min(absChangeX, absChangeY)
+ assertThat(capturedValues.x).isEqualTo(startingPoint.x + adjustedDragDelta.x)
+ assertThat(capturedValues.y).isEqualTo(startingPoint.y + adjustedDragDelta.y)
+ assertThat(resultAspectRatio).isEqualTo(STARTING_ASPECT_RATIO)
+ }
+
+ @Test
+ fun testOnDragPositioningEnd_edgeResize_endAtAdjustedCoordinates(
+ @TestParameter testCase: EdgeResizeTestCases,
+ @TestParameter orientation: Orientation
+ ) {
+ val startingBounds = getAndMockBounds(orientation)
+ val startingPoint = getEdgeStartingPoint(
+ testCase.ctrlType, testCase.additionalEdgeCtrlType, startingBounds)
+
+ decoratedTaskPositioner.onDragPositioningStart(
+ testCase.ctrlType, startingPoint.x, startingPoint.y)
+
+ decoratedTaskPositioner.onDragPositioningEnd(
+ startingPoint.x + testCase.dragDelta.x,
+ startingPoint.y + testCase.dragDelta.y)
+
+ val adjustedDragDelta = calculateAdjustedDelta(
+ testCase.ctrlType + testCase.additionalEdgeCtrlType,
+ testCase.dragDelta,
+ orientation)
+ val capturedValues = getLatestOnEndArguments()
+ val absChangeX = abs(capturedValues.x - startingPoint.x)
+ val absChangeY = abs(capturedValues.y - startingPoint.y)
+ val resultAspectRatio = max(absChangeX, absChangeY) / min(absChangeX, absChangeY)
+ assertThat(capturedValues.x).isEqualTo(startingPoint.x + adjustedDragDelta.x)
+ assertThat(capturedValues.y).isEqualTo(startingPoint.y + adjustedDragDelta.y)
+ assertThat(resultAspectRatio).isEqualTo(STARTING_ASPECT_RATIO)
+ }
+
+ /**
+ * Returns the most recent arguments passed to the `.onPositioningStart()` of the
+ * [mockTaskPositioner].
+ */
+ private fun getLatestOnStartArguments(): CtrlCoordinateCapture {
+ val captorCtrlType = argumentCaptor<Int>()
+ val captorCoordinates = argumentCaptor<Float>()
+ verify(mockTaskPositioner).onDragPositioningStart(
+ captorCtrlType.capture(), captorCoordinates.capture(), captorCoordinates.capture())
+
+ return CtrlCoordinateCapture(captorCtrlType.firstValue, captorCoordinates.firstValue,
+ captorCoordinates.secondValue)
+ }
+
+ /**
+ * Returns the most recent arguments passed to the `.onPositioningMove()` of the
+ * [mockTaskPositioner].
+ */
+ private fun getLatestOnMoveArguments(): PointF {
+ val captorCoordinates = argumentCaptor<Float>()
+ verify(mockTaskPositioner).onDragPositioningMove(
+ captorCoordinates.capture(), captorCoordinates.capture())
+
+ return PointF(captorCoordinates.firstValue, captorCoordinates.secondValue)
+ }
+
+ /**
+ * Returns the most recent arguments passed to the `.onPositioningEnd()` of the
+ * [mockTaskPositioner].
+ */
+ private fun getLatestOnEndArguments(): PointF {
+ val captorCoordinates = argumentCaptor<Float>()
+ verify(mockTaskPositioner).onDragPositioningEnd(
+ captorCoordinates.capture(), captorCoordinates.capture())
+
+ return PointF(captorCoordinates.firstValue, captorCoordinates.secondValue)
+ }
+
+ /**
+ * Mocks the app bounds to correspond with a given orientation and returns the mocked bounds.
+ */
+ private fun getAndMockBounds(orientation: Orientation): Rect {
+ val mockBounds = if (orientation.isPortrait) PORTRAIT_BOUNDS else LANDSCAPE_BOUNDS
+ doReturn(mockBounds).`when`(mockTaskPositioner).onDragPositioningStart(
+ any(), any(), any())
+ doReturn(mockBounds).`when`(decoratedTaskPositioner).getBounds(any())
+ return mockBounds
+ }
+
+ /**
+ * Calculates the corner point a given drag action should start from, based on the [ctrlType],
+ * given the [startingBounds].
+ */
+ private fun getCornerStartingPoint(@CtrlType ctrlType: Int, startingBounds: Rect): PointF {
+ return when (ctrlType) {
+ CTRL_TYPE_BOTTOM + CTRL_TYPE_RIGHT ->
+ PointF(startingBounds.right.toFloat(), startingBounds.bottom.toFloat())
+
+ CTRL_TYPE_BOTTOM + CTRL_TYPE_LEFT ->
+ PointF(startingBounds.left.toFloat(), startingBounds.bottom.toFloat())
+
+ CTRL_TYPE_TOP + CTRL_TYPE_RIGHT ->
+ PointF(startingBounds.right.toFloat(), startingBounds.top.toFloat())
+ // CTRL_TYPE_TOP + CTRL_TYPE_LEFT
+ else ->
+ PointF(startingBounds.left.toFloat(), startingBounds.top.toFloat())
+ }
+ }
+
+ /**
+ * Calculates the point along an edge the edge resize should start from, based on the starting
+ * edge ([edgeCtrlType]) and the additional edge we expect to resize ([additionalEdgeCtrlType]),
+ * given the [startingBounds].
+ */
+ private fun getEdgeStartingPoint(
+ @CtrlType edgeCtrlType: Int, @CtrlType additionalEdgeCtrlType: Int, startingBounds: Rect
+ ): PointF {
+ val simulatedCorner = getCornerStartingPoint(
+ edgeCtrlType + additionalEdgeCtrlType, startingBounds)
+ when (additionalEdgeCtrlType) {
+ CTRL_TYPE_TOP -> {
+ simulatedCorner.offset(0f, -SMALL_DELTA)
+ return simulatedCorner
+ }
+ CTRL_TYPE_BOTTOM -> {
+ simulatedCorner.offset(0f, SMALL_DELTA)
+ return simulatedCorner
+ }
+ CTRL_TYPE_LEFT -> {
+ simulatedCorner.offset(SMALL_DELTA, 0f)
+ return simulatedCorner
+ }
+ // CTRL_TYPE_RIGHT
+ else -> {
+ simulatedCorner.offset(-SMALL_DELTA, 0f)
+ return simulatedCorner
+ }
+ }
+ }
+
+ /**
+ * Calculates the adjustments to the drag delta we expect for a given action and orientation.
+ */
+ private fun calculateAdjustedDelta(
+ @CtrlType ctrlType: Int, delta: PointF, orientation: Orientation
+ ): PointF {
+ if ((abs(delta.x) < abs(delta.y) && delta.x != 0f) || delta.y == 0f) {
+ // Only respect x delta if it's less than y delta but non-zero (i.e there is a change
+ // in x to be applied), or if the y delta is zero (i.e there is no change in y to be
+ // applied).
+ val adjustedY = if (orientation.isPortrait)
+ delta.x * STARTING_ASPECT_RATIO else
+ delta.x / STARTING_ASPECT_RATIO
+ if (ctrlType.isBottomRightOrTopLeftCorner()) {
+ return PointF(delta.x, adjustedY)
+ }
+ return PointF(delta.x, -adjustedY)
+ }
+ // Respect y delta.
+ val adjustedX = if (orientation.isPortrait)
+ delta.y / STARTING_ASPECT_RATIO else
+ delta.y * STARTING_ASPECT_RATIO
+ if (ctrlType.isBottomRightOrTopLeftCorner()) {
+ return PointF(adjustedX, delta.y)
+ }
+ return PointF(-adjustedX, delta.y)
+ }
+
+ private fun @receiver:CtrlType Int.isBottomRightOrTopLeftCorner(): Boolean {
+ return this == CTRL_TYPE_BOTTOM + CTRL_TYPE_RIGHT || this == CTRL_TYPE_TOP + CTRL_TYPE_LEFT
+ }
+
+ private inner class CtrlCoordinateCapture(ctrl: Int, xValue: Float, yValue: Float) {
+ var ctrlType = ctrl
+ var x = xValue
+ var y = yValue
+ }
+
+ companion object {
+ private val PORTRAIT_BOUNDS = Rect(100, 100, 200, 400)
+ private val LANDSCAPE_BOUNDS = Rect(100, 100, 400, 200)
+ private val STARTING_ASPECT_RATIO = PORTRAIT_BOUNDS.height() / PORTRAIT_BOUNDS.width()
+ private const val LARGE_DELTA = 50f
+ private const val SMALL_DELTA = 30f
+
+ enum class Orientation(
+ val isPortrait: Boolean
+ ) {
+ PORTRAIT (true),
+ LANDSCAPE (false)
+ }
+
+ enum class ResizeableOrNotResizingTestCases(
+ val ctrlType: Int,
+ val isResizeable: Boolean
+ ) {
+ NotResizing (CTRL_TYPE_UNDEFINED, false),
+ Resizeable (CTRL_TYPE_RIGHT, true)
+ }
+
+ /**
+ * Tests cases for the start of a corner resize.
+ * @param ctrlType the control type of the corner the resize is initiated on.
+ */
+ enum class CornerResizeStartTestCases(
+ val ctrlType: Int
+ ) {
+ BottomRightCorner (CTRL_TYPE_BOTTOM + CTRL_TYPE_RIGHT),
+ BottomLeftCorner (CTRL_TYPE_BOTTOM + CTRL_TYPE_LEFT),
+ TopRightCorner (CTRL_TYPE_TOP + CTRL_TYPE_RIGHT),
+ TopLeftCorner (CTRL_TYPE_TOP + CTRL_TYPE_LEFT)
+ }
+
+ /**
+ * Tests cases for the moving and ending of a invalid corner resize. Where the compass point
+ * (e.g `SouthEast`) represents the direction of the drag.
+ * @param ctrlType the control type of the corner the resize is initiated on.
+ * @param dragDelta the delta of the attempted drag action, from the [ctrlType]'s
+ * corresponding corner point. Represented as a combination a different signed small and
+ * large deltas which correspond to the direction/angle of drag.
+ */
+ enum class InvalidCornerResizeTestCases(
+ val ctrlType: Int,
+ val dragDelta: PointF
+ ) {
+ BottomRightCornerNorthEastDrag (
+ CTRL_TYPE_BOTTOM + CTRL_TYPE_RIGHT,
+ PointF(LARGE_DELTA, -LARGE_DELTA)),
+ BottomRightCornerSouthWestDrag (
+ CTRL_TYPE_BOTTOM + CTRL_TYPE_RIGHT,
+ PointF(-LARGE_DELTA, LARGE_DELTA)),
+ TopLeftCornerNorthEastDrag (
+ CTRL_TYPE_TOP + CTRL_TYPE_LEFT,
+ PointF(LARGE_DELTA, -LARGE_DELTA)),
+ TopLeftCornerSouthWestDrag (
+ CTRL_TYPE_TOP + CTRL_TYPE_LEFT,
+ PointF(-LARGE_DELTA, LARGE_DELTA)),
+ BottomLeftCornerSouthEastDrag (
+ CTRL_TYPE_BOTTOM + CTRL_TYPE_LEFT,
+ PointF(LARGE_DELTA, LARGE_DELTA)),
+ BottomLeftCornerNorthWestDrag (
+ CTRL_TYPE_BOTTOM + CTRL_TYPE_LEFT,
+ PointF(-LARGE_DELTA, -LARGE_DELTA)),
+ TopRightCornerSouthEastDrag (
+ CTRL_TYPE_TOP + CTRL_TYPE_RIGHT,
+ PointF(LARGE_DELTA, LARGE_DELTA)),
+ TopRightCornerNorthWestDrag (
+ CTRL_TYPE_TOP + CTRL_TYPE_RIGHT,
+ PointF(-LARGE_DELTA, -LARGE_DELTA)),
+ }
+
+ /**
+ * Tests cases for the moving and ending of a valid corner resize. Where the compass point
+ * (e.g `SouthEast`) represents the direction of the drag, followed by the expected
+ * behaviour in that direction (i.e `RespectY` means the y delta will be respected whereas
+ * `RespectX` means the x delta will be respected).
+ * @param ctrlType the control type of the corner the resize is initiated on.
+ * @param dragDelta the delta of the attempted drag action, from the [ctrlType]'s
+ * corresponding corner point. Represented as a combination a different signed small and
+ * large deltas which correspond to the direction/angle of drag.
+ */
+ enum class ValidCornerResizeTestCases(
+ val ctrlType: Int,
+ val dragDelta: PointF,
+ ) {
+ BottomRightCornerSouthEastDragRespectY (
+ CTRL_TYPE_BOTTOM + CTRL_TYPE_RIGHT,
+ PointF(+LARGE_DELTA, SMALL_DELTA)),
+ BottomRightCornerSouthEastDragRespectX (
+ CTRL_TYPE_BOTTOM + CTRL_TYPE_RIGHT,
+ PointF(SMALL_DELTA, LARGE_DELTA)),
+ BottomRightCornerNorthWestDragRespectY (
+ CTRL_TYPE_BOTTOM + CTRL_TYPE_RIGHT,
+ PointF(-LARGE_DELTA, -SMALL_DELTA)),
+ BottomRightCornerNorthWestDragRespectX (
+ CTRL_TYPE_BOTTOM + CTRL_TYPE_RIGHT,
+ PointF(-SMALL_DELTA, -LARGE_DELTA)),
+ TopLeftCornerSouthEastDragRespectY (
+ CTRL_TYPE_TOP + CTRL_TYPE_LEFT,
+ PointF(LARGE_DELTA, SMALL_DELTA)),
+ TopLeftCornerSouthEastDragRespectX (
+ CTRL_TYPE_TOP + CTRL_TYPE_LEFT,
+ PointF(SMALL_DELTA, LARGE_DELTA)),
+ TopLeftCornerNorthWestDragRespectY (
+ CTRL_TYPE_TOP + CTRL_TYPE_LEFT,
+ PointF(-LARGE_DELTA, -SMALL_DELTA)),
+ TopLeftCornerNorthWestDragRespectX (
+ CTRL_TYPE_TOP + CTRL_TYPE_LEFT,
+ PointF(-SMALL_DELTA, -LARGE_DELTA)),
+ BottomLeftCornerSouthWestDragRespectY (
+ CTRL_TYPE_BOTTOM + CTRL_TYPE_LEFT,
+ PointF(-LARGE_DELTA, SMALL_DELTA)),
+ BottomLeftCornerSouthWestDragRespectX (
+ CTRL_TYPE_BOTTOM + CTRL_TYPE_LEFT,
+ PointF(-SMALL_DELTA, LARGE_DELTA)),
+ BottomLeftCornerNorthEastDragRespectY (
+ CTRL_TYPE_BOTTOM + CTRL_TYPE_LEFT,
+ PointF(LARGE_DELTA, -SMALL_DELTA)),
+ BottomLeftCornerNorthEastDragRespectX (
+ CTRL_TYPE_BOTTOM + CTRL_TYPE_LEFT,
+ PointF(SMALL_DELTA, -LARGE_DELTA)),
+ TopRightCornerSouthWestDragRespectY (
+ CTRL_TYPE_TOP + CTRL_TYPE_RIGHT,
+ PointF(-LARGE_DELTA, SMALL_DELTA)),
+ TopRightCornerSouthWestDragRespectX (
+ CTRL_TYPE_TOP + CTRL_TYPE_RIGHT,
+ PointF(-SMALL_DELTA, LARGE_DELTA)),
+ TopRightCornerNorthEastDragRespectY (
+ CTRL_TYPE_TOP + CTRL_TYPE_RIGHT,
+ PointF(LARGE_DELTA, -SMALL_DELTA)),
+ TopRightCornerNorthEastDragRespectX (
+ CTRL_TYPE_TOP + CTRL_TYPE_RIGHT,
+ PointF(+SMALL_DELTA, -LARGE_DELTA))
+ }
+
+ /**
+ * Tests cases for the start of an edge resize.
+ * @param ctrlType the control type of the edge the resize is initiated on.
+ * @param additionalEdgeCtrlType the expected additional edge to be included in the ctrl
+ * type.
+ */
+ enum class EdgeResizeStartTestCases(
+ val ctrlType: Int,
+ val additionalEdgeCtrlType: Int
+ ) {
+ BottomOfLeftEdgeResize (CTRL_TYPE_LEFT, CTRL_TYPE_BOTTOM),
+ TopOfLeftEdgeResize (CTRL_TYPE_LEFT, CTRL_TYPE_TOP),
+ BottomOfRightEdgeResize (CTRL_TYPE_RIGHT, CTRL_TYPE_BOTTOM),
+ TopOfRightEdgeResize (CTRL_TYPE_RIGHT, CTRL_TYPE_TOP),
+ RightOfTopEdgeResize (CTRL_TYPE_TOP, CTRL_TYPE_RIGHT),
+ LeftOfTopEdgeResize (CTRL_TYPE_TOP, CTRL_TYPE_LEFT),
+ RightOfBottomEdgeResize (CTRL_TYPE_BOTTOM, CTRL_TYPE_RIGHT),
+ LeftOfBottomEdgeResize (CTRL_TYPE_BOTTOM, CTRL_TYPE_LEFT)
+ }
+
+ /**
+ * Tests cases for the moving and ending of an edge resize.
+ * @param ctrlType the control type of the edge the resize is initiated on.
+ * @param additionalEdgeCtrlType the expected additional edge to be included in the ctrl
+ * type.
+ * @param dragDelta the delta of the attempted drag action, from the [ctrlType]'s
+ * corresponding edge point. Represented as a combination a different signed small and
+ * large deltas which correspond to the direction/angle of drag.
+ */
+ enum class EdgeResizeTestCases(
+ val ctrlType: Int,
+ val additionalEdgeCtrlType: Int,
+ val dragDelta: PointF
+ ) {
+ BottomOfLeftEdgeResize (CTRL_TYPE_LEFT, CTRL_TYPE_BOTTOM, PointF(-SMALL_DELTA, 0f)),
+ TopOfLeftEdgeResize (CTRL_TYPE_LEFT, CTRL_TYPE_TOP, PointF(-SMALL_DELTA, 0f)),
+ BottomOfRightEdgeResize (CTRL_TYPE_RIGHT, CTRL_TYPE_BOTTOM, PointF(SMALL_DELTA, 0f)),
+ TopOfRightEdgeResize (CTRL_TYPE_RIGHT, CTRL_TYPE_TOP, PointF(SMALL_DELTA, 0f)),
+ RightOfTopEdgeResize (CTRL_TYPE_TOP, CTRL_TYPE_RIGHT, PointF(0f, -SMALL_DELTA)),
+ LeftOfTopEdgeResize (CTRL_TYPE_TOP, CTRL_TYPE_LEFT, PointF(0f, -SMALL_DELTA)),
+ RightOfBottomEdgeResize (CTRL_TYPE_BOTTOM, CTRL_TYPE_RIGHT, PointF(0f, SMALL_DELTA)),
+ LeftOfBottomEdgeResize (CTRL_TYPE_BOTTOM, CTRL_TYPE_LEFT, PointF(0f, SMALL_DELTA))
+ }
+ }
+}
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/windowdecor/FluidResizeTaskPositionerTest.kt b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/windowdecor/FluidResizeTaskPositionerTest.kt
index 3a3e965..7543fed 100644
--- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/windowdecor/FluidResizeTaskPositionerTest.kt
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/windowdecor/FluidResizeTaskPositionerTest.kt
@@ -121,6 +121,7 @@
displayId = DISPLAY_ID
configuration.windowConfiguration.setBounds(STARTING_BOUNDS)
configuration.windowConfiguration.displayRotation = ROTATION_90
+ isResizeable = true
}
`when`(mockWindowDecoration.calculateValidDragArea()).thenReturn(VALID_DRAG_AREA)
mockWindowDecoration.mDisplay = mockDisplay
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/windowdecor/VeiledResizeTaskPositionerTest.kt b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/windowdecor/VeiledResizeTaskPositionerTest.kt
index 6ae16ed..7784af6 100644
--- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/windowdecor/VeiledResizeTaskPositionerTest.kt
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/windowdecor/VeiledResizeTaskPositionerTest.kt
@@ -141,6 +141,7 @@
displayId = DISPLAY_ID
configuration.windowConfiguration.setBounds(STARTING_BOUNDS)
configuration.windowConfiguration.displayRotation = ROTATION_90
+ isResizeable = true
}
`when`(mockDesktopWindowDecoration.calculateValidDragArea()).thenReturn(VALID_DRAG_AREA)
mockDesktopWindowDecoration.mDisplay = mockDisplay
diff --git a/media/TEST_MAPPING b/media/TEST_MAPPING
index 6ac9695..e52e0b1 100644
--- a/media/TEST_MAPPING
+++ b/media/TEST_MAPPING
@@ -30,24 +30,14 @@
"file_patterns": ["(?i)drm|crypto"]
},
{
- "name": "CtsMediaDrmFrameworkTestCases",
- "options" : [
- {
- "include-annotation": "android.platform.test.annotations.Presubmit"
- }
- ],
+ "name": "CtsMediaDrmFrameworkTestCases_Presubmit",
"file_patterns": ["(?i)drm|crypto"]
},
{
"file_patterns": [
"[^/]*(LoudnessCodec)[^/]*\\.java"
],
- "name": "LoudnessCodecApiTest",
- "options": [
- {
- "include-annotation": "android.platform.test.annotations.Presubmit"
- }
- ]
+ "name": "LoudnessCodecApiTest_Presubmit"
}
]
}
diff --git a/media/java/android/media/SoundPool.java b/media/java/android/media/SoundPool.java
index f33a744..7b9ff23 100644
--- a/media/java/android/media/SoundPool.java
+++ b/media/java/android/media/SoundPool.java
@@ -26,6 +26,7 @@
import android.os.Looper;
import android.os.Message;
import android.os.ParcelFileDescriptor;
+import android.os.Trace;
import android.util.AndroidRuntimeException;
import android.util.Log;
@@ -314,8 +315,13 @@
public final int play(int soundID, float leftVolume, float rightVolume,
int priority, int loop, float rate) {
// FIXME: b/174876164 implement device id for soundpool
- baseStart(0);
- return _play(soundID, leftVolume, rightVolume, priority, loop, rate, getPlayerIId());
+ try {
+ Trace.traceBegin(Trace.TRACE_TAG_AUDIO, "SoundPool.play");
+ baseStart(0);
+ return _play(soundID, leftVolume, rightVolume, priority, loop, rate, getPlayerIId());
+ } finally {
+ Trace.traceEnd(Trace.TRACE_TAG_AUDIO);
+ }
}
/**
diff --git a/media/java/android/media/projection/TEST_MAPPING b/media/java/android/media/projection/TEST_MAPPING
index 7aa9118..b33097c 100644
--- a/media/java/android/media/projection/TEST_MAPPING
+++ b/media/java/android/media/projection/TEST_MAPPING
@@ -1,15 +1,7 @@
{
"presubmit": [
{
- "name": "MediaProjectionTests",
- "options": [
- {
- "exclude-annotation": "androidx.test.filters.FlakyTest"
- },
- {
- "exclude-annotation": "org.junit.Ignore"
- }
- ]
+ "name": "MediaProjectionTests"
}
]
}
diff --git a/media/jni/soundpool/SoundPool.cpp b/media/jni/soundpool/SoundPool.cpp
index 9f32a83..4c0b8d0 100644
--- a/media/jni/soundpool/SoundPool.cpp
+++ b/media/jni/soundpool/SoundPool.cpp
@@ -21,6 +21,9 @@
#include <algorithm>
#include <thread>
+#define ATRACE_TAG ATRACE_TAG_AUDIO
+#include <utils/Trace.h>
+
#include "SoundPool.h"
namespace android
@@ -135,8 +138,10 @@
return 0;
}
+ ATRACE_BEGIN("SoundPool::play (native)");
const int32_t streamID = mStreamManager.queueForPlay(
sound, soundID, leftVolume, rightVolume, priority, loop, rate, playerIId);
+ ATRACE_END();
ALOGV("%s returned %d", __func__, streamID);
return streamID;
diff --git a/mime/java-res/android.mime.types b/mime/java-res/android.mime.types
index 5cf807d..17cdee4 100644
--- a/mime/java-res/android.mime.types
+++ b/mime/java-res/android.mime.types
@@ -132,6 +132,7 @@
# Optional additions that should not override any previous mapping.
?application/x-wifi-config ?xml
+?multipart/related mht
# Special cases where Android has a strong opinion about mappings, so we
# define them very last and make them override in both directions (no "?").
diff --git a/native/android/TEST_MAPPING b/native/android/TEST_MAPPING
index 7c71098..be84574 100644
--- a/native/android/TEST_MAPPING
+++ b/native/android/TEST_MAPPING
@@ -14,12 +14,7 @@
"file_patterns": ["permission_manager.cpp"]
},
{
- "name": "CtsOsTestCases",
- "options": [
- {
- "include-filter": "android.os.cts.PerformanceHintManagerTest"
- }
- ],
+ "name": "CtsOsTestCases_cts_performancehintmanagertest",
"file_patterns": ["performance_hint.cpp"]
}
],
diff --git a/native/webview/TEST_MAPPING b/native/webview/TEST_MAPPING
index 07f4383..3858059 100644
--- a/native/webview/TEST_MAPPING
+++ b/native/webview/TEST_MAPPING
@@ -1,28 +1,13 @@
{
"presubmit": [
{
- "name": "CtsWebkitTestCases",
- "options": [
- {
- "exclude-annotation": "androidx.test.filters.FlakyTest"
- }
- ]
+ "name": "CtsWebkitTestCases"
},
{
- "name": "CtsSdkSandboxWebkitTestCases",
- "options": [
- {
- "exclude-annotation": "androidx.test.filters.FlakyTest"
- }
- ]
+ "name": "CtsSdkSandboxWebkitTestCases"
},
{
- "name": "CtsHostsideWebViewTests",
- "options": [
- {
- "exclude-annotation": "androidx.test.filters.FlakyTest"
- }
- ]
+ "name": "CtsHostsideWebViewTests"
},
{
"name": "GtsWebViewTestCases",
diff --git a/nfc/api/current.txt b/nfc/api/current.txt
index 5b6b6c0..e7cb76c 100644
--- a/nfc/api/current.txt
+++ b/nfc/api/current.txt
@@ -205,6 +205,7 @@
method public int getSelectionModeForCategory(String);
method public boolean isDefaultServiceForAid(android.content.ComponentName, String);
method public boolean isDefaultServiceForCategory(android.content.ComponentName, String);
+ method @FlaggedApi("android.nfc.enable_card_emulation_euicc") public boolean isEuiccSupported();
method public boolean registerAidsForService(android.content.ComponentName, String, java.util.List<java.lang.String>);
method @FlaggedApi("android.nfc.nfc_read_polling_loop") public boolean registerPollingLoopFilterForService(@NonNull android.content.ComponentName, @NonNull String, boolean);
method @FlaggedApi("android.nfc.nfc_read_polling_loop") public boolean registerPollingLoopPatternFilterForService(@NonNull android.content.ComponentName, @NonNull String, boolean);
diff --git a/nfc/api/system-current.txt b/nfc/api/system-current.txt
index cc5ff81..bc8a7af 100644
--- a/nfc/api/system-current.txt
+++ b/nfc/api/system-current.txt
@@ -98,7 +98,6 @@
public final class CardEmulation {
method @FlaggedApi("android.permission.flags.wallet_role_enabled") @Nullable @RequiresPermission(android.Manifest.permission.NFC_PREFERRED_PAYMENT_INFO) public static android.content.ComponentName getPreferredPaymentService(@NonNull android.content.Context);
method @FlaggedApi("android.nfc.enable_nfc_mainline") @NonNull public java.util.List<android.nfc.cardemulation.ApduServiceInfo> getServices(@NonNull String, int);
- method @FlaggedApi("android.nfc.enable_card_emulation_euicc") public boolean isEuiccSupported();
method @FlaggedApi("android.nfc.nfc_override_recover_routing_table") public void overrideRoutingTable(@NonNull android.app.Activity, int, int);
method @FlaggedApi("android.nfc.nfc_override_recover_routing_table") public void recoverRoutingTable(@NonNull android.app.Activity);
}
diff --git a/nfc/java/android/nfc/cardemulation/CardEmulation.java b/nfc/java/android/nfc/cardemulation/CardEmulation.java
index a72a896..83ad32c 100644
--- a/nfc/java/android/nfc/cardemulation/CardEmulation.java
+++ b/nfc/java/android/nfc/cardemulation/CardEmulation.java
@@ -992,9 +992,7 @@
* Is EUICC supported as a Secure Element EE which supports off host card emulation.
*
* @return true if the device supports EUICC for off host card emulation, false otherwise.
- * @hide
*/
- @SystemApi
@FlaggedApi(android.nfc.Flags.FLAG_ENABLE_CARD_EMULATION_EUICC)
public boolean isEuiccSupported() {
return callServiceReturn(() -> sService.isEuiccSupported(), false);
diff --git a/packages/PrintSpooler/TEST_MAPPING b/packages/PrintSpooler/TEST_MAPPING
index ad3b44f..f8bf8a0 100644
--- a/packages/PrintSpooler/TEST_MAPPING
+++ b/packages/PrintSpooler/TEST_MAPPING
@@ -1,12 +1,7 @@
{
"presubmit": [
{
- "name": "CtsPrintTestCases",
- "options": [
- {
- "include-annotation": "android.platform.test.annotations.Presubmit"
- }
- ]
+ "name": "CtsPrintTestCases_Presubmit"
}
],
"postsubmit": [
diff --git a/packages/SettingsLib/Preference/src/com/android/settingslib/preference/PreferenceBinding.kt b/packages/SettingsLib/Preference/src/com/android/settingslib/preference/PreferenceBinding.kt
index 9be0e71..5fcf478 100644
--- a/packages/SettingsLib/Preference/src/com/android/settingslib/preference/PreferenceBinding.kt
+++ b/packages/SettingsLib/Preference/src/com/android/settingslib/preference/PreferenceBinding.kt
@@ -108,6 +108,9 @@
/** Abstract preference screen to provide preference hierarchy and binding factory. */
interface PreferenceScreenCreator : PreferenceScreenMetadata, PreferenceScreenProvider {
+ /** Returns if the flag (e.g. for rollout) is enabled on current screen. */
+ fun isFlagEnabled(context: Context): Boolean = true
+
val preferenceBindingFactory: PreferenceBindingFactory
get() = DefaultPreferenceBindingFactory
diff --git a/packages/SettingsLib/Preference/src/com/android/settingslib/preference/PreferenceFragment.kt b/packages/SettingsLib/Preference/src/com/android/settingslib/preference/PreferenceFragment.kt
index 68f640b..a270681 100644
--- a/packages/SettingsLib/Preference/src/com/android/settingslib/preference/PreferenceFragment.kt
+++ b/packages/SettingsLib/Preference/src/com/android/settingslib/preference/PreferenceFragment.kt
@@ -44,13 +44,8 @@
fun createPreferenceScreenFromResource() =
factory.inflate(getPreferenceScreenResId(context))
- if (!usePreferenceScreenMetadata()) return createPreferenceScreenFromResource()
-
- val screenKey = getPreferenceScreenBindingKey(context)
val screenCreator =
- (PreferenceScreenRegistry[screenKey] as? PreferenceScreenCreator)
- ?: return createPreferenceScreenFromResource()
-
+ getPreferenceScreenCreator(context) ?: return createPreferenceScreenFromResource()
val preferenceBindingFactory = screenCreator.preferenceBindingFactory
val preferenceHierarchy = screenCreator.getPreferenceHierarchy(context)
val preferenceScreen =
@@ -73,17 +68,14 @@
return preferenceScreen
}
- /**
- * Returns if preference screen metadata can be used to set up preference screen.
- *
- * This is for flagging purpose. If false (e.g. flag is disabled), xml resource is used to build
- * preference screen.
- */
- protected open fun usePreferenceScreenMetadata(): Boolean = false
-
/** Returns the xml resource to create preference screen. */
@XmlRes protected open fun getPreferenceScreenResId(context: Context): Int = 0
+ protected fun getPreferenceScreenCreator(context: Context): PreferenceScreenCreator? =
+ (PreferenceScreenRegistry[getPreferenceScreenBindingKey(context)]
+ as? PreferenceScreenCreator)
+ ?.run { if (isFlagEnabled(context)) this else null }
+
override fun getPreferenceScreenBindingKey(context: Context): String? =
arguments?.getString(EXTRA_BINDING_SCREEN_KEY)
@@ -91,19 +83,4 @@
preferenceScreenBindingHelper?.close()
super.onDestroy()
}
-
- companion object {
- /** Returns [PreferenceFragment] instance to display the preference screen of given key. */
- fun of(screenKey: String): PreferenceFragment? {
- val screenMetadata = PreferenceScreenRegistry[screenKey] ?: return null
- if (
- screenMetadata is PreferenceScreenCreator && screenMetadata.hasCompleteHierarchy()
- ) {
- return PreferenceFragment().apply {
- arguments = Bundle().apply { putString(EXTRA_BINDING_SCREEN_KEY, screenKey) }
- }
- }
- return null
- }
- }
}
diff --git a/packages/SettingsLib/src/com/android/settingslib/users/TEST_MAPPING b/packages/SettingsLib/src/com/android/settingslib/users/TEST_MAPPING
index 71cbcb5..1346ee5 100644
--- a/packages/SettingsLib/src/com/android/settingslib/users/TEST_MAPPING
+++ b/packages/SettingsLib/src/com/android/settingslib/users/TEST_MAPPING
@@ -1,12 +1,7 @@
{
"presubmit": [
{
- "name": "SettingsLibTests",
- "options": [
- {
- "include-filter": "com.android.settingslib.users."
- }
- ]
+ "name": "SettingsLibTests_settingslib_users"
}
]
}
\ No newline at end of file
diff --git a/packages/SettingsProvider/TEST_MAPPING b/packages/SettingsProvider/TEST_MAPPING
index 0eed2b7..cf9ed2e 100644
--- a/packages/SettingsProvider/TEST_MAPPING
+++ b/packages/SettingsProvider/TEST_MAPPING
@@ -4,12 +4,7 @@
"name": "SettingsProviderTest"
},
{
- "name": "CtsProviderTestCases",
- "options": [
- {
- "include-filter": "android.provider.cts.settings."
- }
- ]
+ "name": "CtsProviderTestCases_cts_settings"
}
],
"postsubmit": [
diff --git a/packages/Shell/TEST_MAPPING b/packages/Shell/TEST_MAPPING
index 9bb1b4b..6b9f1eb 100644
--- a/packages/Shell/TEST_MAPPING
+++ b/packages/Shell/TEST_MAPPING
@@ -1,23 +1,10 @@
{
"presubmit": [
{
- "name": "CtsBugreportTestCases",
- "options": [
- {
- "exclude-annotation": "androidx.test.filters.LargeTest"
- }
- ]
+ "name": "CtsBugreportTestCases_android_server_os"
},
{
- "name": "ShellTests",
- "options": [
- {
- "exclude-annotation": "androidx.test.filters.LargeTest"
- },
- {
- "exclude-annotation": "androidx.test.filters.FlakyTest"
- }
- ]
+ "name": "ShellTests_android_server_os"
},
{
"name": "CtsUiAutomationTestCases",
diff --git a/packages/SystemUI/Android.bp b/packages/SystemUI/Android.bp
index be4e9a1..f59eab0 100644
--- a/packages/SystemUI/Android.bp
+++ b/packages/SystemUI/Android.bp
@@ -934,9 +934,9 @@
"androidx.compose.runtime_runtime",
],
libs: [
- "android.test.runner",
- "android.test.base",
- "android.test.mock",
+ "android.test.runner.stubs.system",
+ "android.test.base.stubs.system",
+ "android.test.mock.stubs.system",
"truth",
],
diff --git a/packages/SystemUI/TEST_MAPPING b/packages/SystemUI/TEST_MAPPING
index 16dd4e5..07a1e63 100644
--- a/packages/SystemUI/TEST_MAPPING
+++ b/packages/SystemUI/TEST_MAPPING
@@ -21,15 +21,7 @@
// v2/android-virtual-infra/test_mapping/presubmit-avd
"presubmit": [
{
- "name": "SystemUIGoogleTests",
- "options": [
- {
- "exclude-annotation": "org.junit.Ignore"
- },
- {
- "exclude-annotation": "androidx.test.filters.FlakyTest"
- }
- ]
+ "name": "SystemUIGoogleTests"
},
{
// Permission indicators
@@ -48,15 +40,7 @@
},
{
// Permission indicators
- "name": "CtsVoiceRecognitionTestCases",
- "options": [
- {
- "exclude-annotation": "org.junit.Ignore"
- },
- {
- "exclude-annotation": "androidx.test.filters.FlakyTest"
- }
- ]
+ "name": "CtsVoiceRecognitionTestCases"
}
],
diff --git a/packages/SystemUI/accessibility/accessibilitymenu/TEST_MAPPING b/packages/SystemUI/accessibility/accessibilitymenu/TEST_MAPPING
index 4a10108..1820f39 100644
--- a/packages/SystemUI/accessibility/accessibilitymenu/TEST_MAPPING
+++ b/packages/SystemUI/accessibility/accessibilitymenu/TEST_MAPPING
@@ -2,12 +2,7 @@
// TODO: b/324945360 - Re-enable on presubmit after fixing failures
"postsubmit": [
{
- "name": "AccessibilityMenuServiceTests",
- "options": [
- {
- "exclude-annotation": "android.support.test.filters.FlakyTest"
- }
- ]
+ "name": "AccessibilityMenuServiceTests"
}
]
}
\ No newline at end of file
diff --git a/packages/SystemUI/aconfig/systemui.aconfig b/packages/SystemUI/aconfig/systemui.aconfig
index 02e8cd6..7974f92 100644
--- a/packages/SystemUI/aconfig/systemui.aconfig
+++ b/packages/SystemUI/aconfig/systemui.aconfig
@@ -1313,6 +1313,16 @@
}
flag {
+ name: "sim_pin_bouncer_reset"
+ namespace: "systemui"
+ description: "The SIM PIN bouncer does not close after unlocking"
+ bug: "297461589"
+ metadata {
+ purpose: PURPOSE_BUGFIX
+ }
+}
+
+flag {
name: "use_transitions_for_keyguard_occluded"
namespace: "systemui"
description: "Use Keyguard Transitions to set Notification Shade occlusion state"
diff --git a/packages/SystemUI/compose/core/TEST_MAPPING b/packages/SystemUI/compose/core/TEST_MAPPING
index b71c5fb..56e531d 100644
--- a/packages/SystemUI/compose/core/TEST_MAPPING
+++ b/packages/SystemUI/compose/core/TEST_MAPPING
@@ -1,26 +1,10 @@
{
"presubmit": [
{
- "name": "PlatformComposeCoreTests",
- "options": [
- {
- "exclude-annotation": "org.junit.Ignore"
- },
- {
- "exclude-annotation": "androidx.test.filters.FlakyTest"
- }
- ]
+ "name": "PlatformComposeCoreTests"
},
{
- "name": "SystemUIComposeGalleryTests",
- "options": [
- {
- "exclude-annotation": "org.junit.Ignore"
- },
- {
- "exclude-annotation": "androidx.test.filters.FlakyTest"
- }
- ]
+ "name": "SystemUIComposeGalleryTests"
}
]
}
\ No newline at end of file
diff --git a/packages/SystemUI/compose/core/src/com/android/compose/windowsizeclass/WindowSizeClass.kt b/packages/SystemUI/compose/core/src/com/android/compose/windowsizeclass/WindowSizeClass.kt
index 4674d6e..c01396a 100644
--- a/packages/SystemUI/compose/core/src/com/android/compose/windowsizeclass/WindowSizeClass.kt
+++ b/packages/SystemUI/compose/core/src/com/android/compose/windowsizeclass/WindowSizeClass.kt
@@ -16,15 +16,16 @@
package com.android.compose.windowsizeclass
+import android.view.WindowManager
import androidx.compose.material3.windowsizeclass.ExperimentalMaterial3WindowSizeClassApi
import androidx.compose.material3.windowsizeclass.WindowSizeClass
import androidx.compose.runtime.Composable
+import androidx.compose.runtime.remember
import androidx.compose.runtime.staticCompositionLocalOf
import androidx.compose.ui.graphics.toComposeRect
import androidx.compose.ui.platform.LocalConfiguration
import androidx.compose.ui.platform.LocalContext
import androidx.compose.ui.platform.LocalDensity
-import androidx.window.layout.WindowMetricsCalculator
val LocalWindowSizeClass =
staticCompositionLocalOf<WindowSizeClass> {
@@ -41,7 +42,10 @@
LocalConfiguration.current
val density = LocalDensity.current
val context = LocalContext.current
- val metrics = WindowMetricsCalculator.getOrCreate().computeCurrentWindowMetrics(context)
+ val metrics =
+ remember(context) {
+ context.getSystemService(WindowManager::class.java)!!.currentWindowMetrics
+ }
val size = with(density) { metrics.bounds.toComposeRect().size.toDpSize() }
return WindowSizeClass.calculateFromSize(size)
}
diff --git a/packages/SystemUI/compose/facade/enabled/src/com/android/systemui/scene/NotificationsShadeSceneModule.kt b/packages/SystemUI/compose/facade/enabled/src/com/android/systemui/scene/NotificationsShadeSceneModule.kt
deleted file mode 100644
index c58df35..0000000
--- a/packages/SystemUI/compose/facade/enabled/src/com/android/systemui/scene/NotificationsShadeSceneModule.kt
+++ /dev/null
@@ -1,29 +0,0 @@
-/*
- * 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 com.android.systemui.scene
-
-import com.android.systemui.notifications.ui.composable.NotificationsShadeScene
-import com.android.systemui.scene.ui.composable.Scene
-import dagger.Binds
-import dagger.Module
-import dagger.multibindings.IntoSet
-
-@Module
-interface NotificationsShadeSceneModule {
-
- @Binds @IntoSet fun notificationsShade(scene: NotificationsShadeScene): Scene
-}
diff --git a/packages/SystemUI/compose/features/src/com/android/systemui/notifications/ui/composable/NotificationsShadeScene.kt b/packages/SystemUI/compose/features/src/com/android/systemui/notifications/ui/composable/NotificationsShadeScene.kt
deleted file mode 100644
index 1f4cd04..0000000
--- a/packages/SystemUI/compose/features/src/com/android/systemui/notifications/ui/composable/NotificationsShadeScene.kt
+++ /dev/null
@@ -1,116 +0,0 @@
-/*
- * 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 com.android.systemui.notifications.ui.composable
-
-import androidx.compose.foundation.layout.Column
-import androidx.compose.foundation.layout.fillMaxWidth
-import androidx.compose.foundation.layout.padding
-import androidx.compose.runtime.Composable
-import androidx.compose.ui.Modifier
-import androidx.compose.ui.unit.dp
-import com.android.compose.animation.scene.SceneScope
-import com.android.compose.animation.scene.UserAction
-import com.android.compose.animation.scene.UserActionResult
-import com.android.systemui.battery.BatteryMeterViewController
-import com.android.systemui.dagger.SysUISingleton
-import com.android.systemui.lifecycle.ExclusiveActivatable
-import com.android.systemui.lifecycle.rememberViewModel
-import com.android.systemui.notifications.ui.viewmodel.NotificationsShadeUserActionsViewModel
-import com.android.systemui.scene.session.ui.composable.SaveableSession
-import com.android.systemui.scene.shared.model.Scenes
-import com.android.systemui.scene.ui.composable.Scene
-import com.android.systemui.shade.shared.model.ShadeMode
-import com.android.systemui.shade.ui.composable.ExpandedShadeHeader
-import com.android.systemui.shade.ui.composable.OverlayShade
-import com.android.systemui.shade.ui.viewmodel.ShadeHeaderViewModel
-import com.android.systemui.statusbar.notification.stack.ui.view.NotificationScrollView
-import com.android.systemui.statusbar.notification.stack.ui.viewmodel.NotificationsPlaceholderViewModel
-import com.android.systemui.statusbar.phone.ui.StatusBarIconController
-import com.android.systemui.statusbar.phone.ui.TintedIconManager
-import dagger.Lazy
-import javax.inject.Inject
-import kotlinx.coroutines.flow.Flow
-
-@SysUISingleton
-class NotificationsShadeScene
-@Inject
-constructor(
- private val actionsViewModelFactory: NotificationsShadeUserActionsViewModel.Factory,
- private val shadeHeaderViewModelFactory: ShadeHeaderViewModel.Factory,
- private val notificationsPlaceholderViewModelFactory: NotificationsPlaceholderViewModel.Factory,
- private val tintedIconManagerFactory: TintedIconManager.Factory,
- private val batteryMeterViewControllerFactory: BatteryMeterViewController.Factory,
- private val statusBarIconController: StatusBarIconController,
- private val shadeSession: SaveableSession,
- private val stackScrollView: Lazy<NotificationScrollView>,
-) : ExclusiveActivatable(), Scene {
-
- override val key = Scenes.NotificationsShade
-
- private val actionsViewModel: NotificationsShadeUserActionsViewModel by lazy {
- actionsViewModelFactory.create()
- }
-
- override val userActions: Flow<Map<UserAction, UserActionResult>> = actionsViewModel.actions
-
- override suspend fun onActivated(): Nothing {
- actionsViewModel.activate()
- }
-
- @Composable
- override fun SceneScope.Content(
- modifier: Modifier,
- ) {
- val notificationsPlaceholderViewModel =
- rememberViewModel("NotificationsShadeScene") {
- notificationsPlaceholderViewModelFactory.create()
- }
-
- OverlayShade(
- modifier = modifier,
- onScrimClicked = {},
- ) {
- Column {
- ExpandedShadeHeader(
- viewModelFactory = shadeHeaderViewModelFactory,
- createTintedIconManager = tintedIconManagerFactory::create,
- createBatteryMeterViewController = batteryMeterViewControllerFactory::create,
- statusBarIconController = statusBarIconController,
- modifier = Modifier.padding(horizontal = 16.dp),
- )
-
- NotificationScrollingStack(
- shadeSession = shadeSession,
- stackScrollView = stackScrollView.get(),
- viewModel = notificationsPlaceholderViewModel,
- maxScrimTop = { 0f },
- shouldPunchHoleBehindScrim = false,
- shouldFillMaxSize = false,
- shouldReserveSpaceForNavBar = false,
- shadeMode = ShadeMode.Dual,
- modifier = Modifier.fillMaxWidth(),
- )
-
- // Communicates the bottom position of the drawable area within the shade to NSSL.
- NotificationStackCutoffGuideline(
- stackScrollView = stackScrollView.get(),
- viewModel = notificationsPlaceholderViewModel,
- )
- }
- }
- }
-}
diff --git a/packages/SystemUI/compose/features/src/com/android/systemui/qs/ui/composable/QuickSettingsShadeScene.kt b/packages/SystemUI/compose/features/src/com/android/systemui/qs/ui/composable/QuickSettingsShadeScene.kt
deleted file mode 100644
index e27c7e2..0000000
--- a/packages/SystemUI/compose/features/src/com/android/systemui/qs/ui/composable/QuickSettingsShadeScene.kt
+++ /dev/null
@@ -1,92 +0,0 @@
-/*
- * 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 com.android.systemui.qs.ui.composable
-
-import androidx.compose.foundation.layout.Column
-import androidx.compose.foundation.layout.padding
-import androidx.compose.runtime.Composable
-import androidx.compose.ui.Modifier
-import com.android.compose.animation.scene.SceneScope
-import com.android.compose.animation.scene.UserAction
-import com.android.compose.animation.scene.UserActionResult
-import com.android.systemui.battery.BatteryMeterViewController
-import com.android.systemui.dagger.SysUISingleton
-import com.android.systemui.lifecycle.ExclusiveActivatable
-import com.android.systemui.lifecycle.rememberViewModel
-import com.android.systemui.qs.ui.viewmodel.QuickSettingsShadeSceneContentViewModel
-import com.android.systemui.qs.ui.viewmodel.QuickSettingsShadeUserActionsViewModel
-import com.android.systemui.scene.shared.model.Scenes
-import com.android.systemui.scene.ui.composable.Scene
-import com.android.systemui.shade.ui.composable.ExpandedShadeHeader
-import com.android.systemui.shade.ui.composable.OverlayShade
-import com.android.systemui.shade.ui.viewmodel.ShadeHeaderViewModel
-import com.android.systemui.statusbar.phone.ui.StatusBarIconController
-import com.android.systemui.statusbar.phone.ui.TintedIconManager
-import javax.inject.Inject
-import kotlinx.coroutines.flow.Flow
-
-@SysUISingleton
-class QuickSettingsShadeScene
-@Inject
-constructor(
- private val actionsViewModelFactory: QuickSettingsShadeUserActionsViewModel.Factory,
- private val contentViewModelFactory: QuickSettingsShadeSceneContentViewModel.Factory,
- private val shadeHeaderViewModelFactory: ShadeHeaderViewModel.Factory,
- private val tintedIconManagerFactory: TintedIconManager.Factory,
- private val batteryMeterViewControllerFactory: BatteryMeterViewController.Factory,
- private val statusBarIconController: StatusBarIconController,
-) : ExclusiveActivatable(), Scene {
-
- override val key = Scenes.QuickSettingsShade
-
- private val actionsViewModel: QuickSettingsShadeUserActionsViewModel by lazy {
- actionsViewModelFactory.create()
- }
-
- override val userActions: Flow<Map<UserAction, UserActionResult>> = actionsViewModel.actions
-
- override suspend fun onActivated(): Nothing {
- actionsViewModel.activate()
- }
-
- @Composable
- override fun SceneScope.Content(
- modifier: Modifier,
- ) {
- val viewModel =
- rememberViewModel("QuickSettingsShadeScene") { contentViewModelFactory.create() }
-
- OverlayShade(
- modifier = modifier,
- onScrimClicked = {},
- ) {
- Column {
- ExpandedShadeHeader(
- viewModelFactory = shadeHeaderViewModelFactory,
- createTintedIconManager = tintedIconManagerFactory::create,
- createBatteryMeterViewController = batteryMeterViewControllerFactory::create,
- statusBarIconController = statusBarIconController,
- modifier = Modifier.padding(QuickSettingsShade.Dimensions.Padding),
- )
-
- ShadeBody(
- viewModel = viewModel.quickSettingsContainerViewModel,
- )
- }
- }
- }
-}
diff --git a/packages/SystemUI/compose/features/src/com/android/systemui/shade/ui/composable/ShadeScene.kt b/packages/SystemUI/compose/features/src/com/android/systemui/shade/ui/composable/ShadeScene.kt
index df22264..8a59e20 100644
--- a/packages/SystemUI/compose/features/src/com/android/systemui/shade/ui/composable/ShadeScene.kt
+++ b/packages/SystemUI/compose/features/src/com/android/systemui/shade/ui/composable/ShadeScene.kt
@@ -16,6 +16,7 @@
package com.android.systemui.shade.ui.composable
+import android.view.HapticFeedbackConstants
import android.view.ViewGroup
import androidx.compose.animation.core.animateDpAsState
import androidx.compose.animation.core.animateFloatAsState
@@ -60,6 +61,7 @@
import androidx.compose.ui.platform.LocalContext
import androidx.compose.ui.platform.LocalDensity
import androidx.compose.ui.platform.LocalLifecycleOwner
+import androidx.compose.ui.platform.LocalView
import androidx.compose.ui.res.colorResource
import androidx.compose.ui.res.dimensionResource
import androidx.compose.ui.unit.dp
@@ -178,9 +180,7 @@
override val userActions: Flow<Map<UserAction, UserActionResult>> = actionsViewModel.actions
@Composable
- override fun SceneScope.Content(
- modifier: Modifier,
- ) =
+ override fun SceneScope.Content(modifier: Modifier) =
ShadeScene(
notificationStackScrollView.get(),
viewModel =
@@ -224,6 +224,13 @@
modifier: Modifier = Modifier,
shadeSession: SaveableSession,
) {
+ val view = LocalView.current
+ LaunchedEffect(Unit) {
+ if (layoutState.currentTransition?.fromContent == Scenes.Gone) {
+ view.performHapticFeedback(HapticFeedbackConstants.GESTURE_START)
+ }
+ }
+
val shadeMode by viewModel.shadeMode.collectAsStateWithLifecycle()
when (shadeMode) {
is ShadeMode.Single ->
@@ -282,7 +289,7 @@
animateSceneFloatAsState(
value = 1f,
key = QuickSettings.SharedValues.TilesSquishiness,
- canOverflow = false
+ canOverflow = false,
)
val isEmptySpaceClickable by viewModel.isEmptySpaceClickable.collectAsStateWithLifecycle()
val isMediaVisible by viewModel.isMediaVisible.collectAsStateWithLifecycle()
@@ -320,7 +327,7 @@
} else {
cutoutInsets
}
- }
+ },
)
}
@@ -337,7 +344,7 @@
modifier =
Modifier.fillMaxSize()
.element(Shade.Elements.BackgroundScrim)
- .background(colorResource(R.color.shade_scrim_background_dark)),
+ .background(colorResource(R.color.shade_scrim_background_dark))
)
Layout(
modifier =
@@ -398,13 +405,13 @@
.pointerInteropFilter { true }
.verticalNestedScrollToScene(
topBehavior = NestedScrollBehavior.EdgeAlways,
- isExternalOverscrollGesture = { false }
+ isExternalOverscrollGesture = { false },
)
) {
NotificationStackCutoffGuideline(
stackScrollView = notificationStackScrollView,
viewModel = notificationsPlaceholderViewModel,
- modifier = Modifier.align(Alignment.TopCenter)
+ modifier = Modifier.align(Alignment.TopCenter),
)
}
}
@@ -440,24 +447,16 @@
canOverflow = false,
)
val unfoldTranslationXForStartSide by
- viewModel
- .unfoldTranslationX(
- isOnStartSide = true,
- )
- .collectAsStateWithLifecycle(0f)
+ viewModel.unfoldTranslationX(isOnStartSide = true).collectAsStateWithLifecycle(0f)
val unfoldTranslationXForEndSide by
- viewModel
- .unfoldTranslationX(
- isOnStartSide = false,
- )
- .collectAsStateWithLifecycle(0f)
+ viewModel.unfoldTranslationX(isOnStartSide = false).collectAsStateWithLifecycle(0f)
val navBarBottomHeight = WindowInsets.navigationBars.asPaddingValues().calculateBottomPadding()
val bottomPadding by
animateDpAsState(
targetValue = if (isCustomizing) 0.dp else navBarBottomHeight,
animationSpec = tween(customizingAnimationDuration),
- label = "animateQSSceneBottomPaddingAsState"
+ label = "animateQSSceneBottomPaddingAsState",
)
val density = LocalDensity.current
LaunchedEffect(navBarBottomHeight, density) {
@@ -516,9 +515,7 @@
)
)
- Column(
- modifier = Modifier.fillMaxSize(),
- ) {
+ Column(modifier = Modifier.fillMaxSize()) {
CollapsedShadeHeader(
viewModelFactory = viewModel.shadeHeaderViewModelFactory,
createTintedIconManager = createTintedIconManager,
@@ -526,9 +523,7 @@
statusBarIconController = statusBarIconController,
modifier =
Modifier.then(brightnessMirrorShowingModifier)
- .padding(
- horizontal = { unfoldTranslationXForStartSide.roundToInt() },
- )
+ .padding(horizontal = { unfoldTranslationXForStartSide.roundToInt() }),
)
Row(modifier = Modifier.fillMaxWidth().weight(1f)) {
@@ -536,14 +531,14 @@
modifier =
Modifier.element(Shade.Elements.SplitShadeStartColumn)
.weight(1f)
- .graphicsLayer { translationX = unfoldTranslationXForStartSide },
+ .graphicsLayer { translationX = unfoldTranslationXForStartSide }
) {
BrightnessMirror(
viewModel = brightnessMirrorViewModel,
qsSceneAdapter = viewModel.qsSceneAdapter,
// Need to use the offset measured from the container as the header
// has to be accounted for
- measureFromContainer = true
+ measureFromContainer = true,
)
Column(
verticalArrangement = Arrangement.Top,
@@ -557,7 +552,7 @@
.thenIf(!isCustomizerShowing) {
Modifier.verticalScroll(
quickSettingsScrollState,
- enabled = isScrollable
+ enabled = isScrollable,
)
.clipScrollableContainer(Orientation.Horizontal)
}
@@ -619,16 +614,16 @@
.padding(
end =
dimensionResource(R.dimen.notification_panel_margin_horizontal),
- bottom = navBarBottomHeight
+ bottom = navBarBottomHeight,
)
- .then(brightnessMirrorShowingModifier)
+ .then(brightnessMirrorShowingModifier),
)
}
}
NotificationStackCutoffGuideline(
stackScrollView = notificationStackScrollView,
viewModel = notificationsPlaceholderViewModel,
- modifier = Modifier.align(Alignment.BottomCenter).navigationBarsPadding()
+ modifier = Modifier.align(Alignment.BottomCenter).navigationBarsPadding(),
)
}
}
@@ -652,6 +647,6 @@
null
} else {
{ mediaOffsetProvider.offset }
- }
+ },
)
}
diff --git a/packages/SystemUI/compose/scene/TEST_MAPPING b/packages/SystemUI/compose/scene/TEST_MAPPING
index f9424ed..65ba037 100644
--- a/packages/SystemUI/compose/scene/TEST_MAPPING
+++ b/packages/SystemUI/compose/scene/TEST_MAPPING
@@ -1,37 +1,13 @@
{
"presubmit": [
{
- "name": "PlatformComposeSceneTransitionLayoutTests",
- "options": [
- {
- "exclude-annotation": "org.junit.Ignore"
- },
- {
- "exclude-annotation": "androidx.test.filters.FlakyTest"
- }
- ]
+ "name": "PlatformComposeSceneTransitionLayoutTests"
},
{
- "name": "PlatformComposeCoreTests",
- "options": [
- {
- "exclude-annotation": "org.junit.Ignore"
- },
- {
- "exclude-annotation": "androidx.test.filters.FlakyTest"
- }
- ]
+ "name": "PlatformComposeCoreTests"
},
{
- "name": "SystemUIComposeGalleryTests",
- "options": [
- {
- "exclude-annotation": "org.junit.Ignore"
- },
- {
- "exclude-annotation": "androidx.test.filters.FlakyTest"
- }
- ]
+ "name": "SystemUIComposeGalleryTests"
}
]
}
\ No newline at end of file
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/domain/interactor/KeyguardDismissActionInteractorTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/domain/interactor/KeyguardDismissActionInteractorTest.kt
index 1981a2d..41cc953 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/domain/interactor/KeyguardDismissActionInteractorTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/domain/interactor/KeyguardDismissActionInteractorTest.kt
@@ -25,7 +25,7 @@
import com.android.systemui.bouncer.data.repository.fakeKeyguardBouncerRepository
import com.android.systemui.bouncer.domain.interactor.alternateBouncerInteractor
import com.android.systemui.coroutines.collectLastValue
-import com.android.systemui.deviceentry.domain.interactor.deviceEntryInteractor
+import com.android.systemui.deviceentry.domain.interactor.deviceUnlockedInteractor
import com.android.systemui.flags.EnableSceneContainer
import com.android.systemui.keyguard.data.repository.fakeKeyguardRepository
import com.android.systemui.keyguard.shared.model.DismissAction
@@ -39,8 +39,6 @@
import com.android.systemui.scene.data.repository.Transition
import com.android.systemui.scene.data.repository.setSceneTransition
import com.android.systemui.scene.domain.interactor.sceneInteractor
-import com.android.systemui.scene.domain.resolver.notifShadeSceneFamilyResolver
-import com.android.systemui.scene.domain.resolver.quickSettingsSceneFamilyResolver
import com.android.systemui.scene.shared.model.Scenes
import com.android.systemui.shade.domain.interactor.shadeInteractor
import com.android.systemui.testKosmos
@@ -79,12 +77,9 @@
dismissInteractor = dismissInteractor,
applicationScope = testScope.backgroundScope,
sceneInteractor = { kosmos.sceneInteractor },
- deviceEntryInteractor = { kosmos.deviceEntryInteractor },
- quickSettingsSceneFamilyResolver = { kosmos.quickSettingsSceneFamilyResolver },
- notifShadeSceneFamilyResolver = { kosmos.notifShadeSceneFamilyResolver },
+ deviceUnlockedInteractor = { kosmos.deviceUnlockedInteractor },
powerInteractor = kosmos.powerInteractor,
alternateBouncerInteractor = kosmos.alternateBouncerInteractor,
- keyguardInteractor = { kosmos.keyguardInteractor },
shadeInteractor = { kosmos.shadeInteractor },
)
}
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/panels/ui/viewmodel/TileUiStateTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/panels/ui/viewmodel/TileUiStateTest.kt
new file mode 100644
index 0000000..b144f06
--- /dev/null
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/panels/ui/viewmodel/TileUiStateTest.kt
@@ -0,0 +1,270 @@
+/*
+ * 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 com.android.systemui.qs.panels.ui.viewmodel
+
+import android.content.res.Resources
+import android.content.res.mainResources
+import android.service.quicksettings.Tile
+import android.widget.Button
+import android.widget.Switch
+import androidx.compose.ui.semantics.Role
+import androidx.test.ext.junit.runners.AndroidJUnit4
+import androidx.test.filters.SmallTest
+import com.android.systemui.SysuiTestCase
+import com.android.systemui.plugins.qs.QSTile
+import com.android.systemui.res.R
+import com.android.systemui.testKosmos
+import com.google.common.truth.Truth.assertThat
+import org.junit.Test
+import org.junit.runner.RunWith
+
+@SmallTest
+@RunWith(AndroidJUnit4::class)
+class TileUiStateTest : SysuiTestCase() {
+
+ private val kosmos = testKosmos()
+ private val resources: Resources
+ get() = kosmos.mainResources
+
+ @Test
+ fun stateUnavailable_secondaryLabelNotmodified() {
+ val testString = "TEST STRING"
+ val state =
+ QSTile.State().apply {
+ state = Tile.STATE_UNAVAILABLE
+ secondaryLabel = testString
+ }
+
+ val uiState = state.toUiState()
+
+ assertThat(uiState.state).isEqualTo(Tile.STATE_UNAVAILABLE)
+ }
+
+ @Test
+ fun accessibilityRole_switch() {
+ val stateSwitch =
+ QSTile.State().apply { expandedAccessibilityClassName = Switch::class.java.name }
+ val uiState = stateSwitch.toUiState()
+ assertThat(uiState.accessibilityRole).isEqualTo(Role.Switch)
+ }
+
+ @Test
+ fun accessibilityRole_button() {
+ val stateButton =
+ QSTile.State().apply { expandedAccessibilityClassName = Button::class.java.name }
+ val uiState = stateButton.toUiState()
+ assertThat(uiState.accessibilityRole).isEqualTo(Role.Button)
+ }
+
+ @Test
+ fun accessibilityRole_switchWithSecondaryClick() {
+ val stateSwitchWithSecondaryClick =
+ QSTile.State().apply {
+ expandedAccessibilityClassName = Switch::class.java.name
+ handlesSecondaryClick = true
+ }
+ val uiState = stateSwitchWithSecondaryClick.toUiState()
+ assertThat(uiState.accessibilityRole).isEqualTo(Role.Button)
+ }
+
+ @Test
+ fun switchInactive_secondaryLabelNotModified() {
+ val testString = "TEST STRING"
+ val state =
+ QSTile.State().apply {
+ expandedAccessibilityClassName = Switch::class.java.name
+ state = Tile.STATE_INACTIVE
+ secondaryLabel = testString
+ }
+
+ val uiState = state.toUiState()
+
+ assertThat(uiState.secondaryLabel).isEqualTo(testString)
+ }
+
+ @Test
+ fun switchActive_secondaryLabelNotModified() {
+ val testString = "TEST STRING"
+ val state =
+ QSTile.State().apply {
+ expandedAccessibilityClassName = Switch::class.java.name
+ state = Tile.STATE_ACTIVE
+ secondaryLabel = testString
+ }
+
+ val uiState = state.toUiState()
+
+ assertThat(uiState.secondaryLabel).isEqualTo(testString)
+ }
+
+ @Test
+ fun buttonInactive_secondaryLabelNotModifiedWhenEmpty() {
+ val state =
+ QSTile.State().apply {
+ expandedAccessibilityClassName = Button::class.java.name
+ state = Tile.STATE_INACTIVE
+ secondaryLabel = ""
+ }
+
+ val uiState = state.toUiState()
+
+ assertThat(uiState.secondaryLabel).isEmpty()
+ }
+
+ @Test
+ fun buttonActive_secondaryLabelNotModifiedWhenEmpty() {
+ val state =
+ QSTile.State().apply {
+ expandedAccessibilityClassName = Button::class.java.name
+ state = Tile.STATE_ACTIVE
+ secondaryLabel = ""
+ }
+
+ val uiState = state.toUiState()
+
+ assertThat(uiState.secondaryLabel).isEmpty()
+ }
+
+ @Test
+ fun buttonUnavailable_emptySecondaryLabel_default() {
+ val state =
+ QSTile.State().apply {
+ expandedAccessibilityClassName = Button::class.java.name
+ state = Tile.STATE_UNAVAILABLE
+ secondaryLabel = ""
+ }
+
+ val uiState = state.toUiState()
+
+ assertThat(uiState.secondaryLabel).isEqualTo(resources.getString(R.string.tile_unavailable))
+ }
+
+ @Test
+ fun switchUnavailable_emptySecondaryLabel_defaultUnavailable() {
+ val state =
+ QSTile.State().apply {
+ expandedAccessibilityClassName = Switch::class.java.name
+ state = Tile.STATE_UNAVAILABLE
+ secondaryLabel = ""
+ }
+
+ val uiState = state.toUiState()
+
+ assertThat(uiState.secondaryLabel).isEqualTo(resources.getString(R.string.tile_unavailable))
+ }
+
+ @Test
+ fun switchInactive_emptySecondaryLabel_defaultOff() {
+ val state =
+ QSTile.State().apply {
+ expandedAccessibilityClassName = Switch::class.java.name
+ state = Tile.STATE_INACTIVE
+ secondaryLabel = ""
+ }
+
+ val uiState = state.toUiState()
+
+ assertThat(uiState.secondaryLabel).isEqualTo(resources.getString(R.string.switch_bar_off))
+ }
+
+ @Test
+ fun switchActive_emptySecondaryLabel_defaultOn() {
+ val state =
+ QSTile.State().apply {
+ expandedAccessibilityClassName = Switch::class.java.name
+ state = Tile.STATE_ACTIVE
+ secondaryLabel = ""
+ }
+
+ val uiState = state.toUiState()
+
+ assertThat(uiState.secondaryLabel).isEqualTo(resources.getString(R.string.switch_bar_on))
+ }
+
+ @Test
+ fun disabledByPolicy_inactive_appearsAsUnavailable() {
+ val stateDisabledByPolicy =
+ QSTile.State().apply {
+ state = Tile.STATE_INACTIVE
+ disabledByPolicy = true
+ }
+
+ val uiState = stateDisabledByPolicy.toUiState()
+
+ assertThat(uiState.state).isEqualTo(Tile.STATE_UNAVAILABLE)
+ }
+
+ @Test
+ fun disabledByPolicy_active_appearsAsUnavailable() {
+ val stateDisabledByPolicy =
+ QSTile.State().apply {
+ state = Tile.STATE_ACTIVE
+ disabledByPolicy = true
+ }
+
+ val uiState = stateDisabledByPolicy.toUiState()
+
+ assertThat(uiState.state).isEqualTo(Tile.STATE_UNAVAILABLE)
+ }
+
+ @Test
+ fun disabledByPolicy_clickLabel() {
+ val stateDisabledByPolicy =
+ QSTile.State().apply {
+ state = Tile.STATE_INACTIVE
+ disabledByPolicy = true
+ }
+
+ val uiState = stateDisabledByPolicy.toUiState()
+ assertThat(uiState.accessibilityUiState.clickLabel)
+ .isEqualTo(
+ resources.getString(
+ R.string.accessibility_tile_disabled_by_policy_action_description
+ )
+ )
+ }
+
+ @Test
+ fun notDisabledByPolicy_clickLabel_null() {
+ val stateDisabledByPolicy =
+ QSTile.State().apply {
+ state = Tile.STATE_INACTIVE
+ disabledByPolicy = false
+ }
+
+ val uiState = stateDisabledByPolicy.toUiState()
+ assertThat(uiState.accessibilityUiState.clickLabel).isNull()
+ }
+
+ @Test
+ fun disabledByPolicy_unavailableInStateDescription() {
+ val state =
+ QSTile.State().apply {
+ disabledByPolicy = true
+ state = Tile.STATE_INACTIVE
+ }
+
+ val uiState = state.toUiState()
+ assertThat(uiState.accessibilityUiState.stateDescription)
+ .contains(resources.getString(R.string.tile_unavailable))
+ }
+
+ private fun QSTile.State.toUiState() = toUiState(resources)
+}
+
+private val TileUiState.accessibilityRole: Role
+ get() = accessibilityUiState.accessibilityRole
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/scene/ui/viewmodel/GoneUserActionsViewModelTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/scene/ui/viewmodel/GoneUserActionsViewModelTest.kt
index e6a24e3..5c47f55 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/scene/ui/viewmodel/GoneUserActionsViewModelTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/scene/ui/viewmodel/GoneUserActionsViewModelTest.kt
@@ -21,13 +21,17 @@
import android.testing.TestableLooper
import androidx.test.ext.junit.runners.AndroidJUnit4
import androidx.test.filters.SmallTest
+import com.android.compose.animation.scene.Edge
import com.android.compose.animation.scene.Swipe
import com.android.compose.animation.scene.SwipeDirection
+import com.android.compose.animation.scene.UserAction
+import com.android.compose.animation.scene.UserActionResult
import com.android.systemui.SysuiTestCase
import com.android.systemui.coroutines.collectLastValue
import com.android.systemui.flags.EnableSceneContainer
import com.android.systemui.kosmos.testScope
import com.android.systemui.lifecycle.activateIn
+import com.android.systemui.scene.shared.model.Scenes
import com.android.systemui.scene.shared.model.TransitionKeys.ToSplitShade
import com.android.systemui.shade.data.repository.shadeRepository
import com.android.systemui.shade.domain.interactor.shadeInteractor
@@ -92,4 +96,42 @@
assertThat(userActions?.get(Swipe(SwipeDirection.Down))?.transitionKey).isNull()
}
+
+ @Test
+ @DisableFlags(DualShade.FLAG_NAME)
+ fun swipeDownWithTwoFingers_singleShade_goesToQuickSettings() =
+ testScope.runTest {
+ val userActions by collectLastValue(underTest.actions)
+ shadeRepository.setShadeLayoutWide(false)
+ runCurrent()
+
+ assertThat(userActions?.get(swipeDownFromTopWithTwoFingers()))
+ .isEqualTo(UserActionResult(Scenes.QuickSettings))
+ }
+
+ @Test
+ @DisableFlags(DualShade.FLAG_NAME)
+ fun swipeDownWithTwoFingers_splitShade_goesToShade() =
+ testScope.runTest {
+ val userActions by collectLastValue(underTest.actions)
+ shadeRepository.setShadeLayoutWide(true)
+ runCurrent()
+
+ assertThat(userActions?.get(swipeDownFromTopWithTwoFingers()))
+ .isEqualTo(UserActionResult(Scenes.Shade, ToSplitShade))
+ }
+
+ @Test
+ @EnableFlags(DualShade.FLAG_NAME)
+ fun swipeDownWithTwoFingers_dualShadeEnabled_isNull() =
+ testScope.runTest {
+ val userActions by collectLastValue(underTest.actions)
+ runCurrent()
+
+ assertThat(userActions?.get(swipeDownFromTopWithTwoFingers())).isNull()
+ }
+
+ private fun swipeDownFromTopWithTwoFingers(): UserAction {
+ return Swipe(direction = SwipeDirection.Down, pointerCount = 2, fromSource = Edge.Top)
+ }
}
diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardConstants.java b/packages/SystemUI/src/com/android/keyguard/KeyguardConstants.java
index a5b62b6..b16c683 100644
--- a/packages/SystemUI/src/com/android/keyguard/KeyguardConstants.java
+++ b/packages/SystemUI/src/com/android/keyguard/KeyguardConstants.java
@@ -28,5 +28,4 @@
* be used temporarily for debugging.
*/
public static final boolean DEBUG = Log.isLoggable("Keyguard", Log.DEBUG);
- public static final boolean DEBUG_SIM_STATES = true;
}
diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardSimPinViewController.java b/packages/SystemUI/src/com/android/keyguard/KeyguardSimPinViewController.java
index 1c1acf8..52c93f7 100644
--- a/packages/SystemUI/src/com/android/keyguard/KeyguardSimPinViewController.java
+++ b/packages/SystemUI/src/com/android/keyguard/KeyguardSimPinViewController.java
@@ -53,7 +53,6 @@
extends KeyguardPinBasedInputViewController<KeyguardSimPinView> {
public static final String TAG = "KeyguardSimPinView";
private static final String LOG_TAG = "KeyguardSimPinView";
- private static final boolean DEBUG = KeyguardConstants.DEBUG_SIM_STATES;
private final KeyguardUpdateMonitor mKeyguardUpdateMonitor;
private final TelephonyManager mTelephonyManager;
@@ -71,7 +70,7 @@
KeyguardUpdateMonitorCallback mUpdateMonitorCallback = new KeyguardUpdateMonitorCallback() {
@Override
public void onSimStateChanged(int subId, int slotId, int simState) {
- if (DEBUG) Log.v(TAG, "onSimStateChanged(subId=" + subId + ",state=" + simState + ")");
+ Log.v(TAG, "onSimStateChanged(subId=" + subId + ",state=" + simState + ")");
// If subId has gone to PUK required then we need to go to the PUK screen.
if (subId == mSubId && simState == TelephonyManager.SIM_STATE_PUK_REQUIRED) {
getKeyguardSecurityCallback().showCurrentSecurityScreen();
@@ -129,7 +128,7 @@
@Override
void resetState() {
super.resetState();
- if (DEBUG) Log.v(TAG, "Resetting state");
+ Log.v(TAG, "Resetting state");
handleSubInfoChangeIfNeeded();
mMessageAreaController.setMessage("");
if (mShowDefaultMessage) {
@@ -216,11 +215,9 @@
mMessageAreaController.setMessage(mView.getResources().getString(
R.string.kg_password_pin_failed));
}
- if (DEBUG) {
- Log.d(LOG_TAG, "verifyPasswordAndUnlock "
- + " CheckSimPin.onSimCheckResponse: " + result
- + " attemptsRemaining=" + result.getAttemptsRemaining());
- }
+ Log.d(LOG_TAG, "verifyPasswordAndUnlock "
+ + " CheckSimPin.onSimCheckResponse: " + result
+ + " attemptsRemaining=" + result.getAttemptsRemaining());
}
getKeyguardSecurityCallback().userActivity();
mCheckSimPinThread = null;
@@ -280,10 +277,8 @@
displayMessage = mView.getResources()
.getString(R.string.kg_sim_lock_esim_instructions, displayMessage);
}
- if (DEBUG) {
- Log.d(LOG_TAG, "getPinPasswordErrorMessage: attemptsRemaining="
- + attemptsRemaining + " displayMessage=" + displayMessage);
- }
+ Log.d(LOG_TAG, "getPinPasswordErrorMessage: attemptsRemaining="
+ + attemptsRemaining + " displayMessage=" + displayMessage);
return displayMessage;
}
@@ -323,14 +318,10 @@
@Override
public void run() {
- if (DEBUG) {
- Log.v(TAG, "call supplyIccLockPin(subid=" + mSubId + ")");
- }
+ Log.v(TAG, "call supplyIccLockPin(subid=" + mSubId + ")");
TelephonyManager telephonyManager = mTelephonyManager.createForSubscriptionId(mSubId);
final PinResult result = telephonyManager.supplyIccLockPin(mPin);
- if (DEBUG) {
- Log.v(TAG, "supplyIccLockPin returned: " + result.toString());
- }
+ Log.v(TAG, "supplyIccLockPin returned: " + result.toString());
mView.post(() -> onSimCheckResponse(result));
}
}
diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitor.java b/packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitor.java
index f731186..22130f8 100644
--- a/packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitor.java
+++ b/packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitor.java
@@ -43,6 +43,7 @@
import static com.android.internal.widget.LockPatternUtils.StrongAuthTracker.STRONG_AUTH_REQUIRED_AFTER_DPM_LOCK_NOW;
import static com.android.internal.widget.LockPatternUtils.StrongAuthTracker.STRONG_AUTH_REQUIRED_AFTER_LOCKOUT;
import static com.android.internal.widget.LockPatternUtils.StrongAuthTracker.STRONG_AUTH_REQUIRED_AFTER_USER_LOCKDOWN;
+import static com.android.systemui.Flags.simPinBouncerReset;
import static com.android.systemui.statusbar.policy.DevicePostureController.DEVICE_POSTURE_OPENED;
import android.annotation.AnyThread;
@@ -1703,6 +1704,9 @@
intent.getStringExtra(Intent.EXTRA_SIM_STATE),
args.slotId,
args.subId);
+ if (args.slotId == SubscriptionManager.INVALID_SIM_SLOT_INDEX) {
+ return;
+ }
mHandler.obtainMessage(MSG_SIM_STATE_CHANGE, args.subId, args.slotId, args.simState)
.sendToTarget();
} else if (TelephonyManager.ACTION_PHONE_STATE_CHANGED.equals(action)) {
@@ -1940,7 +1944,13 @@
}
int state = TelephonyManager.SIM_STATE_UNKNOWN;
String stateExtra = intent.getStringExtra(Intent.EXTRA_SIM_STATE);
- int slotId = intent.getIntExtra(SubscriptionManager.EXTRA_SLOT_INDEX, 0);
+
+ int defaultSlotId = 0;
+ if (simPinBouncerReset()) {
+ defaultSlotId = SubscriptionManager.INVALID_SIM_SLOT_INDEX;
+ }
+ int slotId = intent.getIntExtra(SubscriptionManager.EXTRA_SLOT_INDEX,
+ defaultSlotId);
int subId = intent.getIntExtra(SubscriptionManager.EXTRA_SUBSCRIPTION_INDEX,
SubscriptionManager.INVALID_SUBSCRIPTION_ID);
if (Intent.SIM_STATE_ABSENT.equals(stateExtra)) {
@@ -2479,6 +2489,12 @@
this::onTransitionStateChanged
);
}
+
+ // start() can be invoked in the middle of user switching, so check for this state and issue
+ // the call manually as that important event was missed.
+ if (mUserTracker.isUserSwitching()) {
+ handleUserSwitching(mUserTracker.getUserId(), () -> {});
+ }
}
@VisibleForTesting
diff --git a/packages/SystemUI/src/com/android/systemui/bouncer/domain/interactor/PrimaryBouncerInteractor.kt b/packages/SystemUI/src/com/android/systemui/bouncer/domain/interactor/PrimaryBouncerInteractor.kt
index c28bce2..6d6cd45 100644
--- a/packages/SystemUI/src/com/android/systemui/bouncer/domain/interactor/PrimaryBouncerInteractor.kt
+++ b/packages/SystemUI/src/com/android/systemui/bouncer/domain/interactor/PrimaryBouncerInteractor.kt
@@ -294,7 +294,9 @@
/** Tell the bouncer that bouncer is requested when device is already authenticated */
fun notifyUserRequestedBouncerWhenAlreadyAuthenticated(userId: Int) {
- applicationScope.launch { repository.setKeyguardAuthenticatedPrimaryAuth(userId) }
+ applicationScope.launch {
+ repository.setUserRequestedBouncerWhenAlreadyAuthenticated(userId)
+ }
}
/** Tell the bouncer that keyguard is authenticated with biometrics. */
diff --git a/packages/SystemUI/src/com/android/systemui/bouncer/ui/viewmodel/BouncerContainerViewModel.kt b/packages/SystemUI/src/com/android/systemui/bouncer/ui/viewmodel/BouncerContainerViewModel.kt
index 73a8810..c60f932 100644
--- a/packages/SystemUI/src/com/android/systemui/bouncer/ui/viewmodel/BouncerContainerViewModel.kt
+++ b/packages/SystemUI/src/com/android/systemui/bouncer/ui/viewmodel/BouncerContainerViewModel.kt
@@ -17,12 +17,14 @@
package com.android.systemui.bouncer.ui.viewmodel
import androidx.compose.runtime.getValue
-import com.android.keyguard.ViewMediatorCallback
import com.android.systemui.authentication.domain.interactor.AuthenticationInteractor
import com.android.systemui.bouncer.domain.interactor.PrimaryBouncerInteractor
+import com.android.systemui.deviceentry.domain.interactor.DeviceUnlockedInteractor
import com.android.systemui.lifecycle.ExclusiveActivatable
import com.android.systemui.lifecycle.Hydrator
import com.android.systemui.user.domain.interactor.SelectedUserInteractor
+import com.android.systemui.util.kotlin.Utils.Companion.sample
+import com.android.systemui.util.kotlin.sample
import dagger.assisted.AssistedFactory
import dagger.assisted.AssistedInject
import kotlinx.coroutines.coroutineScope
@@ -34,7 +36,7 @@
private val legacyInteractor: PrimaryBouncerInteractor,
private val authenticationInteractor: AuthenticationInteractor,
private val selectedUserInteractor: SelectedUserInteractor,
- private val viewMediatorCallback: ViewMediatorCallback?,
+ private val deviceUnlockedInteractor: DeviceUnlockedInteractor,
) : ExclusiveActivatable() {
private val hydrator = Hydrator("BouncerContainerViewModel")
@@ -45,6 +47,18 @@
override suspend fun onActivated(): Nothing {
coroutineScope {
launch {
+ legacyInteractor.isShowing
+ .sample(deviceUnlockedInteractor.deviceUnlockStatus, ::Pair)
+ .collect { (isShowing, unlockStatus) ->
+ if (isShowing && unlockStatus.isUnlocked) {
+ legacyInteractor.notifyUserRequestedBouncerWhenAlreadyAuthenticated(
+ selectedUserInteractor.getSelectedUserId()
+ )
+ }
+ }
+ }
+
+ launch {
authenticationInteractor.onAuthenticationResult.collect { authenticationSucceeded ->
if (authenticationSucceeded) {
legacyInteractor.notifyKeyguardAuthenticatedPrimaryAuth(
diff --git a/packages/SystemUI/src/com/android/systemui/display/ui/viewmodel/ConnectingDisplayViewModel.kt b/packages/SystemUI/src/com/android/systemui/display/ui/viewmodel/ConnectingDisplayViewModel.kt
index 81ea2e7..62720a5 100644
--- a/packages/SystemUI/src/com/android/systemui/display/ui/viewmodel/ConnectingDisplayViewModel.kt
+++ b/packages/SystemUI/src/com/android/systemui/display/ui/viewmodel/ConnectingDisplayViewModel.kt
@@ -79,7 +79,7 @@
.combine(concurrentDisplaysInProgessFlow) { pendingDisplay, concurrentDisplaysInProgress
->
if (pendingDisplay == null) {
- hideDialog()
+ dismissDialog()
} else {
showDialog(pendingDisplay, concurrentDisplaysInProgress)
}
@@ -88,17 +88,17 @@
}
private fun showDialog(pendingDisplay: PendingDisplay, concurrentDisplaysInProgess: Boolean) {
- hideDialog()
+ dismissDialog()
dialog =
bottomSheetFactory
.createDialog(
onStartMirroringClickListener = {
scope.launch(bgDispatcher) { pendingDisplay.enable() }
- hideDialog()
+ dismissDialog()
},
onCancelMirroring = {
scope.launch(bgDispatcher) { pendingDisplay.ignore() }
- hideDialog()
+ dismissDialog()
},
navbarBottomInsetsProvider = { Utils.getNavbarInsets(context).bottom },
showConcurrentDisplayInfo = concurrentDisplaysInProgess
@@ -106,8 +106,8 @@
.apply { show() }
}
- private fun hideDialog() {
- dialog?.hide()
+ private fun dismissDialog() {
+ dialog?.dismiss()
dialog = null
}
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/CustomizationProvider.kt b/packages/SystemUI/src/com/android/systemui/keyguard/CustomizationProvider.kt
index 342325f..6df8355 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/CustomizationProvider.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/CustomizationProvider.kt
@@ -54,29 +54,25 @@
addURI(
Contract.AUTHORITY,
Contract.LockScreenQuickAffordances.qualifiedTablePath(
- Contract.LockScreenQuickAffordances.SlotTable.TABLE_NAME,
+ Contract.LockScreenQuickAffordances.SlotTable.TABLE_NAME
),
MATCH_CODE_ALL_SLOTS,
)
addURI(
Contract.AUTHORITY,
Contract.LockScreenQuickAffordances.qualifiedTablePath(
- Contract.LockScreenQuickAffordances.AffordanceTable.TABLE_NAME,
+ Contract.LockScreenQuickAffordances.AffordanceTable.TABLE_NAME
),
MATCH_CODE_ALL_AFFORDANCES,
)
addURI(
Contract.AUTHORITY,
Contract.LockScreenQuickAffordances.qualifiedTablePath(
- Contract.LockScreenQuickAffordances.SelectionTable.TABLE_NAME,
+ Contract.LockScreenQuickAffordances.SelectionTable.TABLE_NAME
),
MATCH_CODE_ALL_SELECTIONS,
)
- addURI(
- Contract.AUTHORITY,
- Contract.FlagsTable.TABLE_NAME,
- MATCH_CODE_ALL_FLAGS,
- )
+ addURI(Contract.AUTHORITY, Contract.FlagsTable.TABLE_NAME, MATCH_CODE_ALL_FLAGS)
}
override fun onCreate(): Boolean {
@@ -106,15 +102,15 @@
when (uriMatcher.match(uri)) {
MATCH_CODE_ALL_SLOTS ->
Contract.LockScreenQuickAffordances.qualifiedTablePath(
- Contract.LockScreenQuickAffordances.SlotTable.TABLE_NAME,
+ Contract.LockScreenQuickAffordances.SlotTable.TABLE_NAME
)
MATCH_CODE_ALL_AFFORDANCES ->
Contract.LockScreenQuickAffordances.qualifiedTablePath(
- Contract.LockScreenQuickAffordances.AffordanceTable.TABLE_NAME,
+ Contract.LockScreenQuickAffordances.AffordanceTable.TABLE_NAME
)
MATCH_CODE_ALL_SELECTIONS ->
Contract.LockScreenQuickAffordances.qualifiedTablePath(
- Contract.LockScreenQuickAffordances.SelectionTable.TABLE_NAME,
+ Contract.LockScreenQuickAffordances.SelectionTable.TABLE_NAME
)
MATCH_CODE_ALL_FLAGS -> Contract.FlagsTable.TABLE_NAME
else -> null
@@ -128,6 +124,7 @@
}
override fun insert(uri: Uri, values: ContentValues?): Uri? {
+ if (!::mainDispatcher.isInitialized) return null
if (uriMatcher.match(uri) != MATCH_CODE_ALL_SELECTIONS) {
throw UnsupportedOperationException()
}
@@ -142,6 +139,7 @@
selectionArgs: Array<out String>?,
sortOrder: String?,
): Cursor? {
+ if (!::mainDispatcher.isInitialized) return null
return runBlocking("$TAG#query", mainDispatcher) {
when (uriMatcher.match(uri)) {
MATCH_CODE_ALL_AFFORDANCES -> queryAffordances()
@@ -163,11 +161,8 @@
return 0
}
- override fun delete(
- uri: Uri,
- selection: String?,
- selectionArgs: Array<out String>?,
- ): Int {
+ override fun delete(uri: Uri, selection: String?, selectionArgs: Array<out String>?): Int {
+ if (!::mainDispatcher.isInitialized) return 0
if (uriMatcher.match(uri) != MATCH_CODE_ALL_SELECTIONS) {
throw UnsupportedOperationException()
}
@@ -232,11 +227,7 @@
throw IllegalArgumentException("Cannot insert selection, affordance ID was empty!")
}
- val success =
- interactor.select(
- slotId = slotId,
- affordanceId = affordanceId,
- )
+ val success = interactor.select(slotId = slotId, affordanceId = affordanceId)
return if (success) {
Log.d(TAG, "Successfully selected $affordanceId for slot $slotId")
@@ -318,22 +309,14 @@
)
.apply {
interactor.getSlotPickerRepresentations().forEach { representation ->
- addRow(
- arrayOf(
- representation.id,
- representation.maxSelectedAffordances,
- )
- )
+ addRow(arrayOf(representation.id, representation.maxSelectedAffordances))
}
}
}
private suspend fun queryFlags(): Cursor {
return MatrixCursor(
- arrayOf(
- Contract.FlagsTable.Columns.NAME,
- Contract.FlagsTable.Columns.VALUE,
- )
+ arrayOf(Contract.FlagsTable.Columns.NAME, Contract.FlagsTable.Columns.VALUE)
)
.apply {
interactor.getPickerFlags().forEach { flag ->
@@ -351,10 +334,7 @@
}
}
- private suspend fun deleteSelection(
- uri: Uri,
- selectionArgs: Array<out String>?,
- ): Int {
+ private suspend fun deleteSelection(uri: Uri, selectionArgs: Array<out String>?): Int {
if (selectionArgs == null) {
throw IllegalArgumentException(
"Cannot delete selection, selection arguments not included!"
@@ -372,11 +352,7 @@
)
}
- val deleted =
- interactor.unselect(
- slotId = slotId,
- affordanceId = affordanceId,
- )
+ val deleted = interactor.unselect(slotId = slotId, affordanceId = affordanceId)
return if (deleted) {
Log.d(TAG, "Successfully unselected $affordanceId for slot $slotId")
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java b/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java
index 3b1569d..1a0525d 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java
@@ -42,6 +42,7 @@
import static com.android.systemui.DejankUtils.whitelistIpcs;
import static com.android.systemui.Flags.notifyPowerManagerUserActivityBackground;
import static com.android.systemui.Flags.relockWithPowerButtonImmediately;
+import static com.android.systemui.Flags.simPinBouncerReset;
import static com.android.systemui.Flags.translucentOccludingActivityFix;
import static com.android.systemui.keyguard.ui.viewmodel.LockscreenToDreamingTransitionViewModel.DREAMING_ANIMATION_DURATION_MS;
@@ -238,7 +239,6 @@
private static final long KEYGUARD_DONE_PENDING_TIMEOUT_MS = 3000;
private static final boolean DEBUG = KeyguardConstants.DEBUG;
- private static final boolean DEBUG_SIM_STATES = KeyguardConstants.DEBUG_SIM_STATES;
private final static String TAG = "KeyguardViewMediator";
@@ -649,11 +649,8 @@
@Override
public void onSimStateChanged(int subId, int slotId, int simState) {
-
- if (DEBUG_SIM_STATES) {
- Log.d(TAG, "onSimStateChanged(subId=" + subId + ", slotId=" + slotId
- + ",state=" + simState + ")");
- }
+ Log.d(TAG, "onSimStateChanged(subId=" + subId + ", slotId=" + slotId
+ + ",state=" + TelephonyManager.simStateToString(simState) + ")");
int size = mKeyguardStateCallbacks.size();
boolean simPinSecure = mUpdateMonitor.isSimPinSecure();
@@ -686,7 +683,7 @@
synchronized (KeyguardViewMediator.this) {
if (shouldWaitForProvisioning()) {
if (!mShowing) {
- if (DEBUG_SIM_STATES) Log.d(TAG, "ICC_ABSENT isn't showing,"
+ Log.d(TAG, "ICC_ABSENT isn't showing,"
+ " we need to show the keyguard since the "
+ "device isn't provisioned yet.");
doKeyguardLocked(null);
@@ -698,11 +695,21 @@
// MVNO SIMs can become transiently NOT_READY when switching networks,
// so we should only lock when they are ABSENT.
if (lastSimStateWasLocked) {
- if (DEBUG_SIM_STATES) Log.d(TAG, "SIM moved to ABSENT when the "
+ Log.d(TAG, "SIM moved to ABSENT when the "
+ "previous state was locked. Reset the state.");
resetStateLocked();
}
mSimWasLocked.append(slotId, false);
+ } else if (simState == TelephonyManager.SIM_STATE_NOT_READY) {
+ if (simPinBouncerReset()) {
+ // Support eSIM disablement, and do not clear `mSimWasLocked`.
+ // NOT_READY could just be a temporary state
+ if (lastSimStateWasLocked) {
+ Log.d(TAG, "SIM moved to NOT_READY when the "
+ + "previous state was locked. Reset the state.");
+ resetStateLocked();
+ }
+ }
}
}
break;
@@ -712,7 +719,7 @@
mSimWasLocked.append(slotId, true);
mPendingPinLock = true;
if (!mShowing) {
- if (DEBUG_SIM_STATES) Log.d(TAG,
+ Log.d(TAG,
"INTENT_VALUE_ICC_LOCKED and keygaurd isn't "
+ "showing; need to show keyguard so user can enter sim pin");
doKeyguardLocked(null);
@@ -724,11 +731,11 @@
case TelephonyManager.SIM_STATE_PERM_DISABLED:
synchronized (KeyguardViewMediator.this) {
if (!mShowing) {
- if (DEBUG_SIM_STATES) Log.d(TAG, "PERM_DISABLED and "
+ Log.d(TAG, "PERM_DISABLED and "
+ "keygaurd isn't showing.");
doKeyguardLocked(null);
} else {
- if (DEBUG_SIM_STATES) Log.d(TAG, "PERM_DISABLED, resetStateLocked to"
+ Log.d(TAG, "PERM_DISABLED, resetStateLocked to"
+ "show permanently disabled message in lockscreen.");
resetStateLocked();
}
@@ -736,9 +743,9 @@
break;
case TelephonyManager.SIM_STATE_READY:
synchronized (KeyguardViewMediator.this) {
- if (DEBUG_SIM_STATES) Log.d(TAG, "READY, reset state? " + mShowing);
+ Log.d(TAG, "READY, reset state? " + mShowing);
if (mShowing && mSimWasLocked.get(slotId, false)) {
- if (DEBUG_SIM_STATES) Log.d(TAG, "SIM moved to READY when the "
+ Log.d(TAG, "SIM moved to READY when the "
+ "previously was locked. Reset the state.");
mSimWasLocked.append(slotId, false);
resetStateLocked();
@@ -746,7 +753,7 @@
}
break;
default:
- if (DEBUG_SIM_STATES) Log.v(TAG, "Unspecific state: " + simState);
+ Log.v(TAG, "Unspecific state: " + simState);
break;
}
}
@@ -1682,6 +1689,12 @@
});
mJavaAdapter.alwaysCollectFlow(communalViewModel.getTransitionFromOccludedEnded(),
getFinishedCallbackConsumer());
+
+ // System ready can be invoked in the middle of user switching, so check for this state
+ // and issue the call manually as that important event was missed.
+ if (mUserTracker.isUserSwitching()) {
+ mUpdateCallback.onUserSwitching(mUserTracker.getUserId());
+ }
}
// Most services aren't available until the system reaches the ready state, so we
// send it here when the device first boots.
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/KeyguardDismissActionInteractor.kt b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/KeyguardDismissActionInteractor.kt
index 8495778..eb9b07a 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/KeyguardDismissActionInteractor.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/KeyguardDismissActionInteractor.kt
@@ -21,7 +21,7 @@
import com.android.systemui.bouncer.shared.flag.ComposeBouncerFlags
import com.android.systemui.dagger.SysUISingleton
import com.android.systemui.dagger.qualifiers.Application
-import com.android.systemui.deviceentry.domain.interactor.DeviceEntryInteractor
+import com.android.systemui.deviceentry.domain.interactor.DeviceUnlockedInteractor
import com.android.systemui.keyguard.data.repository.KeyguardRepository
import com.android.systemui.keyguard.shared.model.DismissAction
import com.android.systemui.keyguard.shared.model.KeyguardDone
@@ -29,13 +29,12 @@
import com.android.systemui.keyguard.shared.model.KeyguardState.PRIMARY_BOUNCER
import com.android.systemui.power.domain.interactor.PowerInteractor
import com.android.systemui.scene.domain.interactor.SceneInteractor
-import com.android.systemui.scene.domain.resolver.NotifShadeSceneFamilyResolver
-import com.android.systemui.scene.domain.resolver.QuickSettingsSceneFamilyResolver
import com.android.systemui.scene.shared.flag.SceneContainerFlag
import com.android.systemui.scene.shared.model.Scenes
import com.android.systemui.shade.domain.interactor.ShadeInteractor
import com.android.systemui.util.kotlin.Utils.Companion.sampleFilter
import com.android.systemui.util.kotlin.sample
+import dagger.Lazy
import javax.inject.Inject
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.ExperimentalCoroutinesApi
@@ -61,14 +60,11 @@
transitionInteractor: KeyguardTransitionInteractor,
val dismissInteractor: KeyguardDismissInteractor,
@Application private val applicationScope: CoroutineScope,
- sceneInteractor: dagger.Lazy<SceneInteractor>,
- deviceEntryInteractor: dagger.Lazy<DeviceEntryInteractor>,
- quickSettingsSceneFamilyResolver: dagger.Lazy<QuickSettingsSceneFamilyResolver>,
- notifShadeSceneFamilyResolver: dagger.Lazy<NotifShadeSceneFamilyResolver>,
+ sceneInteractor: Lazy<SceneInteractor>,
+ deviceUnlockedInteractor: Lazy<DeviceUnlockedInteractor>,
powerInteractor: PowerInteractor,
alternateBouncerInteractor: AlternateBouncerInteractor,
- keyguardInteractor: dagger.Lazy<KeyguardInteractor>,
- shadeInteractor: dagger.Lazy<ShadeInteractor>,
+ shadeInteractor: Lazy<ShadeInteractor>,
) {
val dismissAction: Flow<DismissAction> = repository.dismissAction
@@ -106,18 +102,18 @@
if (SceneContainerFlag.isEnabled) {
combine(
sceneInteractor.get().currentScene,
- deviceEntryInteractor.get().isUnlocked,
- ) { scene, isUnlocked ->
- isUnlocked &&
- (quickSettingsSceneFamilyResolver.get().includesScene(scene) ||
- notifShadeSceneFamilyResolver.get().includesScene(scene))
+ deviceUnlockedInteractor.get().deviceUnlockStatus,
+ ) { scene, unlockStatus ->
+ unlockStatus.isUnlocked &&
+ (scene == Scenes.QuickSettings || scene == Scenes.Shade)
}
.distinctUntilChanged()
} else if (ComposeBouncerFlags.isOnlyComposeBouncerEnabled()) {
- shadeInteractor.get().isAnyExpanded.sample(
- keyguardInteractor.get().isKeyguardDismissible
- ) { isAnyExpanded, isKeyguardDismissible ->
- isAnyExpanded && isKeyguardDismissible
+ combine(
+ shadeInteractor.get().isAnyExpanded,
+ deviceUnlockedInteractor.get().deviceUnlockStatus,
+ ) { isAnyExpanded, deviceUnlockStatus ->
+ isAnyExpanded && deviceUnlockStatus.isUnlocked
}
} else {
flow {
@@ -132,7 +128,7 @@
merge(
finishedTransitionToGone,
isOnShadeWhileUnlocked.filter { it }.map {},
- dismissInteractor.dismissKeyguardRequestWithImmediateDismissAction
+ dismissInteractor.dismissKeyguardRequestWithImmediateDismissAction,
)
.sample(dismissAction)
.filterNot { it is DismissAction.None }
@@ -142,11 +138,11 @@
combine(
transitionInteractor.isFinishedIn(
scene = Scenes.Gone,
- stateWithoutSceneContainer = GONE
+ stateWithoutSceneContainer = GONE,
),
transitionInteractor.isFinishedIn(
scene = Scenes.Bouncer,
- stateWithoutSceneContainer = PRIMARY_BOUNCER
+ stateWithoutSceneContainer = PRIMARY_BOUNCER,
),
alternateBouncerInteractor.isVisible,
isOnShadeWhileUnlocked,
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/LockscreenUserActionsViewModel.kt b/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/LockscreenUserActionsViewModel.kt
index ecae079..3b266f9 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/LockscreenUserActionsViewModel.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/LockscreenUserActionsViewModel.kt
@@ -21,13 +21,11 @@
import com.android.compose.animation.scene.Edge
import com.android.compose.animation.scene.Swipe
import com.android.compose.animation.scene.SwipeDirection
-import com.android.compose.animation.scene.TransitionKey
import com.android.compose.animation.scene.UserAction
import com.android.compose.animation.scene.UserActionResult
import com.android.systemui.communal.domain.interactor.CommunalInteractor
import com.android.systemui.deviceentry.domain.interactor.DeviceEntryInteractor
import com.android.systemui.scene.shared.model.Overlays
-import com.android.systemui.scene.shared.model.SceneFamilies
import com.android.systemui.scene.shared.model.Scenes
import com.android.systemui.scene.shared.model.TransitionKeys.ToSplitShade
import com.android.systemui.scene.ui.viewmodel.SceneContainerEdge
@@ -71,9 +69,8 @@
addAll(
when (shadeMode) {
- ShadeMode.Single -> fullscreenShadeActions()
- ShadeMode.Split ->
- fullscreenShadeActions(transitionKey = ToSplitShade)
+ ShadeMode.Single -> singleShadeActions()
+ ShadeMode.Split -> splitShadeActions()
ShadeMode.Dual -> dualShadeActions()
}
)
@@ -84,18 +81,26 @@
.collect { setActions(it) }
}
- private fun fullscreenShadeActions(
- transitionKey: TransitionKey? = null
- ): Array<Pair<UserAction, UserActionResult>> {
- val notifShadeSceneKey = UserActionResult(SceneFamilies.NotifShade, transitionKey)
- val qsShadeSceneKey = UserActionResult(SceneFamilies.QuickSettings, transitionKey)
+ private fun singleShadeActions(): Array<Pair<UserAction, UserActionResult>> {
return arrayOf(
// Swiping down, not from the edge, always goes to shade.
- Swipe.Down to notifShadeSceneKey,
- swipeDown(pointerCount = 2) to notifShadeSceneKey,
+ Swipe.Down to Scenes.Shade,
+ swipeDown(pointerCount = 2) to Scenes.Shade,
// Swiping down from the top edge goes to QS.
- swipeDownFromTop(pointerCount = 1) to qsShadeSceneKey,
- swipeDownFromTop(pointerCount = 2) to qsShadeSceneKey,
+ swipeDownFromTop(pointerCount = 1) to Scenes.QuickSettings,
+ swipeDownFromTop(pointerCount = 2) to Scenes.QuickSettings,
+ )
+ }
+
+ private fun splitShadeActions(): Array<Pair<UserAction, UserActionResult>> {
+ val splitShadeSceneKey = UserActionResult(Scenes.Shade, ToSplitShade)
+ return arrayOf(
+ // Swiping down, not from the edge, always goes to shade.
+ Swipe.Down to splitShadeSceneKey,
+ swipeDown(pointerCount = 2) to splitShadeSceneKey,
+ // Swiping down from the top edge goes to QS.
+ swipeDownFromTop(pointerCount = 1) to splitShadeSceneKey,
+ swipeDownFromTop(pointerCount = 2) to splitShadeSceneKey,
)
}
diff --git a/packages/SystemUI/src/com/android/systemui/media/controls/domain/resume/MediaResumeListener.kt b/packages/SystemUI/src/com/android/systemui/media/controls/domain/resume/MediaResumeListener.kt
index 9ee59d1..ad84a5e 100644
--- a/packages/SystemUI/src/com/android/systemui/media/controls/domain/resume/MediaResumeListener.kt
+++ b/packages/SystemUI/src/com/android/systemui/media/controls/domain/resume/MediaResumeListener.kt
@@ -16,6 +16,7 @@
package com.android.systemui.media.controls.domain.resume
+import android.annotation.WorkerThread
import android.content.BroadcastReceiver
import android.content.ComponentName
import android.content.Context
@@ -41,6 +42,7 @@
import com.android.systemui.settings.UserTracker
import com.android.systemui.tuner.TunerService
import com.android.systemui.util.Utils
+import com.android.systemui.util.kotlin.logD
import com.android.systemui.util.time.SystemClock
import java.io.PrintWriter
import java.util.concurrent.ConcurrentLinkedQueue
@@ -86,11 +88,12 @@
@VisibleForTesting
val userUnlockReceiver =
object : BroadcastReceiver() {
+ @WorkerThread
override fun onReceive(context: Context, intent: Intent) {
if (Intent.ACTION_USER_UNLOCKED == intent.action) {
val userId = intent.getIntExtra(Intent.EXTRA_USER_HANDLE, -1)
if (userId == currentUserId) {
- backgroundExecutor.execute { loadMediaResumptionControls() }
+ loadMediaResumptionControls()
}
}
}
@@ -109,7 +112,7 @@
override fun addTrack(
desc: MediaDescription,
component: ComponentName,
- browser: ResumeMediaBrowser
+ browser: ResumeMediaBrowser,
) {
val token = browser.token
val appIntent = browser.appIntent
@@ -123,7 +126,7 @@
Log.e(TAG, "Error getting package information", e)
}
- Log.d(TAG, "Adding resume controls for ${browser.userId}: $desc")
+ logD(TAG) { "Adding resume controls for ${browser.userId}: $desc" }
mediaDataManager.addResumptionControls(
browser.userId,
desc,
@@ -131,7 +134,7 @@
token,
appName.toString(),
appIntent,
- component.packageName
+ component.packageName,
)
}
}
@@ -144,8 +147,8 @@
broadcastDispatcher.registerReceiver(
userUnlockReceiver,
unlockFilter,
- null,
- UserHandle.ALL
+ backgroundExecutor,
+ UserHandle.ALL,
)
userTracker.addCallback(userTrackerCallback, mainExecutor)
loadSavedComponents()
@@ -163,7 +166,7 @@
mediaDataManager.setMediaResumptionEnabled(useMediaResumption)
}
},
- Settings.Secure.MEDIA_CONTROLS_RESUME
+ Settings.Secure.MEDIA_CONTROLS_RESUME,
)
}
@@ -197,11 +200,11 @@
}
resumeComponents.add(component to lastPlayed)
}
- Log.d(
- TAG,
+
+ logD(TAG) {
"loaded resume components for $currentUserId: " +
- "${resumeComponents.toArray().contentToString()}"
- )
+ resumeComponents.toArray().contentToString()
+ }
if (needsUpdate) {
// Save any missing times that we had to fill in
@@ -228,7 +231,7 @@
mediaBrowserFactory.create(mediaBrowserCallback, it.first, currentUserId)
browser.findRecentMedia()
} else {
- Log.d(TAG, "User $currentUserId does not have component ${it.first}")
+ logD(TAG) { "User $currentUserId does not have component ${it.first}" }
}
}
}
@@ -240,7 +243,7 @@
data: MediaData,
immediately: Boolean,
receivedSmartspaceCardLatency: Int,
- isSsReactivated: Boolean
+ isSsReactivated: Boolean,
) {
if (useMediaResumption) {
// If this had been started from a resume state, disconnect now that it's live
@@ -281,7 +284,7 @@
mediaBrowserFactory.create(
object : ResumeMediaBrowser.Callback() {
override fun onConnected() {
- Log.d(TAG, "Connected to $componentName")
+ logD(TAG) { "Connected to $componentName" }
}
override fun onError() {
@@ -292,20 +295,20 @@
override fun addTrack(
desc: MediaDescription,
component: ComponentName,
- browser: ResumeMediaBrowser
+ browser: ResumeMediaBrowser,
) {
// Since this is a test, just save the component for later
- Log.d(
- TAG,
+ logD(TAG) {
"Can get resumable media for ${browser.userId} from $componentName"
- )
+ }
+
mediaDataManager.setResumeAction(key, getResumeAction(componentName))
updateResumptionList(componentName)
mediaBrowser = null
}
},
componentName,
- currentUserId
+ currentUserId,
)
mediaBrowser?.testConnection()
}
diff --git a/packages/SystemUI/src/com/android/systemui/model/SceneContainerPlugin.kt b/packages/SystemUI/src/com/android/systemui/model/SceneContainerPlugin.kt
index db5a545..0d748a1 100644
--- a/packages/SystemUI/src/com/android/systemui/model/SceneContainerPlugin.kt
+++ b/packages/SystemUI/src/com/android/systemui/model/SceneContainerPlugin.kt
@@ -17,11 +17,13 @@
package com.android.systemui.model
import com.android.compose.animation.scene.ObservableTransitionState
+import com.android.compose.animation.scene.OverlayKey
import com.android.compose.animation.scene.SceneKey
import com.android.systemui.dagger.SysUISingleton
import com.android.systemui.scene.domain.interactor.SceneContainerOcclusionInteractor
import com.android.systemui.scene.domain.interactor.SceneInteractor
import com.android.systemui.scene.shared.flag.SceneContainerFlag
+import com.android.systemui.scene.shared.model.Overlays
import com.android.systemui.scene.shared.model.Scenes
import com.android.systemui.shared.system.QuickStepContract.SYSUI_STATE_BOUNCER_SHOWING
import com.android.systemui.shared.system.QuickStepContract.SYSUI_STATE_COMMUNAL_HUB_SHOWING
@@ -57,12 +59,12 @@
val transitionState = sceneInteractor.get().transitionState.value
val idleTransitionStateOrNull = transitionState as? ObservableTransitionState.Idle
- val currentSceneOrNull = idleTransitionStateOrNull?.currentScene
val invisibleDueToOcclusion = occlusionInteractor.get().invisibleDueToOcclusion.value
- return currentSceneOrNull?.let { sceneKey ->
+ return idleTransitionStateOrNull?.let { idleState ->
EvaluatorByFlag[flag]?.invoke(
SceneContainerPluginState(
- scene = sceneKey,
+ scene = idleState.currentScene,
+ overlays = idleState.currentOverlays,
invisibleDueToOcclusion = invisibleDueToOcclusion,
)
)
@@ -89,10 +91,15 @@
it.invisibleDueToOcclusion -> false
it.scene == Scenes.Lockscreen -> true
it.scene == Scenes.Shade -> true
+ Overlays.NotificationsShade in it.overlays -> true
else -> false
}
},
- SYSUI_STATE_QUICK_SETTINGS_EXPANDED to { it.scene == Scenes.QuickSettings },
+ SYSUI_STATE_QUICK_SETTINGS_EXPANDED to
+ {
+ it.scene == Scenes.QuickSettings ||
+ Overlays.QuickSettingsShade in it.overlays
+ },
SYSUI_STATE_BOUNCER_SHOWING to { it.scene == Scenes.Bouncer },
SYSUI_STATE_STATUS_BAR_KEYGUARD_SHOWING to
{
@@ -106,5 +113,9 @@
)
}
- data class SceneContainerPluginState(val scene: SceneKey, val invisibleDueToOcclusion: Boolean)
+ data class SceneContainerPluginState(
+ val scene: SceneKey,
+ val overlays: Set<OverlayKey>,
+ val invisibleDueToOcclusion: Boolean,
+ )
}
diff --git a/packages/SystemUI/src/com/android/systemui/qs/TEST_MAPPING b/packages/SystemUI/src/com/android/systemui/qs/TEST_MAPPING
index 66f020f..75140be 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/TEST_MAPPING
+++ b/packages/SystemUI/src/com/android/systemui/qs/TEST_MAPPING
@@ -1,28 +1,12 @@
{
"presubmit": [
{
- "name": "CtsTileServiceTestCases",
- "options": [
- {
- "exclude-annotation": "org.junit.Ignore"
- },
- {
- "exclude-annotation": "androidx.test.filters.FlakyTest"
- }
- ]
+ "name": "CtsTileServiceTestCases"
}
],
"postsubmit": [
{
- "name": "QuickSettingsDeviceResetTests",
- "options": [
- {
- "exclude-annotation": "org.junit.Ignore"
- },
- {
- "exclude-annotation": "androidx.test.filters.FlakyTest"
- }
- ]
+ "name": "QuickSettingsDeviceResetTests"
}
]
}
\ No newline at end of file
diff --git a/packages/SystemUI/src/com/android/systemui/qs/composefragment/QSFragmentCompose.kt b/packages/SystemUI/src/com/android/systemui/qs/composefragment/QSFragmentCompose.kt
index c2f1c3d..af167d4 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/composefragment/QSFragmentCompose.kt
+++ b/packages/SystemUI/src/com/android/systemui/qs/composefragment/QSFragmentCompose.kt
@@ -158,7 +158,7 @@
override fun onCreateView(
inflater: LayoutInflater,
container: ViewGroup?,
- savedInstanceState: Bundle?
+ savedInstanceState: Bundle?,
): View {
val context = inflater.context
return ComposeView(context).apply {
@@ -181,7 +181,7 @@
notificationScrimClippingParams.bottom,
notificationScrimClippingParams.radius,
)
- }
+ },
) {
AnimatedContent(targetState = qsState) {
when (it) {
@@ -272,7 +272,7 @@
qsExpansionFraction: Float,
panelExpansionFraction: Float,
headerTranslation: Float,
- squishinessFraction: Float
+ squishinessFraction: Float,
) {
viewModel.qsExpansionValue = qsExpansionFraction
viewModel.panelExpansionFractionValue = panelExpansionFraction
@@ -318,12 +318,12 @@
override fun setTransitionToFullShadeProgress(
isTransitioningToFullShade: Boolean,
qsTransitionFraction: Float,
- qsSquishinessFraction: Float
+ qsSquishinessFraction: Float,
) {
super.setTransitionToFullShadeProgress(
isTransitioningToFullShade,
qsTransitionFraction,
- qsSquishinessFraction
+ qsSquishinessFraction,
)
}
@@ -334,7 +334,7 @@
bottom: Int,
cornerRadius: Int,
visible: Boolean,
- fullWidth: Boolean
+ fullWidth: Boolean,
) {
notificationScrimClippingParams.isEnabled = visible
notificationScrimClippingParams.top = top
@@ -402,7 +402,7 @@
launch {
setListenerJob(
heightListener,
- viewModel.containerViewModel.editModeViewModel.isEditing
+ viewModel.containerViewModel.editModeViewModel.isEditing,
) {
onQsHeightChanged()
}
@@ -410,7 +410,7 @@
launch {
setListenerJob(
qsContainerController,
- viewModel.containerViewModel.editModeViewModel.isEditing
+ viewModel.containerViewModel.editModeViewModel.isEditing,
) {
setCustomizerShowing(it)
}
@@ -422,6 +422,7 @@
@Composable
private fun QuickQuickSettingsElement() {
val qqsPadding by viewModel.qqsHeaderHeight.collectAsStateWithLifecycle()
+ val bottomPadding = dimensionResource(id = R.dimen.qqs_layout_padding_bottom)
DisposableEffect(Unit) {
qqsVisible.value = true
@@ -441,7 +442,7 @@
)
}
.onSizeChanged { size -> qqsHeight.value = size.height }
- .padding(top = { qqsPadding })
+ .padding(top = { qqsPadding }, bottom = { bottomPadding.roundToPx() })
) {
val qsEnabled by viewModel.qsEnabled.collectAsStateWithLifecycle()
if (qsEnabled) {
@@ -450,7 +451,7 @@
modifier =
Modifier.collapseExpandSemanticAction(
stringResource(id = R.string.accessibility_quick_settings_expand)
- )
+ ),
)
}
}
@@ -482,7 +483,7 @@
FooterActions(
viewModel = viewModel.footerActionsViewModel,
qsVisibilityLifecycleOwner = this@QSFragmentCompose,
- modifier = Modifier.sysuiResTag("qs_footer_actions")
+ modifier = Modifier.sysuiResTag("qs_footer_actions"),
)
}
}
@@ -562,7 +563,7 @@
private suspend inline fun <Listener : Any, Data> setListenerJob(
listenerFlow: MutableStateFlow<Listener?>,
dataFlow: Flow<Data>,
- crossinline onCollect: suspend Listener.(Data) -> Unit
+ crossinline onCollect: suspend Listener.(Data) -> Unit,
) {
coroutineScope {
try {
diff --git a/packages/SystemUI/src/com/android/systemui/qs/panels/ui/compose/QuickQuickSettings.kt b/packages/SystemUI/src/com/android/systemui/qs/panels/ui/compose/QuickQuickSettings.kt
index eeb55ca..fde40da 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/panels/ui/compose/QuickQuickSettings.kt
+++ b/packages/SystemUI/src/com/android/systemui/qs/panels/ui/compose/QuickQuickSettings.kt
@@ -22,18 +22,16 @@
import androidx.compose.runtime.DisposableEffect
import androidx.compose.runtime.getValue
import androidx.compose.ui.Modifier
+import androidx.compose.ui.util.fastMap
import androidx.lifecycle.compose.collectAsStateWithLifecycle
import com.android.systemui.compose.modifiers.sysuiResTag
import com.android.systemui.qs.panels.ui.viewmodel.QuickQuickSettingsViewModel
@Composable
-fun QuickQuickSettings(
- viewModel: QuickQuickSettingsViewModel,
- modifier: Modifier = Modifier,
-) {
+fun QuickQuickSettings(viewModel: QuickQuickSettingsViewModel, modifier: Modifier = Modifier) {
val sizedTiles by
viewModel.tileViewModels.collectAsStateWithLifecycle(initialValue = emptyList())
- val tiles = sizedTiles.map { it.tile }
+ val tiles = sizedTiles.fastMap { it.tile }
DisposableEffect(tiles) {
val token = Any()
@@ -44,14 +42,18 @@
TileLazyGrid(
modifier = modifier.sysuiResTag("qqs_tile_layout"),
- columns = GridCells.Fixed(columns)
+ columns = GridCells.Fixed(columns),
) {
items(
- tiles.size,
+ sizedTiles.size,
key = { index -> sizedTiles[index].tile.spec.spec },
- span = { index -> GridItemSpan(sizedTiles[index].width) }
+ span = { index -> GridItemSpan(sizedTiles[index].width) },
) { index ->
- Tile(tile = tiles[index], iconOnly = sizedTiles[index].isIcon, modifier = Modifier)
+ Tile(
+ tile = sizedTiles[index].tile,
+ iconOnly = sizedTiles[index].isIcon,
+ modifier = Modifier,
+ )
}
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/qs/panels/ui/compose/Tile.kt b/packages/SystemUI/src/com/android/systemui/qs/panels/ui/compose/Tile.kt
index 93037d1..afd47a7 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/panels/ui/compose/Tile.kt
+++ b/packages/SystemUI/src/com/android/systemui/qs/panels/ui/compose/Tile.kt
@@ -18,6 +18,7 @@
package com.android.systemui.qs.panels.ui.compose
+import android.content.res.Resources
import android.graphics.drawable.Animatable
import android.service.quicksettings.Tile.STATE_ACTIVE
import android.service.quicksettings.Tile.STATE_INACTIVE
@@ -71,6 +72,7 @@
import androidx.compose.runtime.Composable
import androidx.compose.runtime.CompositionLocalProvider
import androidx.compose.runtime.LaunchedEffect
+import androidx.compose.runtime.ReadOnlyComposable
import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.remember
@@ -85,13 +87,19 @@
import androidx.compose.ui.graphics.Shape
import androidx.compose.ui.layout.onGloballyPositioned
import androidx.compose.ui.layout.positionInRoot
+import androidx.compose.ui.platform.LocalConfiguration
import androidx.compose.ui.platform.LocalContext
import androidx.compose.ui.platform.testTag
import androidx.compose.ui.res.dimensionResource
import androidx.compose.ui.res.stringResource
+import androidx.compose.ui.semantics.Role
+import androidx.compose.ui.semantics.clearAndSetSemantics
+import androidx.compose.ui.semantics.contentDescription
import androidx.compose.ui.semantics.onClick
+import androidx.compose.ui.semantics.role
import androidx.compose.ui.semantics.semantics
import androidx.compose.ui.semantics.stateDescription
+import androidx.compose.ui.semantics.toggleableState
import androidx.compose.ui.text.style.TextAlign
import androidx.compose.ui.text.style.TextOverflow
import androidx.compose.ui.unit.Dp
@@ -106,12 +114,15 @@
import com.android.systemui.common.shared.model.Icon
import com.android.systemui.common.ui.compose.Icon
import com.android.systemui.common.ui.compose.load
+import com.android.systemui.compose.modifiers.sysuiResTag
import com.android.systemui.plugins.qs.QSTile
import com.android.systemui.qs.panels.shared.model.SizedTile
import com.android.systemui.qs.panels.shared.model.SizedTileImpl
+import com.android.systemui.qs.panels.ui.compose.TileDefaults.longPressLabel
import com.android.systemui.qs.panels.ui.model.GridCell
import com.android.systemui.qs.panels.ui.model.SpacerGridCell
import com.android.systemui.qs.panels.ui.model.TileGridCell
+import com.android.systemui.qs.panels.ui.viewmodel.AccessibilityUiState
import com.android.systemui.qs.panels.ui.viewmodel.EditTileViewModel
import com.android.systemui.qs.panels.ui.viewmodel.TileUiState
import com.android.systemui.qs.panels.ui.viewmodel.TileViewModel
@@ -126,15 +137,15 @@
object TileType
+private const val TEST_TAG_SMALL = "qs_tile_small"
+private const val TEST_TAG_LARGE = "qs_tile_large"
+private const val TEST_TAG_TOGGLE = "qs_tile_toggle_target"
+
@Composable
-fun Tile(
- tile: TileViewModel,
- iconOnly: Boolean,
- showLabels: Boolean = false,
- modifier: Modifier,
-) {
+fun Tile(tile: TileViewModel, iconOnly: Boolean, showLabels: Boolean = false, modifier: Modifier) {
val state by tile.state.collectAsStateWithLifecycle(tile.currentState)
- val uiState = remember(state) { state.toUiState() }
+ val resources = resources()
+ val uiState = remember(state, resources) { state.toUiState(resources) }
val colors = TileDefaults.getColorForState(uiState)
// TODO(b/361789146): Draw the shapes instead of clipping
@@ -150,6 +161,7 @@
onClick = tile::onClick,
onLongClick = tile::onLongClick,
modifier = modifier.height(tileHeight()),
+ uiState = uiState,
) {
val icon = getTileIcon(icon = uiState.icon)
if (iconOnly) {
@@ -169,6 +181,7 @@
}
},
onLongClick = { tile.onLongClick(it) },
+ accessibilityUiState = uiState.accessibilityUiState,
)
}
}
@@ -185,6 +198,7 @@
onClick: (Expandable) -> Unit = {},
onLongClick: (Expandable) -> Unit = {},
modifier: Modifier = Modifier,
+ uiState: TileUiState? = null,
content: @Composable BoxScope.(Expandable) -> Unit,
) {
Column(
@@ -194,7 +208,7 @@
modifier = modifier,
) {
val backgroundColor =
- if (iconOnly) {
+ if (iconOnly || uiState?.handlesSecondaryClick != true) {
colors.iconBackground
} else {
colors.background
@@ -202,18 +216,43 @@
Expandable(
color = backgroundColor,
shape = shape,
- modifier = Modifier.height(tileHeight()).clip(shape)
+ modifier = Modifier.height(tileHeight()).clip(shape),
) {
+ val longPressLabel = longPressLabel()
Box(
modifier =
Modifier.fillMaxSize()
.thenIf(clickEnabled) {
Modifier.combinedClickable(
onClick = { onClick(it) },
- onLongClick = { onLongClick(it) }
+ onLongClick = { onLongClick(it) },
+ onClickLabel = uiState?.accessibilityUiState?.clickLabel,
+ onLongClickLabel = longPressLabel,
)
}
- .tilePadding(),
+ .thenIf(uiState != null) {
+ uiState as TileUiState
+ Modifier.semantics {
+ role = uiState.accessibilityUiState.accessibilityRole
+ if (
+ uiState.accessibilityUiState.accessibilityRole ==
+ Role.Switch
+ ) {
+ uiState.accessibilityUiState.toggleableState?.let {
+ toggleableState = it
+ }
+ }
+ stateDescription = uiState.accessibilityUiState.stateDescription
+ }
+ .sysuiResTag(if (iconOnly) TEST_TAG_SMALL else TEST_TAG_LARGE)
+ .thenIf(iconOnly) {
+ Modifier.semantics {
+ contentDescription =
+ uiState.accessibilityUiState.contentDescription
+ }
+ }
+ }
+ .tilePadding()
) {
content(it)
}
@@ -238,21 +277,39 @@
icon: Icon,
colors: TileColors,
iconShape: Shape,
+ accessibilityUiState: AccessibilityUiState? = null,
toggleClickSupported: Boolean = false,
onClick: () -> Unit = {},
onLongClick: () -> Unit = {},
) {
Row(
verticalAlignment = Alignment.CenterVertically,
- horizontalArrangement = tileHorizontalArrangement()
+ horizontalArrangement = tileHorizontalArrangement(),
) {
// Icon
+ val longPressLabel = longPressLabel()
Box(
modifier =
Modifier.size(TileDefaults.ToggleTargetSize).thenIf(toggleClickSupported) {
Modifier.clip(iconShape)
.background(colors.iconBackground, { 1f })
- .combinedClickable(onClick = onClick, onLongClick = onLongClick)
+ .combinedClickable(
+ onClick = onClick,
+ onLongClick = onLongClick,
+ onLongClickLabel = longPressLabel,
+ )
+ .thenIf(accessibilityUiState != null) {
+ accessibilityUiState as AccessibilityUiState
+ Modifier.semantics {
+ contentDescription = accessibilityUiState.contentDescription
+ stateDescription = accessibilityUiState.stateDescription
+ accessibilityUiState.toggleableState?.let {
+ toggleableState = it
+ }
+ role = Role.Switch
+ }
+ .sysuiResTag(TEST_TAG_TOGGLE)
+ }
}
) {
TileIcon(icon = icon, color = colors.icon, modifier = Modifier.align(Alignment.Center))
@@ -260,16 +317,19 @@
// Labels
Column(verticalArrangement = Arrangement.Center, modifier = Modifier.fillMaxHeight()) {
- Text(
- label,
- color = colors.label,
- modifier = Modifier.tileMarquee(),
- )
+ Text(label, color = colors.label, modifier = Modifier.tileMarquee())
if (!TextUtils.isEmpty(secondaryLabel)) {
Text(
secondaryLabel ?: "",
color = colors.secondaryLabel,
- modifier = Modifier.tileMarquee(),
+ modifier =
+ Modifier.tileMarquee().thenIf(
+ accessibilityUiState
+ ?.stateDescription
+ ?.contains(secondaryLabel ?: "") == true
+ ) {
+ Modifier.clearAndSetSemantics {}
+ },
)
}
}
@@ -277,10 +337,7 @@
}
private fun Modifier.tileMarquee(): Modifier {
- return basicMarquee(
- iterations = 1,
- initialDelayMillis = 200,
- )
+ return basicMarquee(iterations = 1, initialDelayMillis = 200)
}
@Composable
@@ -320,11 +377,11 @@
Column(
verticalArrangement =
spacedBy(dimensionResource(id = R.dimen.qs_label_container_margin)),
- modifier = modifier.fillMaxSize().verticalScroll(rememberScrollState())
+ modifier = modifier.fillMaxSize().verticalScroll(rememberScrollState()),
) {
AnimatedContent(
targetState = currentListState.dragInProgress,
- modifier = Modifier.wrapContentSize()
+ modifier = Modifier.wrapContentSize(),
) { dragIsInProgress ->
EditGridHeader(Modifier.dragAndDropRemoveZone(currentListState, onRemoveTile)) {
if (dragIsInProgress) {
@@ -348,12 +405,12 @@
AnimatedVisibility(
visible = !currentListState.dragInProgress,
enter = fadeIn(),
- exit = fadeOut()
+ exit = fadeOut(),
) {
Column(
verticalArrangement =
spacedBy(dimensionResource(id = R.dimen.qs_label_container_margin)),
- modifier = modifier.fillMaxSize()
+ modifier = modifier.fillMaxSize(),
) {
EditGridHeader { Text(text = "Hold and drag to add tiles.") }
@@ -381,14 +438,14 @@
@Composable
private fun EditGridHeader(
modifier: Modifier = Modifier,
- content: @Composable BoxScope.() -> Unit
+ content: @Composable BoxScope.() -> Unit,
) {
CompositionLocalProvider(
LocalContentColor provides MaterialTheme.colorScheme.onBackground.copy(alpha = .5f)
) {
Box(
contentAlignment = Alignment.Center,
- modifier = modifier.fillMaxWidth().height(EditModeTileDefaults.EditGridHeaderHeight)
+ modifier = modifier.fillMaxWidth().height(EditModeTileDefaults.EditGridHeaderHeight),
) {
content()
}
@@ -403,7 +460,7 @@
modifier =
Modifier.fillMaxHeight()
.border(1.dp, LocalContentColor.current, shape = CircleShape)
- .padding(10.dp)
+ .padding(10.dp),
) {
Icon(imageVector = Icons.Default.Clear, contentDescription = null)
Text(text = "Remove")
@@ -454,7 +511,7 @@
gridContentOffset = coordinates.positionInRoot()
}
.testTag(CURRENT_TILES_GRID_TEST_TAG),
- columns = GridCells.Fixed(columns)
+ columns = GridCells.Fixed(columns),
) {
editTiles(
listState.tiles,
@@ -488,7 +545,7 @@
// Available tiles
TileLazyGrid(
modifier = Modifier.height(availableGridHeight).testTag(AVAILABLE_TILES_GRID_TEST_TAG),
- columns = GridCells.Fixed(columns)
+ columns = GridCells.Fixed(columns),
) {
groupedTiles.forEach { category, tiles ->
stickyHeader {
@@ -498,7 +555,7 @@
color = labelColors.label,
modifier =
Modifier.background(Color.Black)
- .padding(start = 16.dp, bottom = 8.dp, top = 8.dp)
+ .padding(start = 16.dp, bottom = 8.dp, top = 8.dp),
)
}
editTiles(
@@ -542,7 +599,7 @@
count = cells.size,
key = { cells[it].key(it, dragAndDropState) },
span = { cells[it].span },
- contentType = { TileType }
+ contentType = { TileType },
) { index ->
when (val cell = cells[index]) {
is TileGridCell ->
@@ -552,7 +609,7 @@
Modifier.background(
color = MaterialTheme.colorScheme.secondary,
alpha = { EditModeTileDefaults.PLACEHOLDER_ALPHA },
- shape = RoundedCornerShape(TileDefaults.InactiveCornerRadius)
+ shape = RoundedCornerShape(TileDefaults.InactiveCornerRadius),
)
.animateItem()
)
@@ -565,7 +622,7 @@
onClick = onClick,
onResize = onResize,
showLabels = showLabels,
- indicatePosition = indicatePosition
+ indicatePosition = indicatePosition,
)
}
is SpacerGridCell -> SpacerGridCell()
@@ -604,7 +661,7 @@
modifier =
Modifier.height(tileHeight)
.animateItem()
- .semantics {
+ .semantics(mergeDescendants = true) {
onClick(onClickActionName) { false }
this.stateDescription = stateDescription
}
@@ -613,7 +670,7 @@
onClick,
onResize,
dragAndDropState,
- )
+ ),
)
}
@@ -645,7 +702,7 @@
TileIcon(
icon = tileViewModel.icon,
color = colors.icon,
- modifier = Modifier.align(Alignment.Center)
+ modifier = Modifier.align(Alignment.Center),
)
} else {
LargeTileContent(
@@ -694,11 +751,7 @@
}
}
if (loadedDrawable !is Animatable) {
- Icon(
- icon = icon,
- tint = color,
- modifier = iconModifier,
- )
+ Icon(icon = icon, tint = color, modifier = iconModifier)
} else if (icon is Icon.Resource) {
val image = AnimatedImageVector.animatedVectorResource(id = icon.res)
val painter =
@@ -716,7 +769,7 @@
painter = painter,
contentDescription = icon.contentDescription?.load(),
colorFilter = ColorFilter.tint(color = color),
- modifier = iconModifier
+ modifier = iconModifier,
)
}
}
@@ -765,6 +818,8 @@
val TileHeight = 72.dp
val IconTileWithLabelHeight = 140.dp
+ @Composable fun longPressLabel() = stringResource(id = R.string.accessibility_long_click_tile)
+
/** An active tile without dual target uses the active color as background */
@Composable
fun activeTileColors(): TileColors =
@@ -850,7 +905,7 @@
} else {
InactiveCornerRadius
},
- label = label
+ label = label,
)
return RoundedCornerShape(animatedCornerRadius)
}
@@ -858,3 +913,14 @@
private const val CURRENT_TILES_GRID_TEST_TAG = "CurrentTilesGrid"
private const val AVAILABLE_TILES_GRID_TEST_TAG = "AvailableTilesGrid"
+
+/**
+ * A composable function that returns the [Resources]. It will be recomposed when [Configuration]
+ * gets updated.
+ */
+@Composable
+@ReadOnlyComposable
+private fun resources(): Resources {
+ LocalConfiguration.current
+ return LocalContext.current.resources
+}
diff --git a/packages/SystemUI/src/com/android/systemui/qs/panels/ui/viewmodel/TileUiState.kt b/packages/SystemUI/src/com/android/systemui/qs/panels/ui/viewmodel/TileUiState.kt
index 45051fe..aa42080 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/panels/ui/viewmodel/TileUiState.kt
+++ b/packages/SystemUI/src/com/android/systemui/qs/panels/ui/viewmodel/TileUiState.kt
@@ -16,8 +16,16 @@
package com.android.systemui.qs.panels.ui.viewmodel
+import android.content.res.Resources
+import android.service.quicksettings.Tile
+import android.text.TextUtils
+import android.widget.Switch
import androidx.compose.runtime.Immutable
+import androidx.compose.ui.semantics.Role
+import androidx.compose.ui.state.ToggleableState
import com.android.systemui.plugins.qs.QSTile
+import com.android.systemui.qs.tileimpl.SubtitleArrayMapping
+import com.android.systemui.res.R
import java.util.function.Supplier
@Immutable
@@ -27,14 +35,78 @@
val state: Int,
val handlesSecondaryClick: Boolean,
val icon: Supplier<QSTile.Icon?>,
+ val accessibilityUiState: AccessibilityUiState,
)
-fun QSTile.State.toUiState(): TileUiState {
+data class AccessibilityUiState(
+ val contentDescription: String,
+ val stateDescription: String,
+ val accessibilityRole: Role,
+ val toggleableState: ToggleableState? = null,
+ val clickLabel: String? = null,
+)
+
+fun QSTile.State.toUiState(resources: Resources): TileUiState {
+ val accessibilityRole =
+ if (expandedAccessibilityClassName == Switch::class.java.name && !handlesSecondaryClick) {
+ Role.Switch
+ } else {
+ Role.Button
+ }
+ // State handling and description
+ val stateDescription = StringBuilder()
+ val stateText =
+ if (accessibilityRole == Role.Switch || state == Tile.STATE_UNAVAILABLE) {
+ getStateText(resources)
+ } else {
+ ""
+ }
+ val secondaryLabel = getSecondaryLabel(stateText)
+ if (!TextUtils.isEmpty(stateText)) {
+ stateDescription.append(stateText)
+ }
+ if (disabledByPolicy && state != Tile.STATE_UNAVAILABLE) {
+ stateDescription.append(", ")
+ stateDescription.append(getUnavailableText(spec, resources))
+ }
+ if (
+ !TextUtils.isEmpty(this.stateDescription) &&
+ !stateDescription.contains(this.stateDescription!!)
+ ) {
+ stateDescription.append(", ")
+ stateDescription.append(this.stateDescription)
+ }
+ val toggleableState =
+ if (accessibilityRole == Role.Switch || handlesSecondaryClick) {
+ ToggleableState(state == Tile.STATE_ACTIVE)
+ } else {
+ null
+ }
return TileUiState(
- label?.toString() ?: "",
- secondaryLabel?.toString() ?: "",
- state,
- handlesSecondaryClick,
- icon?.let { Supplier { icon } } ?: iconSupplier ?: Supplier { null },
+ label = label?.toString() ?: "",
+ secondaryLabel = secondaryLabel?.toString() ?: "",
+ state = if (disabledByPolicy) Tile.STATE_UNAVAILABLE else state,
+ handlesSecondaryClick = handlesSecondaryClick,
+ icon = icon?.let { Supplier { icon } } ?: iconSupplier ?: Supplier { null },
+ AccessibilityUiState(
+ contentDescription?.toString() ?: "",
+ stateDescription.toString(),
+ accessibilityRole,
+ toggleableState,
+ resources
+ .getString(R.string.accessibility_tile_disabled_by_policy_action_description)
+ .takeIf { disabledByPolicy },
+ ),
)
}
+
+private fun QSTile.State.getStateText(resources: Resources): CharSequence {
+ val arrayResId = SubtitleArrayMapping.getSubtitleId(spec)
+ val array = resources.getStringArray(arrayResId)
+ return array[state]
+}
+
+private fun getUnavailableText(spec: String?, resources: Resources): String {
+ val arrayResId = SubtitleArrayMapping.getSubtitleId(spec)
+ return resources.getStringArray(arrayResId)[Tile.STATE_UNAVAILABLE]
+}
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/BluetoothTile.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/BluetoothTile.java
index 7ceb786..7bff827 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tiles/BluetoothTile.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/BluetoothTile.java
@@ -32,7 +32,7 @@
import android.service.quicksettings.Tile;
import android.text.TextUtils;
import android.util.Log;
-import android.widget.Switch;
+import android.widget.Button;
import androidx.annotation.VisibleForTesting;
@@ -59,13 +59,13 @@
import com.android.systemui.res.R;
import com.android.systemui.statusbar.policy.BluetoothController;
-import kotlinx.coroutines.Job;
-
import java.util.List;
import java.util.concurrent.Executor;
import javax.inject.Inject;
+import kotlinx.coroutines.Job;
+
/** Quick settings tile: Bluetooth **/
public class BluetoothTile extends QSTileImpl<BooleanState> {
@@ -147,6 +147,8 @@
}
}
+
+
@Override
public Intent getLongClickIntent() {
return new Intent(Settings.ACTION_BLUETOOTH_SETTINGS);
@@ -221,7 +223,7 @@
state.state = Tile.STATE_INACTIVE;
}
- state.expandedAccessibilityClassName = Switch.class.getName();
+ state.expandedAccessibilityClassName = Button.class.getName();
state.forceExpandIcon = mFeatureFlags.isEnabled(Flags.BLUETOOTH_QS_TILE_DIALOG);
}
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/FontScalingTile.kt b/packages/SystemUI/src/com/android/systemui/qs/tiles/FontScalingTile.kt
index 078698c..7606293 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tiles/FontScalingTile.kt
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/FontScalingTile.kt
@@ -55,7 +55,7 @@
qsLogger: QSLogger,
private val keyguardStateController: KeyguardStateController,
private val dialogTransitionAnimator: DialogTransitionAnimator,
- private val fontScalingDialogDelegateProvider: Provider<FontScalingDialogDelegate>
+ private val fontScalingDialogDelegateProvider: Provider<FontScalingDialogDelegate>,
) :
QSTileImpl<QSTile.State?>(
host,
@@ -66,7 +66,7 @@
metricsLogger,
statusBarStateController,
activityStarter,
- qsLogger
+ qsLogger,
) {
private val icon = ResourceIcon.get(R.drawable.ic_qs_font_scaling)
@@ -86,7 +86,7 @@
expandable?.dialogTransitionController(
DialogCuj(
InteractionJankMonitor.CUJ_SHADE_DIALOG_OPEN,
- INTERACTION_JANK_TAG
+ INTERACTION_JANK_TAG,
)
)
controller?.let { dialogTransitionAnimator.show(dialog, controller) }
@@ -102,7 +102,7 @@
/* cancelAction= */ null,
/* dismissShade= */ true,
/* afterKeyguardGone= */ true,
- /* deferred= */ false
+ /* deferred= */ false,
)
}
}
@@ -110,6 +110,7 @@
override fun handleUpdateState(state: QSTile.State?, arg: Any?) {
state?.label = mContext.getString(R.string.quick_settings_font_scaling_label)
state?.icon = icon
+ state?.contentDescription = state?.label
}
override fun getLongClickIntent(): Intent? {
diff --git a/packages/SystemUI/src/com/android/systemui/scene/KeyguardlessSceneContainerFrameworkModule.kt b/packages/SystemUI/src/com/android/systemui/scene/KeyguardlessSceneContainerFrameworkModule.kt
index 1aa982f..e441a23 100644
--- a/packages/SystemUI/src/com/android/systemui/scene/KeyguardlessSceneContainerFrameworkModule.kt
+++ b/packages/SystemUI/src/com/android/systemui/scene/KeyguardlessSceneContainerFrameworkModule.kt
@@ -22,8 +22,6 @@
import com.android.systemui.scene.domain.SceneDomainModule
import com.android.systemui.scene.domain.interactor.WindowRootViewVisibilityInteractor
import com.android.systemui.scene.domain.resolver.HomeSceneFamilyResolverModule
-import com.android.systemui.scene.domain.resolver.NotifShadeSceneFamilyResolverModule
-import com.android.systemui.scene.domain.resolver.QuickSettingsSceneFamilyResolverModule
import com.android.systemui.scene.domain.startable.KeyguardStateCallbackStartable
import com.android.systemui.scene.domain.startable.SceneContainerStartable
import com.android.systemui.scene.domain.startable.ScrimStartable
@@ -47,7 +45,6 @@
EmptySceneModule::class,
GoneSceneModule::class,
NotificationsShadeOverlayModule::class,
- NotificationsShadeSceneModule::class,
NotificationsShadeSessionModule::class,
QuickSettingsShadeOverlayModule::class,
QuickSettingsSceneModule::class,
@@ -56,8 +53,6 @@
// List SceneResolver modules for supported SceneFamilies
HomeSceneFamilyResolverModule::class,
- NotifShadeSceneFamilyResolverModule::class,
- QuickSettingsSceneFamilyResolverModule::class,
]
)
interface KeyguardlessSceneContainerFrameworkModule {
diff --git a/packages/SystemUI/src/com/android/systemui/scene/SceneContainerFrameworkModule.kt b/packages/SystemUI/src/com/android/systemui/scene/SceneContainerFrameworkModule.kt
index 7f0cf86..a89f752 100644
--- a/packages/SystemUI/src/com/android/systemui/scene/SceneContainerFrameworkModule.kt
+++ b/packages/SystemUI/src/com/android/systemui/scene/SceneContainerFrameworkModule.kt
@@ -22,8 +22,6 @@
import com.android.systemui.scene.domain.SceneDomainModule
import com.android.systemui.scene.domain.interactor.WindowRootViewVisibilityInteractor
import com.android.systemui.scene.domain.resolver.HomeSceneFamilyResolverModule
-import com.android.systemui.scene.domain.resolver.NotifShadeSceneFamilyResolverModule
-import com.android.systemui.scene.domain.resolver.QuickSettingsSceneFamilyResolverModule
import com.android.systemui.scene.domain.startable.KeyguardStateCallbackStartable
import com.android.systemui.scene.domain.startable.SceneContainerStartable
import com.android.systemui.scene.domain.startable.ScrimStartable
@@ -52,16 +50,12 @@
QuickSettingsSceneModule::class,
ShadeSceneModule::class,
QuickSettingsShadeOverlayModule::class,
- QuickSettingsShadeSceneModule::class,
NotificationsShadeOverlayModule::class,
- NotificationsShadeSceneModule::class,
NotificationsShadeSessionModule::class,
SceneDomainModule::class,
// List SceneResolver modules for supported SceneFamilies
HomeSceneFamilyResolverModule::class,
- NotifShadeSceneFamilyResolverModule::class,
- QuickSettingsSceneFamilyResolverModule::class,
]
)
interface SceneContainerFrameworkModule {
diff --git a/packages/SystemUI/src/com/android/systemui/scene/domain/resolver/NotifShadeSceneFamilyResolver.kt b/packages/SystemUI/src/com/android/systemui/scene/domain/resolver/NotifShadeSceneFamilyResolver.kt
deleted file mode 100644
index a313273..0000000
--- a/packages/SystemUI/src/com/android/systemui/scene/domain/resolver/NotifShadeSceneFamilyResolver.kt
+++ /dev/null
@@ -1,71 +0,0 @@
-/*
- * 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 com.android.systemui.scene.domain.resolver
-
-import com.android.compose.animation.scene.SceneKey
-import com.android.systemui.dagger.SysUISingleton
-import com.android.systemui.dagger.qualifiers.Application
-import com.android.systemui.scene.shared.model.SceneFamilies
-import com.android.systemui.scene.shared.model.Scenes
-import com.android.systemui.shade.domain.interactor.ShadeModeInteractor
-import com.android.systemui.shade.shared.model.ShadeMode
-import dagger.Binds
-import dagger.Module
-import dagger.multibindings.IntoSet
-import javax.inject.Inject
-import kotlinx.coroutines.CoroutineScope
-import kotlinx.coroutines.flow.SharingStarted
-import kotlinx.coroutines.flow.StateFlow
-import kotlinx.coroutines.flow.map
-import kotlinx.coroutines.flow.stateIn
-
-@SysUISingleton
-class NotifShadeSceneFamilyResolver
-@Inject
-constructor(
- @Application applicationScope: CoroutineScope,
- shadeModeInteractor: ShadeModeInteractor,
-) : SceneResolver {
- override val targetFamily: SceneKey = SceneFamilies.NotifShade
-
- override val resolvedScene: StateFlow<SceneKey> =
- shadeModeInteractor.shadeMode
- .map(::notifShadeScene)
- .stateIn(
- applicationScope,
- started = SharingStarted.Eagerly,
- initialValue = notifShadeScene(shadeModeInteractor.shadeMode.value),
- )
-
- override fun includesScene(scene: SceneKey): Boolean = scene in notifShadeScenes
-
- private fun notifShadeScene(shadeMode: ShadeMode) =
- when (shadeMode) {
- is ShadeMode.Single -> Scenes.Shade
- is ShadeMode.Dual -> Scenes.NotificationsShade
- is ShadeMode.Split -> Scenes.Shade
- }
-
- companion object {
- val notifShadeScenes = setOf(Scenes.NotificationsShade, Scenes.Shade)
- }
-}
-
-@Module
-interface NotifShadeSceneFamilyResolverModule {
- @Binds @IntoSet fun bindResolver(interactor: NotifShadeSceneFamilyResolver): SceneResolver
-}
diff --git a/packages/SystemUI/src/com/android/systemui/scene/domain/resolver/QuickSettingsSceneFamilyResolver.kt b/packages/SystemUI/src/com/android/systemui/scene/domain/resolver/QuickSettingsSceneFamilyResolver.kt
deleted file mode 100644
index 923e712a..0000000
--- a/packages/SystemUI/src/com/android/systemui/scene/domain/resolver/QuickSettingsSceneFamilyResolver.kt
+++ /dev/null
@@ -1,72 +0,0 @@
-/*
- * 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 com.android.systemui.scene.domain.resolver
-
-import com.android.compose.animation.scene.SceneKey
-import com.android.systemui.dagger.SysUISingleton
-import com.android.systemui.dagger.qualifiers.Application
-import com.android.systemui.scene.shared.model.SceneFamilies
-import com.android.systemui.scene.shared.model.Scenes
-import com.android.systemui.shade.domain.interactor.ShadeModeInteractor
-import com.android.systemui.shade.shared.model.ShadeMode
-import dagger.Binds
-import dagger.Module
-import dagger.multibindings.IntoSet
-import javax.inject.Inject
-import kotlinx.coroutines.CoroutineScope
-import kotlinx.coroutines.flow.SharingStarted
-import kotlinx.coroutines.flow.StateFlow
-import kotlinx.coroutines.flow.map
-import kotlinx.coroutines.flow.stateIn
-
-@SysUISingleton
-class QuickSettingsSceneFamilyResolver
-@Inject
-constructor(
- @Application applicationScope: CoroutineScope,
- shadeModeInteractor: ShadeModeInteractor,
-) : SceneResolver {
- override val targetFamily: SceneKey = SceneFamilies.QuickSettings
-
- override val resolvedScene: StateFlow<SceneKey> =
- shadeModeInteractor.shadeMode
- .map(::quickSettingsScene)
- .stateIn(
- applicationScope,
- started = SharingStarted.Eagerly,
- initialValue = quickSettingsScene(shadeModeInteractor.shadeMode.value),
- )
-
- override fun includesScene(scene: SceneKey): Boolean = scene in quickSettingsScenes
-
- private fun quickSettingsScene(shadeMode: ShadeMode) =
- when (shadeMode) {
- is ShadeMode.Single -> Scenes.QuickSettings
- is ShadeMode.Dual -> Scenes.QuickSettingsShade
- is ShadeMode.Split -> Scenes.Shade
- }
-
- companion object {
- val quickSettingsScenes =
- setOf(Scenes.QuickSettings, Scenes.QuickSettingsShade, Scenes.Shade)
- }
-}
-
-@Module
-interface QuickSettingsSceneFamilyResolverModule {
- @Binds @IntoSet fun bindResolver(interactor: QuickSettingsSceneFamilyResolver): SceneResolver
-}
diff --git a/packages/SystemUI/src/com/android/systemui/scene/domain/startable/SceneContainerStartable.kt b/packages/SystemUI/src/com/android/systemui/scene/domain/startable/SceneContainerStartable.kt
index c5e0ccc..e11ffcc 100644
--- a/packages/SystemUI/src/com/android/systemui/scene/domain/startable/SceneContainerStartable.kt
+++ b/packages/SystemUI/src/com/android/systemui/scene/domain/startable/SceneContainerStartable.kt
@@ -107,6 +107,7 @@
* Hooks up business logic that manipulates the state of the [SceneInteractor] for the system UI
* scene container based on state from other systems.
*/
+@OptIn(ExperimentalCoroutinesApi::class)
@SysUISingleton
class SceneContainerStartable
@Inject
@@ -408,8 +409,7 @@
}
isOnPrimaryBouncer -> {
// When the device becomes unlocked in primary Bouncer,
- // notify dismiss succeeded and
- // go to previous scene or Gone.
+ // notify dismiss succeeded and go to previous scene or Gone.
dismissCallbackRegistry.notifyDismissSucceeded()
if (
previousScene.value == Scenes.Lockscreen ||
@@ -596,12 +596,12 @@
combine(
sceneInteractor.transitionState
.mapNotNull { it as? ObservableTransitionState.Idle }
- .map { it.currentScene }
.distinctUntilChanged(),
occlusionInteractor.invisibleDueToOcclusion,
- ) { sceneKey, invisibleDueToOcclusion ->
+ ) { idleState, invisibleDueToOcclusion ->
SceneContainerPlugin.SceneContainerPluginState(
- scene = sceneKey,
+ scene = idleState.currentScene,
+ overlays = idleState.currentOverlays,
invisibleDueToOcclusion = invisibleDueToOcclusion,
)
}
diff --git a/packages/SystemUI/src/com/android/systemui/scene/shared/model/Scenes.kt b/packages/SystemUI/src/com/android/systemui/scene/shared/model/Scenes.kt
index 115d664..82b4b1c 100644
--- a/packages/SystemUI/src/com/android/systemui/scene/shared/model/Scenes.kt
+++ b/packages/SystemUI/src/com/android/systemui/scene/shared/model/Scenes.kt
@@ -43,22 +43,6 @@
@JvmField val Lockscreen = SceneKey("lockscreen")
/**
- * The notifications shade scene primarily shows a scrollable list of notifications as an
- * overlay UI.
- *
- * It's used only in the dual shade configuration, where there are two separate shades: one for
- * notifications (this scene) and another for [QuickSettingsShade].
- *
- * It's not used in the single/accordion configuration (swipe down once to reveal the shade,
- * swipe down again the to expand quick settings) or in the "split" shade configuration (on
- * large screens or unfolded foldables, where notifications and quick settings are shown
- * side-by-side in their own columns).
- */
- @Deprecated("The notifications shade scene has been replaced by an overlay")
- @JvmField
- val NotificationsShade = SceneKey("notifications_shade")
-
- /**
* The quick settings scene shows the quick setting tiles.
*
* This scene is used for single/accordion configuration (swipe down once to reveal the shade,
@@ -69,27 +53,12 @@
* scene is used.
*
* For the dual shade configuration, where there are two separate shades: one for notifications
- * and one for quick settings, [NotificationsShade] and [QuickSettingsShade] scenes are used
- * respectively.
+ * and one for quick settings, the overlays `NotificationsShade` and `QuickSettingsShade` are
+ * used respectively.
*/
@JvmField val QuickSettings = SceneKey("quick_settings")
/**
- * The quick settings shade scene shows the quick setting tiles as an overlay UI.
- *
- * It's used only in the dual shade configuration, where there are two separate shades: one for
- * quick settings (this scene) and another for [NotificationsShade].
- *
- * It's not used in the single/accordion configuration (swipe down once to reveal the shade,
- * swipe down again the to expand quick settings) or in the "split" shade configuration (on
- * large screens or unfolded foldables, where notifications and quick settings are shown
- * side-by-side in their own columns).
- */
- @Deprecated("The quick settings shade scene has been replaced by an overlay")
- @JvmField
- val QuickSettingsShade = SceneKey("quick_settings_shade")
-
- /**
* The shade is the scene that shows a scrollable list of notifications and the minimized
* version of quick settings (AKA "quick quick settings" or "QQS").
*
@@ -97,7 +66,8 @@
* swipe down again the to expand quick settings) and for the "split" shade configuration (on
* large screens or unfolded foldables, where notifications and quick settings are shown
* side-by-side in their own columns). For the dual shade configuration, where there are two
- * separate shades: one for notifications and one for quick settings, other scenes are used.
+ * separate shades: one for notifications and one for quick settings, the overlays
+ * `NotificationsShade` and `QuickSettingsShade` are used respectively.
*/
@JvmField val Shade = SceneKey("shade")
}
@@ -114,16 +84,4 @@
* depending on whether the device is unlocked and has been entered.
*/
@JvmField val Home = SceneKey(debugName = "scene_family_home")
-
- /**
- * The scene that contains the full, interactive notification shade. The specific scene it
- * resolves to can depend on dual / split / single shade settings.
- */
- @JvmField val NotifShade = SceneKey(debugName = "scene_family_notif_shade")
-
- /**
- * The scene that contains the full QuickSettings (not to be confused with Quick-QuickSettings).
- * The specific scene it resolves to can depend on dual / split / single shade settings.
- */
- @JvmField val QuickSettings = SceneKey(debugName = "scene_family_quick_settings")
}
diff --git a/packages/SystemUI/src/com/android/systemui/scene/ui/viewmodel/GoneUserActionsViewModel.kt b/packages/SystemUI/src/com/android/systemui/scene/ui/viewmodel/GoneUserActionsViewModel.kt
index 7bf2b63..5ff507a 100644
--- a/packages/SystemUI/src/com/android/systemui/scene/ui/viewmodel/GoneUserActionsViewModel.kt
+++ b/packages/SystemUI/src/com/android/systemui/scene/ui/viewmodel/GoneUserActionsViewModel.kt
@@ -19,7 +19,6 @@
import com.android.compose.animation.scene.Edge
import com.android.compose.animation.scene.Swipe
import com.android.compose.animation.scene.SwipeDirection
-import com.android.compose.animation.scene.TransitionKey
import com.android.compose.animation.scene.UserAction
import com.android.compose.animation.scene.UserActionResult
import com.android.systemui.scene.shared.model.Overlays
@@ -38,21 +37,25 @@
shadeInteractor.shadeMode.collect { shadeMode ->
setActions(
when (shadeMode) {
- ShadeMode.Single -> fullscreenShadeActions()
- ShadeMode.Split -> fullscreenShadeActions(transitionKey = ToSplitShade)
+ ShadeMode.Single -> singleShadeActions()
+ ShadeMode.Split -> splitShadeActions()
ShadeMode.Dual -> dualShadeActions()
}
)
}
}
- private fun fullscreenShadeActions(
- transitionKey: TransitionKey? = null
- ): Map<UserAction, UserActionResult> {
+ private fun singleShadeActions(): Map<UserAction, UserActionResult> {
return mapOf(
- Swipe.Down to UserActionResult(Scenes.Shade, transitionKey),
- Swipe(direction = SwipeDirection.Down, pointerCount = 2, fromSource = Edge.Top) to
- UserActionResult(Scenes.Shade, transitionKey),
+ Swipe.Down to Scenes.Shade,
+ swipeDownFromTopWithTwoFingers() to Scenes.QuickSettings,
+ )
+ }
+
+ private fun splitShadeActions(): Map<UserAction, UserActionResult> {
+ return mapOf(
+ Swipe.Down to UserActionResult(Scenes.Shade, ToSplitShade),
+ swipeDownFromTopWithTwoFingers() to UserActionResult(Scenes.Shade, ToSplitShade),
)
}
@@ -64,6 +67,10 @@
)
}
+ private fun swipeDownFromTopWithTwoFingers(): UserAction {
+ return Swipe(direction = SwipeDirection.Down, pointerCount = 2, fromSource = Edge.Top)
+ }
+
@AssistedFactory
interface Factory {
fun create(): GoneUserActionsViewModel
diff --git a/packages/SystemUI/src/com/android/systemui/settings/MultiUserUtilsModule.java b/packages/SystemUI/src/com/android/systemui/settings/MultiUserUtilsModule.java
index b9f9b92..05f19ef 100644
--- a/packages/SystemUI/src/com/android/systemui/settings/MultiUserUtilsModule.java
+++ b/packages/SystemUI/src/com/android/systemui/settings/MultiUserUtilsModule.java
@@ -16,6 +16,7 @@
package com.android.systemui.settings;
+import android.app.ActivityManager;
import android.app.IActivityManager;
import android.content.Context;
import android.hardware.display.DisplayManager;
@@ -66,7 +67,7 @@
@Background CoroutineDispatcher backgroundDispatcher,
@Background Handler handler
) {
- int startingUser = userManager.getBootUser().getIdentifier();
+ int startingUser = ActivityManager.getCurrentUser();
UserTrackerImpl tracker = new UserTrackerImpl(context, featureFlagsProvider, userManager,
iActivityManager, dumpManager, appScope, backgroundDispatcher, handler);
tracker.initialize(startingUser);
diff --git a/packages/SystemUI/src/com/android/systemui/settings/UserTracker.kt b/packages/SystemUI/src/com/android/systemui/settings/UserTracker.kt
index 1a997a7..e1631cc 100644
--- a/packages/SystemUI/src/com/android/systemui/settings/UserTracker.kt
+++ b/packages/SystemUI/src/com/android/systemui/settings/UserTracker.kt
@@ -16,11 +16,10 @@
package com.android.systemui.settings
-import com.android.systemui.util.annotations.WeaklyReferencedCallback
-
import android.content.Context
import android.content.pm.UserInfo
import android.os.UserHandle
+import com.android.systemui.util.annotations.WeaklyReferencedCallback
import java.util.concurrent.Executor
/**
@@ -31,19 +30,13 @@
*/
interface UserTracker : UserContentResolverProvider, UserContextProvider {
- /**
- * Current user's id.
- */
+ /** Current user's id. */
val userId: Int
- /**
- * [UserHandle] for current user
- */
+ /** [UserHandle] for current user */
val userHandle: UserHandle
- /**
- * [UserInfo] for current user
- */
+ /** [UserInfo] for current user */
val userInfo: UserInfo
/**
@@ -56,39 +49,33 @@
*/
val userProfiles: List<UserInfo>
- /**
- * Add a [Callback] to be notified of chances, on a particular [Executor]
- */
+ /** Is the system in the process of switching users? */
+ val isUserSwitching: Boolean
+
+ /** Add a [Callback] to be notified of chances, on a particular [Executor] */
fun addCallback(callback: Callback, executor: Executor)
- /**
- * Remove a [Callback] previously added.
- */
+ /** Remove a [Callback] previously added. */
fun removeCallback(callback: Callback)
- /**
- * Callback for notifying of changes.
- */
+ /** Callback for notifying of changes. */
@WeaklyReferencedCallback
interface Callback {
- /**
- * Notifies that the current user will be changed.
- */
+ /** Notifies that the current user will be changed. */
fun onBeforeUserSwitching(newUser: Int) {}
/**
- * Same as {@link onUserChanging(Int, Context, Runnable)} but the callback will be
- * called automatically after the completion of this method.
+ * Same as {@link onUserChanging(Int, Context, Runnable)} but the callback will be called
+ * automatically after the completion of this method.
*/
fun onUserChanging(newUser: Int, userContext: Context) {}
/**
- * Notifies that the current user is being changed.
- * Override this method to run things while the screen is frozen for the user switch.
- * Please use {@link #onUserChanged} if the task doesn't need to push the unfreezing of the
- * screen further. Please be aware that code executed in this callback will lengthen the
- * user switch duration. When overriding this method, resultCallback#run() MUST be called
- * once the execution is complete.
+ * Notifies that the current user is being changed. Override this method to run things while
+ * the screen is frozen for the user switch. Please use {@link #onUserChanged} if the task
+ * doesn't need to push the unfreezing of the screen further. Please be aware that code
+ * executed in this callback will lengthen the user switch duration. When overriding this
+ * method, resultCallback#run() MUST be called once the execution is complete.
*/
fun onUserChanging(newUser: Int, userContext: Context, resultCallback: Runnable) {
onUserChanging(newUser, userContext)
@@ -96,15 +83,13 @@
}
/**
- * Notifies that the current user has changed.
- * Override this method to run things after the screen is unfrozen for the user switch.
- * Please see {@link #onUserChanging} if you need to hide jank.
+ * Notifies that the current user has changed. Override this method to run things after the
+ * screen is unfrozen for the user switch. Please see {@link #onUserChanging} if you need to
+ * hide jank.
*/
fun onUserChanged(newUser: Int, userContext: Context) {}
- /**
- * Notifies that the current user's profiles have changed.
- */
+ /** Notifies that the current user's profiles have changed. */
fun onProfilesChanged(profiles: List<@JvmSuppressWildcards UserInfo>) {}
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/settings/UserTrackerImpl.kt b/packages/SystemUI/src/com/android/systemui/settings/UserTrackerImpl.kt
index 553d1f5..1863e12 100644
--- a/packages/SystemUI/src/com/android/systemui/settings/UserTrackerImpl.kt
+++ b/packages/SystemUI/src/com/android/systemui/settings/UserTrackerImpl.kt
@@ -106,6 +106,9 @@
override var userInfo: UserInfo by SynchronizedDelegate(UserInfo(context.userId, "", 0))
protected set
+ override var isUserSwitching = false
+ protected set
+
/**
* Returns a [List<UserInfo>] of all profiles associated with the current user.
*
@@ -197,6 +200,7 @@
}
override fun onUserSwitching(newUserId: Int, reply: IRemoteCallback?) {
+ isUserSwitching = true
if (isBackgroundUserSwitchEnabled) {
userSwitchingJob?.cancel()
userSwitchingJob =
@@ -210,6 +214,7 @@
}
override fun onUserSwitchComplete(newUserId: Int) {
+ isUserSwitching = false
if (isBackgroundUserSwitchEnabled) {
afterUserSwitchingJob?.cancel()
afterUserSwitchingJob =
@@ -221,7 +226,7 @@
}
}
},
- TAG
+ TAG,
)
}
@@ -349,7 +354,7 @@
private data class DataItem(
val callback: WeakReference<UserTracker.Callback>,
- val executor: Executor
+ val executor: Executor,
) {
fun sameOrEmpty(other: UserTracker.Callback): Boolean {
return callback.get()?.equals(other) ?: true
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/TEST_MAPPING b/packages/SystemUI/src/com/android/systemui/statusbar/TEST_MAPPING
index 718c1c0f..3232684 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/TEST_MAPPING
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/TEST_MAPPING
@@ -1,18 +1,7 @@
{
"presubmit": [
{
- "name": "CtsNotificationTestCases",
- "options": [
- {
- "exclude-annotation": "androidx.test.filters.FlakyTest"
- },
- {
- "exclude-annotation": "org.junit.Ignore"
- },
- {
- "exclude-annotation": "androidx.test.filters.LargeTest"
- }
- ]
+ "name": "CtsNotificationTestCases_notification"
}
],
"postsubmit": [
diff --git a/packages/SystemUI/tests/src/com/android/keyguard/KeyguardUpdateMonitorTest.java b/packages/SystemUI/tests/src/com/android/keyguard/KeyguardUpdateMonitorTest.java
index 52fde7e..4005e10 100644
--- a/packages/SystemUI/tests/src/com/android/keyguard/KeyguardUpdateMonitorTest.java
+++ b/packages/SystemUI/tests/src/com/android/keyguard/KeyguardUpdateMonitorTest.java
@@ -494,7 +494,7 @@
@Test
public void testIgnoresSimStateCallback_rebroadcast() {
- Intent intent = new Intent(TelephonyIntents.ACTION_SIM_STATE_CHANGED);
+ Intent intent = defaultSimStateChangedIntent();
mKeyguardUpdateMonitor.mBroadcastReceiver.onReceive(getContext(), intent);
mTestableLooper.processAllMessages();
@@ -515,7 +515,8 @@
@Test
public void testTelephonyCapable_SimState_Absent() {
- Intent intent = new Intent(TelephonyIntents.ACTION_SIM_STATE_CHANGED);
+
+ Intent intent = defaultSimStateChangedIntent();
intent.putExtra(Intent.EXTRA_SIM_STATE,
Intent.SIM_STATE_ABSENT);
mKeyguardUpdateMonitor.mBroadcastReceiver.onReceive(getContext(),
@@ -526,7 +527,7 @@
@Test
public void testTelephonyCapable_SimState_CardIOError() {
- Intent intent = new Intent(TelephonyIntents.ACTION_SIM_STATE_CHANGED);
+ Intent intent = defaultSimStateChangedIntent();
intent.putExtra(Intent.EXTRA_SIM_STATE,
Intent.SIM_STATE_CARD_IO_ERROR);
mKeyguardUpdateMonitor.mBroadcastReceiver.onReceive(getContext(),
@@ -593,7 +594,7 @@
ServiceState state = new ServiceState();
state.setState(ServiceState.STATE_OUT_OF_SERVICE);
state.fillInNotifierBundle(data);
- Intent intent = new Intent(TelephonyIntents.ACTION_SIM_STATE_CHANGED);
+ Intent intent = defaultSimStateChangedIntent();
intent.putExtra(Intent.EXTRA_SIM_STATE
, Intent.SIM_STATE_NOT_READY);
mKeyguardUpdateMonitor.mBroadcastReceiver.onReceive(getContext()
@@ -608,7 +609,7 @@
ServiceState state = new ServiceState();
state.setState(ServiceState.STATE_OUT_OF_SERVICE);
state.fillInNotifierBundle(data);
- Intent intent = new Intent(TelephonyIntents.ACTION_SIM_STATE_CHANGED);
+ Intent intent = defaultSimStateChangedIntent();
intent.putExtra(Intent.EXTRA_SIM_STATE
, Intent.SIM_STATE_READY);
mKeyguardUpdateMonitor.mBroadcastReceiver.onReceive(getContext()
@@ -649,7 +650,7 @@
ServiceState state = new ServiceState();
state.setState(ServiceState.STATE_IN_SERVICE);
state.fillInNotifierBundle(data);
- Intent intentSimState = new Intent(TelephonyIntents.ACTION_SIM_STATE_CHANGED);
+ Intent intentSimState = defaultSimStateChangedIntent();
intentSimState.putExtra(Intent.EXTRA_SIM_STATE
, Intent.SIM_STATE_LOADED);
mKeyguardUpdateMonitor.mBroadcastReceiver.onReceive(getContext()
@@ -2256,6 +2257,12 @@
Assert.assertFalse(mKeyguardUpdateMonitor.forceIsDismissibleIsKeepingDeviceUnlocked());
}
+ private Intent defaultSimStateChangedIntent() {
+ Intent intent = new Intent(TelephonyIntents.ACTION_SIM_STATE_CHANGED);
+ intent.putExtra(SubscriptionManager.EXTRA_SLOT_INDEX, 0);
+ return intent;
+ }
+
private void verifyFingerprintAuthenticateNeverCalled() {
verify(mFingerprintManager, never()).authenticate(any(), any(), any(), any(), any());
verify(mFingerprintManager, never()).authenticate(any(), any(), any(), any(), anyInt(),
diff --git a/packages/SystemUI/tests/src/com/android/systemui/keyguard/KeyguardViewMediatorTest.java b/packages/SystemUI/tests/src/com/android/systemui/keyguard/KeyguardViewMediatorTest.java
index 597ffef..9e0d358 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/keyguard/KeyguardViewMediatorTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/keyguard/KeyguardViewMediatorTest.java
@@ -26,6 +26,7 @@
import static com.android.internal.widget.LockPatternUtils.StrongAuthTracker.STRONG_AUTH_REQUIRED_AFTER_NON_STRONG_BIOMETRICS_TIMEOUT;
import static com.android.internal.widget.LockPatternUtils.StrongAuthTracker.STRONG_AUTH_REQUIRED_AFTER_USER_LOCKDOWN;
import static com.android.systemui.Flags.FLAG_KEYGUARD_WM_STATE_REFACTOR;
+import static com.android.systemui.Flags.FLAG_SIM_PIN_BOUNCER_RESET;
import static com.android.systemui.keyguard.KeyguardViewMediator.DELAYED_KEYGUARD_ACTION;
import static com.android.systemui.keyguard.KeyguardViewMediator.KEYGUARD_LOCK_AFTER_DELAY_DEFAULT;
import static com.android.systemui.keyguard.KeyguardViewMediator.REBOOT_MAINLINE_UPDATE;
@@ -62,6 +63,7 @@
import android.os.PowerManager;
import android.os.PowerManager.WakeLock;
import android.os.RemoteException;
+import android.platform.test.annotations.EnableFlags;
import android.telephony.TelephonyManager;
import android.testing.AndroidTestingRunner;
import android.testing.TestableLooper;
@@ -588,6 +590,35 @@
@Test
@TestableLooper.RunWithLooper(setAsMainLooper = true)
+ @EnableFlags(FLAG_SIM_PIN_BOUNCER_RESET)
+ public void resetStateLocked_whenSimNotReadyAndWasLockedPrior() {
+ // When showing and provisioned
+ mViewMediator.onSystemReady();
+ when(mUpdateMonitor.isDeviceProvisioned()).thenReturn(true);
+ mViewMediator.setShowingLocked(true, "");
+
+ // and a SIM becomes locked and requires a PIN
+ mViewMediator.mUpdateCallback.onSimStateChanged(
+ 1 /* subId */,
+ 0 /* slotId */,
+ TelephonyManager.SIM_STATE_PIN_REQUIRED);
+ TestableLooper.get(this).processAllMessages();
+
+ reset(mStatusBarKeyguardViewManager);
+
+ // but then disabled by a NOT_READY
+ mViewMediator.mUpdateCallback.onSimStateChanged(
+ 1 /* subId */,
+ 0 /* slotId */,
+ TelephonyManager.SIM_STATE_NOT_READY);
+ TestableLooper.get(this).processAllMessages();
+
+ // A call to reset the keyguard and bouncer was invoked
+ verify(mStatusBarKeyguardViewManager).reset(true);
+ }
+
+ @Test
+ @TestableLooper.RunWithLooper(setAsMainLooper = true)
public void restoreBouncerWhenSimLockedAndKeyguardIsGoingAway_initiallyNotShowing() {
// When showing and provisioned
mViewMediator.onSystemReady();
diff --git a/packages/SystemUI/tests/src/com/android/systemui/settings/UserTrackerImplTest.kt b/packages/SystemUI/tests/src/com/android/systemui/settings/UserTrackerImplTest.kt
index 2e2ac3e..a0ecb80 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/settings/UserTrackerImplTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/settings/UserTrackerImplTest.kt
@@ -231,7 +231,7 @@
"",
"",
UserInfo.FLAG_MANAGED_PROFILE,
- UserManager.USER_TYPE_PROFILE_MANAGED
+ UserManager.USER_TYPE_PROFILE_MANAGED,
)
infoProfile.profileGroupId = id
listOf(info, infoProfile)
@@ -261,7 +261,7 @@
"",
"",
UserInfo.FLAG_MANAGED_PROFILE or UserInfo.FLAG_QUIET_MODE,
- UserManager.USER_TYPE_PROFILE_MANAGED
+ UserManager.USER_TYPE_PROFILE_MANAGED,
)
infoProfile.profileGroupId = id
listOf(info, infoProfile)
@@ -291,7 +291,7 @@
"",
"",
UserInfo.FLAG_MANAGED_PROFILE,
- UserManager.USER_TYPE_PROFILE_MANAGED
+ UserManager.USER_TYPE_PROFILE_MANAGED,
)
infoProfile.profileGroupId = id
listOf(info, infoProfile)
@@ -423,7 +423,7 @@
"",
"",
UserInfo.FLAG_MANAGED_PROFILE,
- UserManager.USER_TYPE_PROFILE_MANAGED
+ UserManager.USER_TYPE_PROFILE_MANAGED,
)
infoProfile.profileGroupId = id
listOf(info, infoProfile)
@@ -469,6 +469,24 @@
assertThat(callback.calledOnProfilesChanged).isEqualTo(0)
}
+ @Test
+ fun testisUserSwitching() =
+ testScope.runTest {
+ tracker.initialize(0)
+ val newID = 5
+ val profileID = newID + 10
+
+ val captor = ArgumentCaptor.forClass(IUserSwitchObserver::class.java)
+ verify(iActivityManager).registerUserSwitchObserver(capture(captor), anyString())
+ assertThat(tracker.isUserSwitching).isFalse()
+
+ captor.value.onUserSwitching(newID, userSwitchingReply)
+ assertThat(tracker.isUserSwitching).isTrue()
+
+ captor.value.onUserSwitchComplete(newID)
+ assertThat(tracker.isUserSwitching).isFalse()
+ }
+
private class TestCallback : UserTracker.Callback {
var calledOnUserChanging = 0
var calledOnUserChanged = 0
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/domain/interactor/KeyguardDismissActionInteractorKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/domain/interactor/KeyguardDismissActionInteractorKosmos.kt
index d920c4f..574bbcd 100644
--- a/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/domain/interactor/KeyguardDismissActionInteractorKosmos.kt
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/domain/interactor/KeyguardDismissActionInteractorKosmos.kt
@@ -17,14 +17,12 @@
package com.android.systemui.keyguard.domain.interactor
import com.android.systemui.bouncer.domain.interactor.alternateBouncerInteractor
-import com.android.systemui.deviceentry.domain.interactor.deviceEntryInteractor
+import com.android.systemui.deviceentry.domain.interactor.deviceUnlockedInteractor
import com.android.systemui.keyguard.data.repository.keyguardRepository
import com.android.systemui.kosmos.Kosmos
import com.android.systemui.kosmos.testScope
import com.android.systemui.power.domain.interactor.powerInteractor
import com.android.systemui.scene.domain.interactor.sceneInteractor
-import com.android.systemui.scene.domain.resolver.notifShadeSceneFamilyResolver
-import com.android.systemui.scene.domain.resolver.quickSettingsSceneFamilyResolver
import com.android.systemui.shade.domain.interactor.shadeInteractor
import kotlinx.coroutines.ExperimentalCoroutinesApi
@@ -37,12 +35,9 @@
dismissInteractor = keyguardDismissInteractor,
applicationScope = testScope.backgroundScope,
sceneInteractor = { sceneInteractor },
- deviceEntryInteractor = { deviceEntryInteractor },
- quickSettingsSceneFamilyResolver = { quickSettingsSceneFamilyResolver },
- notifShadeSceneFamilyResolver = { notifShadeSceneFamilyResolver },
+ deviceUnlockedInteractor = { deviceUnlockedInteractor },
powerInteractor = powerInteractor,
alternateBouncerInteractor = alternateBouncerInteractor,
- keyguardInteractor = { keyguardInteractor },
shadeInteractor = { shadeInteractor },
)
}
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/scene/domain/resolver/SceneResolverKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/scene/domain/resolver/SceneResolverKosmos.kt
index d17b575..8b12425 100644
--- a/packages/SystemUI/tests/utils/src/com/android/systemui/scene/domain/resolver/SceneResolverKosmos.kt
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/scene/domain/resolver/SceneResolverKosmos.kt
@@ -24,16 +24,10 @@
import com.android.systemui.kosmos.Kosmos
import com.android.systemui.kosmos.applicationCoroutineScope
import com.android.systemui.scene.shared.model.SceneFamilies
-import com.android.systemui.shade.domain.interactor.shadeModeInteractor
import kotlinx.coroutines.ExperimentalCoroutinesApi
val Kosmos.sceneFamilyResolvers: Map<SceneKey, SceneResolver>
- get() =
- mapOf(
- SceneFamilies.Home to homeSceneFamilyResolver,
- SceneFamilies.NotifShade to notifShadeSceneFamilyResolver,
- SceneFamilies.QuickSettings to quickSettingsSceneFamilyResolver,
- )
+ get() = mapOf(SceneFamilies.Home to homeSceneFamilyResolver)
val Kosmos.homeSceneFamilyResolver by
Kosmos.Fixture {
@@ -43,19 +37,3 @@
keyguardEnabledInteractor = keyguardEnabledInteractor,
)
}
-
-val Kosmos.notifShadeSceneFamilyResolver by
- Kosmos.Fixture {
- NotifShadeSceneFamilyResolver(
- applicationScope = applicationCoroutineScope,
- shadeModeInteractor = shadeModeInteractor,
- )
- }
-
-val Kosmos.quickSettingsSceneFamilyResolver by
- Kosmos.Fixture {
- QuickSettingsSceneFamilyResolver(
- applicationScope = applicationCoroutineScope,
- shadeModeInteractor = shadeModeInteractor,
- )
- }
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/settings/FakeUserTracker.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/settings/FakeUserTracker.kt
index f3d5b7d..cd76a74 100644
--- a/packages/SystemUI/tests/utils/src/com/android/systemui/settings/FakeUserTracker.kt
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/settings/FakeUserTracker.kt
@@ -33,6 +33,7 @@
private var _userHandle: UserHandle = UserHandle.of(_userId),
private var _userInfo: UserInfo = mock(),
private var _userProfiles: List<UserInfo> = emptyList(),
+ private var _isUserSwitching: Boolean = false,
userContentResolverProvider: () -> ContentResolver = { MockContentResolver() },
userContext: Context = mock(),
private val onCreateCurrentUserContext: (Context) -> Context = { mock() },
@@ -51,6 +52,9 @@
override val userProfiles: List<UserInfo>
get() = _userProfiles
+ override val isUserSwitching: Boolean
+ get() = _isUserSwitching
+
// userContentResolver is lazy because Ravenwood doesn't support MockContentResolver()
// and we still want to allow people use this class for tests that don't use it.
override val userContentResolver: ContentResolver by lazy { userContentResolverProvider() }
@@ -86,11 +90,13 @@
}
fun onUserChanging(userId: Int = _userId) {
+ _isUserSwitching = true
val copy = callbacks.toList()
copy.forEach { it.onUserChanging(userId, userContext) {} }
}
fun onUserChanged(userId: Int = _userId) {
+ _isUserSwitching = false
val copy = callbacks.toList()
copy.forEach { it.onUserChanged(userId, userContext) }
}
diff --git a/packages/services/CameraExtensionsProxy/src/com/android/cameraextensions/CameraExtensionsProxyService.java b/packages/services/CameraExtensionsProxy/src/com/android/cameraextensions/CameraExtensionsProxyService.java
index 136738f..acb74d3 100644
--- a/packages/services/CameraExtensionsProxy/src/com/android/cameraextensions/CameraExtensionsProxyService.java
+++ b/packages/services/CameraExtensionsProxy/src/com/android/cameraextensions/CameraExtensionsProxyService.java
@@ -1620,7 +1620,7 @@
}
ret.outputConfigs.add(entry);
}
- if (Flags.extension10Bit() && EFV_SUPPORTED) {
+ if (EFV_SUPPORTED) {
ret.colorSpace = sessionConfig.getColorSpace();
} else {
ret.colorSpace = ColorSpaceProfiles.UNSPECIFIED;
@@ -2596,7 +2596,7 @@
private static CameraOutputConfig getCameraOutputConfig(Camera2OutputConfigImpl output) {
CameraOutputConfig ret = new CameraOutputConfig();
- if (Flags.extension10Bit() && EFV_SUPPORTED) {
+ if (EFV_SUPPORTED) {
ret.dynamicRangeProfile = output.getDynamicRangeProfile();
} else {
ret.dynamicRangeProfile = DynamicRangeProfiles.STANDARD;
diff --git a/ravenwood/Android.bp b/ravenwood/Android.bp
index d0ea474..d1a3bf9 100644
--- a/ravenwood/Android.bp
+++ b/ravenwood/Android.bp
@@ -341,8 +341,8 @@
android_ravenwood_libgroup {
name: "ravenwood-runtime",
data: [
- "framework-res",
- "ravenwood-empty-res",
+ ":framework-res",
+ ":ravenwood-empty-res",
],
libs: [
"100-framework-minus-apex.ravenwood",
diff --git a/ravenwood/TEST_MAPPING b/ravenwood/TEST_MAPPING
index 7f9d9c2..3583b96 100644
--- a/ravenwood/TEST_MAPPING
+++ b/ravenwood/TEST_MAPPING
@@ -7,30 +7,17 @@
{ "name": "RavenwoodMockitoTest_device" },
{ "name": "RavenwoodBivalentTest_device" },
+ { "name": "RavenwoodBivalentInstTest_nonself_inst" },
+ { "name": "RavenwoodBivalentInstTest_self_inst_device" },
+
// The sysui tests should match vendor/unbundled_google/packages/SystemUIGoogle/TEST_MAPPING
{
- "name": "SystemUIGoogleTests",
- "options": [
- {
- "exclude-annotation": "org.junit.Ignore"
- },
- {
- "exclude-annotation": "androidx.test.filters.FlakyTest"
- }
- ]
+ "name": "SystemUIGoogleTests"
}
],
"presubmit-large": [
{
- "name": "SystemUITests",
- "options": [
- {
- "exclude-annotation": "androidx.test.filters.FlakyTest"
- },
- {
- "exclude-annotation": "org.junit.Ignore"
- }
- ]
+ "name": "SystemUITests"
}
],
"ravenwood-presubmit": [
@@ -138,6 +125,14 @@
"host": true
},
{
+ "name": "RavenwoodBivalentInstTest_nonself_inst",
+ "host": true
+ },
+ {
+ "name": "RavenwoodBivalentInstTest_self_inst",
+ "host": true
+ },
+ {
"name": "RavenwoodBivalentTest",
"host": true
},
diff --git a/ravenwood/junit-impl-src/android/platform/test/ravenwood/RavenwoodAwareTestRunnerHook.java b/ravenwood/junit-impl-src/android/platform/test/ravenwood/RavenwoodAwareTestRunnerHook.java
index 68472c1..7a6f9e3 100644
--- a/ravenwood/junit-impl-src/android/platform/test/ravenwood/RavenwoodAwareTestRunnerHook.java
+++ b/ravenwood/junit-impl-src/android/platform/test/ravenwood/RavenwoodAwareTestRunnerHook.java
@@ -108,7 +108,7 @@
Log.v(TAG, "onBeforeInnerRunnerStart: description=" + description);
// Prepare the environment before the inner runner starts.
- RavenwoodRunnerState.forRunner(runner).enterTestClass(description);
+ runner.mState.enterTestClass(description);
}
/**
@@ -119,7 +119,7 @@
Log.v(TAG, "onAfterInnerRunnerFinished: description=" + description);
RavenwoodTestStats.getInstance().onClassFinished(description);
- RavenwoodRunnerState.forRunner(runner).exitTestClass();
+ runner.mState.exitTestClass();
}
/**
@@ -133,10 +133,10 @@
if (scope == Scope.Instance && order == Order.Outer) {
// Start of a test method.
- RavenwoodRunnerState.forRunner(runner).enterTestMethod(description);
+ runner.mState.enterTestMethod(description);
}
- final var classDescription = RavenwoodRunnerState.forRunner(runner).getClassDescription();
+ final var classDescription = runner.mState.getClassDescription();
// Class-level annotations are checked by the runner already, so we only check
// method-level annotations here.
@@ -160,11 +160,11 @@
Scope scope, Order order, Throwable th) {
Log.v(TAG, "onAfter: description=" + description + ", " + scope + ", " + order + ", " + th);
- final var classDescription = RavenwoodRunnerState.forRunner(runner).getClassDescription();
+ final var classDescription = runner.mState.getClassDescription();
if (scope == Scope.Instance && order == Order.Outer) {
// End of a test method.
- RavenwoodRunnerState.forRunner(runner).exitTestMethod();
+ runner.mState.exitTestMethod();
RavenwoodTestStats.getInstance().onTestFinished(classDescription, description,
th == null ? Result.Passed : Result.Failed);
}
@@ -214,7 +214,7 @@
Description description, RavenwoodRule rule) throws Throwable {
Log.v(TAG, "onRavenwoodRuleEnter: description=" + description);
- RavenwoodRunnerState.forRunner(runner).enterRavenwoodRule(rule);
+ runner.mState.enterRavenwoodRule(rule);
}
@@ -225,6 +225,6 @@
Description description, RavenwoodRule rule) throws Throwable {
Log.v(TAG, "onRavenwoodRuleExit: description=" + description);
- RavenwoodRunnerState.forRunner(runner).exitRavenwoodRule(rule);
+ runner.mState.exitRavenwoodRule(rule);
}
}
\ No newline at end of file
diff --git a/ravenwood/junit-impl-src/android/platform/test/ravenwood/RavenwoodConfigState.java b/ravenwood/junit-impl-src/android/platform/test/ravenwood/RavenwoodConfigState.java
new file mode 100644
index 0000000..3535cb2
--- /dev/null
+++ b/ravenwood/junit-impl-src/android/platform/test/ravenwood/RavenwoodConfigState.java
@@ -0,0 +1,81 @@
+/*
+ * 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.platform.test.ravenwood;
+
+import static com.android.ravenwood.common.RavenwoodCommonUtils.RAVENWOOD_EMPTY_RESOURCES_APK;
+
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertTrue;
+
+import android.annotation.Nullable;
+import android.app.ResourcesManager;
+import android.content.res.Resources;
+import android.view.DisplayAdjustments;
+
+import java.io.File;
+import java.util.HashMap;
+
+/**
+ * Used to store various states associated with {@link RavenwoodConfig} that's inly needed
+ * in junit-impl.
+ *
+ * We don't want to put it in junit-src to avoid having to recompile all the downstream
+ * dependencies after changing this class.
+ *
+ * All members must be called from the runner's main thread.
+ */
+public class RavenwoodConfigState {
+ private static final String TAG = "RavenwoodConfigState";
+
+ private final RavenwoodConfig mConfig;
+
+ public RavenwoodConfigState(RavenwoodConfig config) {
+ mConfig = config;
+ }
+
+ /** Map from path -> resources. */
+ private final HashMap<File, Resources> mCachedResources = new HashMap<>();
+
+ /**
+ * Load {@link Resources} from an APK, with cache.
+ */
+ public Resources loadResources(@Nullable File apkPath) {
+ var cached = mCachedResources.get(apkPath);
+ if (cached != null) {
+ return cached;
+ }
+
+ var fileToLoad = apkPath != null ? apkPath : new File(RAVENWOOD_EMPTY_RESOURCES_APK);
+
+ assertTrue("File " + fileToLoad + " doesn't exist.", fileToLoad.isFile());
+
+ final String path = fileToLoad.getAbsolutePath();
+ final var emptyPaths = new String[0];
+
+ ResourcesManager.getInstance().initializeApplicationPaths(path, emptyPaths);
+
+ final var ret = ResourcesManager.getInstance().getResources(null, path,
+ emptyPaths, emptyPaths, emptyPaths,
+ emptyPaths, null, null,
+ new DisplayAdjustments().getCompatibilityInfo(),
+ RavenwoodRuntimeEnvironmentController.class.getClassLoader(), null);
+
+ assertNotNull(ret);
+
+ mCachedResources.put(apkPath, ret);
+ return ret;
+ }
+}
diff --git a/ravenwood/junit-impl-src/android/platform/test/ravenwood/RavenwoodContext.java b/ravenwood/junit-impl-src/android/platform/test/ravenwood/RavenwoodContext.java
index 48bed79..239c806 100644
--- a/ravenwood/junit-impl-src/android/platform/test/ravenwood/RavenwoodContext.java
+++ b/ravenwood/junit-impl-src/android/platform/test/ravenwood/RavenwoodContext.java
@@ -60,6 +60,8 @@
private final File mCacheDir;
private final Supplier<Resources> mResourcesSupplier;
+ private RavenwoodContext mAppContext;
+
@GuardedBy("mLock")
private Resources mResources;
@@ -77,8 +79,8 @@
mPackageName = packageName;
mMainThread = mainThread;
mResourcesSupplier = resourcesSupplier;
- mFilesDir = createTempDir("files-dir");
- mCacheDir = createTempDir("cache-dir");
+ mFilesDir = createTempDir(packageName + "_files-dir");
+ mCacheDir = createTempDir(packageName + "_cache-dir");
// Services provided by a typical shipping device
registerService(ClipboardManager.class,
@@ -131,34 +133,35 @@
@Override
public Looper getMainLooper() {
Objects.requireNonNull(mMainThread,
- "Test must request setProvideMainThread() via RavenwoodRule");
+ "Test must request setProvideMainThread() via RavenwoodConfig");
return mMainThread.getLooper();
}
@Override
public Handler getMainThreadHandler() {
Objects.requireNonNull(mMainThread,
- "Test must request setProvideMainThread() via RavenwoodRule");
+ "Test must request setProvideMainThread() via RavenwoodConfig");
return mMainThread.getThreadHandler();
}
@Override
public Executor getMainExecutor() {
Objects.requireNonNull(mMainThread,
- "Test must request setProvideMainThread() via RavenwoodRule");
+ "Test must request setProvideMainThread() via RavenwoodConfig");
return mMainThread.getThreadExecutor();
}
@Override
public String getPackageName() {
return Objects.requireNonNull(mPackageName,
- "Test must request setPackageName() via RavenwoodRule");
+ "Test must request setPackageName() (or setTargetPackageName())"
+ + " via RavenwoodConfig");
}
@Override
public String getOpPackageName() {
return Objects.requireNonNull(mPackageName,
- "Test must request setPackageName() via RavenwoodRule");
+ "Test must request setPackageName() via RavenwoodConfig");
}
@Override
@@ -227,6 +230,15 @@
return new File(RAVENWOOD_RESOURCE_APK).getAbsolutePath();
}
+ public void setApplicationContext(RavenwoodContext appContext) {
+ mAppContext = appContext;
+ }
+
+ @Override
+ public Context getApplicationContext() {
+ return mAppContext;
+ }
+
/**
* Wrap the given {@link Supplier} to become memoized.
*
diff --git a/ravenwood/junit-impl-src/android/platform/test/ravenwood/RavenwoodRunnerState.java b/ravenwood/junit-impl-src/android/platform/test/ravenwood/RavenwoodRunnerState.java
index d73afd4..04b67c4 100644
--- a/ravenwood/junit-impl-src/android/platform/test/ravenwood/RavenwoodRunnerState.java
+++ b/ravenwood/junit-impl-src/android/platform/test/ravenwood/RavenwoodRunnerState.java
@@ -19,7 +19,6 @@
import static org.junit.Assert.fail;
-import android.annotation.NonNull;
import android.annotation.Nullable;
import com.android.internal.annotations.GuardedBy;
@@ -35,12 +34,11 @@
import java.util.WeakHashMap;
/**
- * Used to store various states associated with the current test runner.
+ * Used to store various states associated with the current test runner that's inly needed
+ * in junit-impl.
*
- * This class could be added to {@link RavenwoodAwareTestRunner} as a field, but we don't
- * want to put it in junit-src/ (for one, that'll cause all the downstream dependencies to be
- * rebuilt when this file is updated), so we manage it separately using a Map from each
- * {@link RavenwoodAwareTestRunner} instance to a {@link RavenwoodRunnerState}.
+ * We don't want to put it in junit-src to avoid having to recompile all the downstream
+ * dependencies after changing this class.
*
* All members must be called from the runner's main thread.
*/
@@ -51,23 +49,12 @@
private static final WeakHashMap<RavenwoodAwareTestRunner, RavenwoodRunnerState> sStates =
new WeakHashMap<>();
- /**
- * Get the instance for a given runner.
- */
- public static RavenwoodRunnerState forRunner(@NonNull RavenwoodAwareTestRunner runner) {
- synchronized (sStates) {
- var ret = sStates.get(runner);
- if (ret == null) {
- ret = new RavenwoodRunnerState(runner);
- sStates.put(runner, ret);
- }
- return ret;
- }
- }
-
private final RavenwoodAwareTestRunner mRunner;
- private RavenwoodRunnerState(RavenwoodAwareTestRunner runner) {
+ /**
+ * Ctor.
+ */
+ public RavenwoodRunnerState(RavenwoodAwareTestRunner runner) {
mRunner = runner;
}
diff --git a/ravenwood/junit-impl-src/android/platform/test/ravenwood/RavenwoodRuntimeEnvironmentController.java b/ravenwood/junit-impl-src/android/platform/test/ravenwood/RavenwoodRuntimeEnvironmentController.java
index 03c9001..f4756c5 100644
--- a/ravenwood/junit-impl-src/android/platform/test/ravenwood/RavenwoodRuntimeEnvironmentController.java
+++ b/ravenwood/junit-impl-src/android/platform/test/ravenwood/RavenwoodRuntimeEnvironmentController.java
@@ -16,12 +16,10 @@
package android.platform.test.ravenwood;
-import static com.android.ravenwood.common.RavenwoodCommonUtils.RAVENWOOD_EMPTY_RESOURCES_APK;
import static com.android.ravenwood.common.RavenwoodCommonUtils.RAVENWOOD_RESOURCE_APK;
import static com.android.ravenwood.common.RavenwoodCommonUtils.RAVENWOOD_VERBOSE_LOGGING;
-import static org.junit.Assert.assertNotNull;
-import static org.junit.Assert.assertTrue;
+import static org.junit.Assert.fail;
import android.app.ActivityManager;
import android.app.Instrumentation;
@@ -34,7 +32,6 @@
import android.os.Looper;
import android.os.ServiceManager;
import android.util.Log;
-import android.view.DisplayAdjustments;
import androidx.test.platform.app.InstrumentationRegistry;
@@ -163,31 +160,52 @@
main = null;
}
- // TODO This should be integrated into LoadedApk
- final Supplier<Resources> resourcesSupplier = () -> {
- var resApkFile = new File(RAVENWOOD_RESOURCE_APK);
- if (!resApkFile.isFile()) {
- resApkFile = new File(RAVENWOOD_EMPTY_RESOURCES_APK);
- }
- assertTrue(resApkFile.isFile());
- final String res = resApkFile.getAbsolutePath();
- final var emptyPaths = new String[0];
+ final boolean isSelfInstrumenting =
+ Objects.equals(config.mTestPackageName, config.mTargetPackageName);
- ResourcesManager.getInstance().initializeApplicationPaths(res, emptyPaths);
-
- final var ret = ResourcesManager.getInstance().getResources(null, res,
- emptyPaths, emptyPaths, emptyPaths,
- emptyPaths, null, null,
- new DisplayAdjustments().getCompatibilityInfo(),
- RavenwoodRuntimeEnvironmentController.class.getClassLoader(), null);
-
- assertNotNull(ret);
- return ret;
+ // This will load the resources from the apk set to `resource_apk` in the build file.
+ // This is supposed to be the "target app"'s resources.
+ final Supplier<Resources> targetResourcesLoader = () -> {
+ var file = new File(RAVENWOOD_RESOURCE_APK);
+ return config.mState.loadResources(file.exists() ? file : null);
};
+ // Set up test context's resources.
+ // If the target package name == test package name, then we use the main resources.
+ // Otherwise, we don't simulate loading resources from the test APK yet.
+ // (we need to add `test_resource_apk` to `android_ravenwood_test`)
+ final Supplier<Resources> testResourcesLoader;
+ if (isSelfInstrumenting) {
+ testResourcesLoader = targetResourcesLoader;
+ } else {
+ testResourcesLoader = () -> {
+ fail("Cannot load resources from the test context (yet)."
+ + " Use target context's resources instead.");
+ return null; // unreachable.
+ };
+ }
- config.mContext = new RavenwoodContext(config.mPackageName, main, resourcesSupplier);
+ var testContext = new RavenwoodContext(
+ config.mTestPackageName, main, testResourcesLoader);
+ var targetContext = new RavenwoodContext(
+ config.mTargetPackageName, main, targetResourcesLoader);
+
+ // Set up app context.
+ var appContext = new RavenwoodContext(
+ config.mTargetPackageName, main, targetResourcesLoader);
+ appContext.setApplicationContext(appContext);
+ if (isSelfInstrumenting) {
+ testContext.setApplicationContext(appContext);
+ targetContext.setApplicationContext(appContext);
+ } else {
+ // When instrumenting into another APK, the test context doesn't have an app context.
+ targetContext.setApplicationContext(appContext);
+ }
+ config.mTestContext = testContext;
+ config.mTargetContext = targetContext;
+
+ // Prepare other fields.
config.mInstrumentation = new Instrumentation();
- config.mInstrumentation.basicInit(config.mContext);
+ config.mInstrumentation.basicInit(config.mTestContext, config.mTargetContext);
InstrumentationRegistry.registerInstance(config.mInstrumentation, Bundle.EMPTY);
RavenwoodSystemServer.init(config);
@@ -224,10 +242,14 @@
InstrumentationRegistry.registerInstance(null, Bundle.EMPTY);
config.mInstrumentation = null;
- if (config.mContext != null) {
- ((RavenwoodContext) config.mContext).cleanUp();
+ if (config.mTestContext != null) {
+ ((RavenwoodContext) config.mTestContext).cleanUp();
}
- config.mContext = null;
+ if (config.mTargetContext != null) {
+ ((RavenwoodContext) config.mTargetContext).cleanUp();
+ }
+ config.mTestContext = null;
+ config.mTargetContext = null;
if (config.mProvideMainThread) {
Looper.getMainLooper().quit();
@@ -240,7 +262,9 @@
ServiceManager.reset$ravenwood();
setSystemProperties(RavenwoodSystemProperties.DEFAULT_VALUES);
- Binder.restoreCallingIdentity(sOriginalIdentityToken);
+ if (sOriginalIdentityToken != -1) {
+ Binder.restoreCallingIdentity(sOriginalIdentityToken);
+ }
android.os.Process.reset$ravenwood();
ResourcesManager.setInstance(null); // Better structure needed.
diff --git a/ravenwood/junit-impl-src/android/platform/test/ravenwood/RavenwoodSystemServer.java b/ravenwood/junit-impl-src/android/platform/test/ravenwood/RavenwoodSystemServer.java
index f3a93c1..d4090e2 100644
--- a/ravenwood/junit-impl-src/android/platform/test/ravenwood/RavenwoodSystemServer.java
+++ b/ravenwood/junit-impl-src/android/platform/test/ravenwood/RavenwoodSystemServer.java
@@ -67,7 +67,7 @@
sStartedServices = new ArraySet<>();
sTimings = new TimingsTraceAndSlog();
- sServiceManager = new SystemServiceManager(config.mContext);
+ sServiceManager = new SystemServiceManager(config.mTestContext);
sServiceManager.setStartInfo(false,
SystemClock.elapsedRealtime(),
SystemClock.uptimeMillis());
diff --git a/ravenwood/junit-src/android/platform/test/ravenwood/RavenwoodAwareTestRunner.java b/ravenwood/junit-src/android/platform/test/ravenwood/RavenwoodAwareTestRunner.java
index bc944d7..cb8af0c 100644
--- a/ravenwood/junit-src/android/platform/test/ravenwood/RavenwoodAwareTestRunner.java
+++ b/ravenwood/junit-src/android/platform/test/ravenwood/RavenwoodAwareTestRunner.java
@@ -171,6 +171,12 @@
private Description mDescription = null;
private Throwable mExceptionInConstructor = null;
+ /**
+ * Stores internal states / methods associated with this runner that's only needed in
+ * junit-impl.
+ */
+ final RavenwoodRunnerState mState = new RavenwoodRunnerState(this);
+
private Error logAndFail(String message, Throwable exception) {
Log.e(TAG, message, exception);
throw new AssertionError(message, exception);
diff --git a/ravenwood/junit-src/android/platform/test/ravenwood/RavenwoodConfig.java b/ravenwood/junit-src/android/platform/test/ravenwood/RavenwoodConfig.java
index 04e0bed..ea33aa6 100644
--- a/ravenwood/junit-src/android/platform/test/ravenwood/RavenwoodConfig.java
+++ b/ravenwood/junit-src/android/platform/test/ravenwood/RavenwoodConfig.java
@@ -63,7 +63,10 @@
int mUid = NOBODY_UID;
int mPid = sNextPid.getAndIncrement();
- String mPackageName;
+ String mTestPackageName;
+ String mTargetPackageName;
+
+ int mMinSdkLevel;
boolean mProvideMainThread = false;
@@ -71,9 +74,15 @@
final List<Class<?>> mServicesRequired = new ArrayList<>();
- volatile Context mContext;
+ volatile Context mTestContext;
+ volatile Context mTargetContext;
volatile Instrumentation mInstrumentation;
+ /**
+ * Stores internal states / methods associated with this config that's only needed in
+ * junit-impl.
+ */
+ final RavenwoodConfigState mState = new RavenwoodConfigState(this);
private RavenwoodConfig() {
}
@@ -84,6 +93,12 @@
return RavenwoodRule.isOnRavenwood();
}
+ private void setDefaults() {
+ if (mTargetPackageName == null) {
+ mTargetPackageName = mTestPackageName;
+ }
+ }
+
public static class Builder {
private final RavenwoodConfig mConfig = new RavenwoodConfig();
@@ -109,11 +124,28 @@
}
/**
- * Configure the identity of this process to be the given package name for the duration
- * of the test. Has no effect on non-Ravenwood environments.
+ * Configure the package name of the test, which corresponds to
+ * {@link Instrumentation#getContext()}.
*/
public Builder setPackageName(@NonNull String packageName) {
- mConfig.mPackageName = Objects.requireNonNull(packageName);
+ mConfig.mTestPackageName = Objects.requireNonNull(packageName);
+ return this;
+ }
+
+ /**
+ * Configure the package name of the target app, which corresponds to
+ * {@link Instrumentation#getTargetContext()}. Defaults to {@link #setPackageName}.
+ */
+ public Builder setTargetPackageName(@NonNull String packageName) {
+ mConfig.mTargetPackageName = Objects.requireNonNull(packageName);
+ return this;
+ }
+
+ /**
+ * Configure the min SDK level of the test.
+ */
+ public Builder setMinSdkLevel(int sdkLevel) {
+ mConfig.mMinSdkLevel = sdkLevel;
return this;
}
@@ -178,6 +210,7 @@
}
public RavenwoodConfig build() {
+ mConfig.setDefaults();
return mConfig;
}
}
diff --git a/ravenwood/junit-src/android/platform/test/ravenwood/RavenwoodRule.java b/ravenwood/junit-src/android/platform/test/ravenwood/RavenwoodRule.java
index 7847e7c..984106b 100644
--- a/ravenwood/junit-src/android/platform/test/ravenwood/RavenwoodRule.java
+++ b/ravenwood/junit-src/android/platform/test/ravenwood/RavenwoodRule.java
@@ -216,7 +216,7 @@
*/
@Deprecated
public Context getContext() {
- return Objects.requireNonNull(mConfiguration.mContext,
+ return Objects.requireNonNull(mConfiguration.mTestContext,
"Context is only available during @Test execution");
}
diff --git a/packages/SystemUI/compose/facade/enabled/src/com/android/systemui/scene/QuickSettingsShadeSceneModule.kt b/ravenwood/junit-stub-src/android/platform/test/ravenwood/RavenwoodConfigState.java
similarity index 62%
rename from packages/SystemUI/compose/facade/enabled/src/com/android/systemui/scene/QuickSettingsShadeSceneModule.kt
rename to ravenwood/junit-stub-src/android/platform/test/ravenwood/RavenwoodConfigState.java
index 5bb6ae4..43a28ba 100644
--- a/packages/SystemUI/compose/facade/enabled/src/com/android/systemui/scene/QuickSettingsShadeSceneModule.kt
+++ b/ravenwood/junit-stub-src/android/platform/test/ravenwood/RavenwoodConfigState.java
@@ -13,17 +13,10 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
+package android.platform.test.ravenwood;
-package com.android.systemui.scene
-
-import com.android.systemui.qs.ui.composable.QuickSettingsShadeScene
-import com.android.systemui.scene.ui.composable.Scene
-import dagger.Binds
-import dagger.Module
-import dagger.multibindings.IntoSet
-
-@Module
-interface QuickSettingsShadeSceneModule {
-
- @Binds @IntoSet fun quickSettingsShade(scene: QuickSettingsShadeScene): Scene
+/** Stub class. The actual implementaetion is in junit-impl-src. */
+public class RavenwoodConfigState {
+ public RavenwoodConfigState(RavenwoodConfig config) {
+ }
}
diff --git a/packages/SystemUI/compose/facade/enabled/src/com/android/systemui/scene/QuickSettingsShadeSceneModule.kt b/ravenwood/junit-stub-src/android/platform/test/ravenwood/RavenwoodRunnerState.java
similarity index 62%
copy from packages/SystemUI/compose/facade/enabled/src/com/android/systemui/scene/QuickSettingsShadeSceneModule.kt
copy to ravenwood/junit-stub-src/android/platform/test/ravenwood/RavenwoodRunnerState.java
index 5bb6ae4..83cbc52 100644
--- a/packages/SystemUI/compose/facade/enabled/src/com/android/systemui/scene/QuickSettingsShadeSceneModule.kt
+++ b/ravenwood/junit-stub-src/android/platform/test/ravenwood/RavenwoodRunnerState.java
@@ -13,17 +13,10 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
+package android.platform.test.ravenwood;
-package com.android.systemui.scene
-
-import com.android.systemui.qs.ui.composable.QuickSettingsShadeScene
-import com.android.systemui.scene.ui.composable.Scene
-import dagger.Binds
-import dagger.Module
-import dagger.multibindings.IntoSet
-
-@Module
-interface QuickSettingsShadeSceneModule {
-
- @Binds @IntoSet fun quickSettingsShade(scene: QuickSettingsShadeScene): Scene
+/** Stub class. The actual implementaetion is in junit-impl-src. */
+public class RavenwoodRunnerState {
+ public RavenwoodRunnerState(RavenwoodAwareTestRunner runner) {
+ }
}
diff --git a/ravenwood/tests/bivalentinst/Android.bp b/ravenwood/tests/bivalentinst/Android.bp
new file mode 100644
index 0000000..38d1b299
--- /dev/null
+++ b/ravenwood/tests/bivalentinst/Android.bp
@@ -0,0 +1,149 @@
+package {
+ // See: http://go/android-license-faq
+ // A large-scale-change added 'default_applicable_licenses' to import
+ // all of the 'license_kinds' from "frameworks_base_license"
+ // to get the below license kinds:
+ // SPDX-license-identifier-Apache-2.0
+ default_applicable_licenses: ["frameworks_base_license"],
+}
+
+android_ravenwood_test {
+ name: "RavenwoodBivalentInstTest_self_inst",
+
+ srcs: [
+ "test/**/*.java",
+ ],
+ exclude_srcs: [
+ "test/**/*_nonself.java",
+ ],
+
+ static_libs: [
+ "RavenwoodBivalentInstTest_self_inst_device_R",
+
+ "androidx.annotation_annotation",
+ "androidx.test.ext.junit",
+ "androidx.test.rules",
+
+ "junit",
+ "truth",
+ ],
+ // TODO(b/366246777) uncomment it and the test.
+ // resource_apk: "RavenwoodBivalentInstTest_self_inst_device",
+ auto_gen_config: true,
+}
+
+android_ravenwood_test {
+ name: "RavenwoodBivalentInstTest_nonself_inst",
+
+ srcs: [
+ "test/**/*.java",
+ ],
+ exclude_srcs: [
+ "test/**/*_self.java",
+ ],
+
+ static_libs: [
+ "RavenwoodBivalentInstTestTarget_R",
+ "RavenwoodBivalentInstTest_nonself_inst_device_R",
+
+ "androidx.annotation_annotation",
+ "androidx.test.ext.junit",
+ "androidx.test.rules",
+
+ "junit",
+ "truth",
+ ],
+ // TODO(b/366246777) uncomment it and the test.
+ // resource_apk: "RavenwoodBivalentInstTestTarget",
+ auto_gen_config: true,
+}
+
+// We have 3 R.javas from the 3 packages (2 test apks below, and 1 target APK)
+// RavenwoodBivalentInstTest needs to use all of them, but we can't add all the
+// {.aapt.srcjar}'s together because that'd cause
+// "duplicate declaration of androidx.test.core.R$string."
+// So we build them as separate libraries, and include them as static_libs.
+java_library {
+ name: "RavenwoodBivalentInstTestTarget_R",
+ srcs: [
+ ":RavenwoodBivalentInstTestTarget{.aapt.srcjar}",
+ ],
+}
+
+java_library {
+ name: "RavenwoodBivalentInstTest_self_inst_device_R",
+ srcs: [
+ ":RavenwoodBivalentInstTest_self_inst_device{.aapt.srcjar}",
+ ],
+}
+
+java_library {
+ name: "RavenwoodBivalentInstTest_nonself_inst_device_R",
+ srcs: [
+ ":RavenwoodBivalentInstTest_nonself_inst_device{.aapt.srcjar}",
+ ],
+}
+
+android_test {
+ name: "RavenwoodBivalentInstTest_self_inst_device",
+
+ srcs: [
+ "test/**/*.java",
+ ],
+ exclude_srcs: [
+ "test/**/*_nonself.java",
+ ],
+ static_libs: [
+ "junit",
+ "truth",
+
+ "androidx.annotation_annotation",
+ "androidx.test.ext.junit",
+ "androidx.test.rules",
+
+ "ravenwood-junit",
+ ],
+ test_suites: [
+ "device-tests",
+ ],
+ use_resource_processor: false,
+ manifest: "AndroidManifest-self-inst.xml",
+ test_config: "AndroidTest-self-inst.xml",
+ optimize: {
+ enabled: false,
+ },
+}
+
+android_test {
+ name: "RavenwoodBivalentInstTest_nonself_inst_device",
+
+ srcs: [
+ "test/**/*.java",
+ ],
+ exclude_srcs: [
+ "test/**/*_self.java",
+ ],
+ static_libs: [
+ "junit",
+ "truth",
+
+ "androidx.annotation_annotation",
+ "androidx.test.ext.junit",
+ "androidx.test.rules",
+
+ "ravenwood-junit",
+ ],
+ data: [
+ ":RavenwoodBivalentInstTestTarget",
+ ],
+ test_suites: [
+ "device-tests",
+ ],
+ use_resource_processor: false,
+ manifest: "AndroidManifest-nonself-inst.xml",
+ test_config: "AndroidTest-nonself-inst.xml",
+ instrumentation_for: "RavenwoodBivalentInstTestTarget",
+ optimize: {
+ enabled: false,
+ },
+}
diff --git a/ravenwood/tests/bivalentinst/AndroidManifest-nonself-inst.xml b/ravenwood/tests/bivalentinst/AndroidManifest-nonself-inst.xml
new file mode 100644
index 0000000..a5a1f17
--- /dev/null
+++ b/ravenwood/tests/bivalentinst/AndroidManifest-nonself-inst.xml
@@ -0,0 +1,28 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- 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.
+-->
+
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+ package="com.android.ravenwood.bivalentinsttest_nonself_inst">
+
+ <application android:debuggable="true" >
+ <uses-library android:name="android.test.runner" />
+ </application>
+
+ <instrumentation
+ android:name="androidx.test.runner.AndroidJUnitRunner"
+ android:targetPackage="com.android.ravenwood.bivalentinst_target_app"
+ />
+</manifest>
diff --git a/ravenwood/tests/bivalentinst/AndroidManifest-self-inst.xml b/ravenwood/tests/bivalentinst/AndroidManifest-self-inst.xml
new file mode 100644
index 0000000..3dc4c56
--- /dev/null
+++ b/ravenwood/tests/bivalentinst/AndroidManifest-self-inst.xml
@@ -0,0 +1,28 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- 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.
+-->
+
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+ package="com.android.ravenwood.bivalentinsttest_self_inst">
+
+ <application android:debuggable="true" >
+ <uses-library android:name="android.test.runner" />
+ </application>
+
+ <instrumentation
+ android:name="androidx.test.runner.AndroidJUnitRunner"
+ android:targetPackage="com.android.ravenwood.bivalentinsttest_self_inst"
+ />
+</manifest>
diff --git a/ravenwood/tests/bivalentinst/AndroidTest-nonself-inst.xml b/ravenwood/tests/bivalentinst/AndroidTest-nonself-inst.xml
new file mode 100644
index 0000000..9491c53
--- /dev/null
+++ b/ravenwood/tests/bivalentinst/AndroidTest-nonself-inst.xml
@@ -0,0 +1,30 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- 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.
+-->
+<configuration>
+ <option name="test-suite-tag" value="apct" />
+ <option name="test-suite-tag" value="apct-instrumentation" />
+
+ <target_preparer class="com.android.tradefed.targetprep.suite.SuiteApkInstaller">
+ <option name="cleanup-apks" value="true" />
+ <option name="test-file-name" value="RavenwoodBivalentInstTestTarget.apk" />
+ <option name="test-file-name" value="RavenwoodBivalentInstTest_nonself_inst_device.apk" />
+ </target_preparer>
+
+ <test class="com.android.tradefed.testtype.AndroidJUnitTest" >
+ <option name="package" value="com.android.ravenwood.bivalentinsttest_nonself_inst" />
+ <option name="runner" value="androidx.test.runner.AndroidJUnitRunner" />
+ </test>
+</configuration>
diff --git a/ravenwood/tests/bivalentinst/AndroidTest-self-inst.xml b/ravenwood/tests/bivalentinst/AndroidTest-self-inst.xml
new file mode 100644
index 0000000..3079c06
--- /dev/null
+++ b/ravenwood/tests/bivalentinst/AndroidTest-self-inst.xml
@@ -0,0 +1,29 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- 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.
+-->
+<configuration>
+ <option name="test-suite-tag" value="apct" />
+ <option name="test-suite-tag" value="apct-instrumentation" />
+
+ <target_preparer class="com.android.tradefed.targetprep.suite.SuiteApkInstaller">
+ <option name="cleanup-apks" value="true" />
+ <option name="test-file-name" value="RavenwoodBivalentInstTest_self_inst_device.apk" />
+ </target_preparer>
+
+ <test class="com.android.tradefed.testtype.AndroidJUnitTest" >
+ <option name="package" value="com.android.ravenwood.bivalentinsttest_self_inst" />
+ <option name="runner" value="androidx.test.runner.AndroidJUnitRunner" />
+ </test>
+</configuration>
diff --git a/ravenwood/tests/bivalentinst/res/values/strings.xml b/ravenwood/tests/bivalentinst/res/values/strings.xml
new file mode 100644
index 0000000..73ef650
--- /dev/null
+++ b/ravenwood/tests/bivalentinst/res/values/strings.xml
@@ -0,0 +1,20 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 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.
+-->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string translatable="false" name="test_string_in_test">String in test APK</string>
+</resources>
diff --git a/ravenwood/tests/bivalentinst/targetapp/Android.bp b/ravenwood/tests/bivalentinst/targetapp/Android.bp
new file mode 100644
index 0000000..7528a62
--- /dev/null
+++ b/ravenwood/tests/bivalentinst/targetapp/Android.bp
@@ -0,0 +1,20 @@
+package {
+ // See: http://go/android-license-faq
+ // A large-scale-change added 'default_applicable_licenses' to import
+ // all of the 'license_kinds' from "frameworks_base_license"
+ // to get the below license kinds:
+ // SPDX-license-identifier-Apache-2.0
+ default_applicable_licenses: ["frameworks_base_license"],
+}
+
+android_app {
+ name: "RavenwoodBivalentInstTestTarget",
+ srcs: [
+ "src/**/*.java",
+ ],
+ sdk_version: "current",
+ optimize: {
+ enabled: false,
+ },
+ use_resource_processor: false,
+}
diff --git a/ravenwood/tests/bivalentinst/targetapp/AndroidManifest.xml b/ravenwood/tests/bivalentinst/targetapp/AndroidManifest.xml
new file mode 100644
index 0000000..0715f5d
--- /dev/null
+++ b/ravenwood/tests/bivalentinst/targetapp/AndroidManifest.xml
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- 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.
+-->
+
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+ package="com.android.ravenwood.bivalentinst_target_app">
+ <application>
+ </application>
+</manifest>
diff --git a/ravenwood/tests/bivalentinst/targetapp/res/values/strings.xml b/ravenwood/tests/bivalentinst/targetapp/res/values/strings.xml
new file mode 100644
index 0000000..395bc2a
--- /dev/null
+++ b/ravenwood/tests/bivalentinst/targetapp/res/values/strings.xml
@@ -0,0 +1,20 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 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.
+-->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string translatable="false" name="test_string_in_target">Test string in target APK</string>
+</resources>
diff --git a/packages/SystemUI/compose/facade/enabled/src/com/android/systemui/scene/QuickSettingsShadeSceneModule.kt b/ravenwood/tests/bivalentinst/targetapp/src/com/android/ravenwoodtest/bivalentinst/Empty.java
similarity index 62%
copy from packages/SystemUI/compose/facade/enabled/src/com/android/systemui/scene/QuickSettingsShadeSceneModule.kt
copy to ravenwood/tests/bivalentinst/targetapp/src/com/android/ravenwoodtest/bivalentinst/Empty.java
index 5bb6ae4..15e50ec 100644
--- a/packages/SystemUI/compose/facade/enabled/src/com/android/systemui/scene/QuickSettingsShadeSceneModule.kt
+++ b/ravenwood/tests/bivalentinst/targetapp/src/com/android/ravenwoodtest/bivalentinst/Empty.java
@@ -13,17 +13,10 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
+package com.android.ravenwoodtest.bivalentinst;
-package com.android.systemui.scene
-
-import com.android.systemui.qs.ui.composable.QuickSettingsShadeScene
-import com.android.systemui.scene.ui.composable.Scene
-import dagger.Binds
-import dagger.Module
-import dagger.multibindings.IntoSet
-
-@Module
-interface QuickSettingsShadeSceneModule {
-
- @Binds @IntoSet fun quickSettingsShade(scene: QuickSettingsShadeScene): Scene
+/**
+ * Empty class. We need it because an instrumentation target APK must have code.
+ */
+public class Empty {
}
diff --git a/ravenwood/tests/bivalentinst/test/com/android/ravenwoodtest/bivalentinst/RavenwoodInstrumentationTest_nonself.java b/ravenwood/tests/bivalentinst/test/com/android/ravenwoodtest/bivalentinst/RavenwoodInstrumentationTest_nonself.java
new file mode 100644
index 0000000..9f3ca6f
--- /dev/null
+++ b/ravenwood/tests/bivalentinst/test/com/android/ravenwoodtest/bivalentinst/RavenwoodInstrumentationTest_nonself.java
@@ -0,0 +1,115 @@
+/*
+ * 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 com.android.ravenwoodtest.bivalentinst;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import android.app.Instrumentation;
+import android.content.Context;
+import android.platform.test.annotations.DisabledOnRavenwood;
+import android.platform.test.ravenwood.RavenwoodConfig;
+import android.platform.test.ravenwood.RavenwoodConfig.Config;
+
+import androidx.test.ext.junit.runners.AndroidJUnit4;
+import androidx.test.platform.app.InstrumentationRegistry;
+
+import org.junit.BeforeClass;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+/**
+ * Tests for the case where the instrumentation target is _not_ the test APK itself.
+ */
+@RunWith(AndroidJUnit4.class)
+public class RavenwoodInstrumentationTest_nonself {
+ private static final String TARGET_PACKAGE_NAME =
+ "com.android.ravenwood.bivalentinst_target_app";
+ private static final String TEST_PACKAGE_NAME =
+ "com.android.ravenwood.bivalentinsttest_nonself_inst";
+
+ @Config
+ public static final RavenwoodConfig sConfig = new RavenwoodConfig.Builder()
+ .setPackageName(TEST_PACKAGE_NAME)
+ .setTargetPackageName(TARGET_PACKAGE_NAME)
+ .build();
+
+ private static Instrumentation sInstrumentation;
+ private static Context sTestContext;
+ private static Context sTargetContext;
+
+ @BeforeClass
+ public static void beforeClass() {
+ sInstrumentation = InstrumentationRegistry.getInstrumentation();
+ sTestContext = sInstrumentation.getContext();
+ sTargetContext = sInstrumentation.getTargetContext();
+ }
+
+ @Test
+ public void testTestContextPackageName() {
+ assertThat(sTestContext.getPackageName()).isEqualTo(TEST_PACKAGE_NAME);
+ }
+
+ @Test
+ public void testTargetContextPackageName() {
+ assertThat(sTargetContext.getPackageName()).isEqualTo(TARGET_PACKAGE_NAME);
+ }
+
+ @Test
+ public void testTestAppContext() {
+ // Test context doesn't have an app context.
+ assertThat(sTestContext.getApplicationContext()).isNull();
+ }
+
+ @Test
+ public void testTargetAppContextPackageName() {
+ assertThat(sTargetContext.getApplicationContext().getPackageName())
+ .isEqualTo(TARGET_PACKAGE_NAME);
+ }
+
+ @Test
+ public void testTargetAppAppContextPackageName() {
+ assertThat(sTargetContext.getApplicationContext()
+ .getApplicationContext().getPackageName())
+ .isEqualTo(TARGET_PACKAGE_NAME);
+ }
+
+ @Test
+ public void testContextSameness() {
+ assertThat(sTargetContext).isNotSameInstanceAs(sTestContext);
+
+ assertThat(sTargetContext).isNotSameInstanceAs(sTargetContext.getApplicationContext());
+
+ assertThat(sTargetContext.getApplicationContext()).isSameInstanceAs(
+ sTargetContext.getApplicationContext().getApplicationContext());
+ }
+
+ @Test
+ @DisabledOnRavenwood(reason = "b/366246777")
+ public void testTargetAppResource() {
+ assertThat(sTargetContext.getString(
+ com.android.ravenwood.bivalentinst_target_app.R.string.test_string_in_target))
+ .isEqualTo("Test string in target APK");
+ }
+
+ @Test
+ @DisabledOnRavenwood(
+ reason = "Loading resources from non-self-instrumenting test APK isn't supported yet")
+ public void testTestAppResource() {
+ assertThat(sTestContext.getString(
+ com.android.ravenwood.bivalentinsttest_nonself_inst.R.string.test_string_in_test))
+ .isEqualTo("String in test APK");
+ }
+}
diff --git a/ravenwood/tests/bivalentinst/test/com/android/ravenwoodtest/bivalentinst/RavenwoodInstrumentationTest_self.java b/ravenwood/tests/bivalentinst/test/com/android/ravenwoodtest/bivalentinst/RavenwoodInstrumentationTest_self.java
new file mode 100644
index 0000000..fdff222
--- /dev/null
+++ b/ravenwood/tests/bivalentinst/test/com/android/ravenwoodtest/bivalentinst/RavenwoodInstrumentationTest_self.java
@@ -0,0 +1,126 @@
+/*
+ * 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 com.android.ravenwoodtest.bivalentinst;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import android.app.Instrumentation;
+import android.content.Context;
+import android.platform.test.annotations.DisabledOnRavenwood;
+import android.platform.test.ravenwood.RavenwoodConfig;
+import android.platform.test.ravenwood.RavenwoodConfig.Config;
+
+import androidx.test.ext.junit.runners.AndroidJUnit4;
+import androidx.test.platform.app.InstrumentationRegistry;
+
+import org.junit.BeforeClass;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+/**
+ * Tests for the case where the instrumentation target is the test APK itself.
+ */
+@RunWith(AndroidJUnit4.class)
+public class RavenwoodInstrumentationTest_self {
+
+ private static final String TARGET_PACKAGE_NAME =
+ "com.android.ravenwood.bivalentinsttest_self_inst";
+ private static final String TEST_PACKAGE_NAME =
+ "com.android.ravenwood.bivalentinsttest_self_inst";
+
+ @Config
+ public static final RavenwoodConfig sConfig = new RavenwoodConfig.Builder()
+ .setPackageName(TEST_PACKAGE_NAME)
+ .setTargetPackageName(TARGET_PACKAGE_NAME)
+ .build();
+
+
+ private static Instrumentation sInstrumentation;
+ private static Context sTestContext;
+ private static Context sTargetContext;
+
+ @BeforeClass
+ public static void beforeClass() {
+ sInstrumentation = InstrumentationRegistry.getInstrumentation();
+ sTestContext = sInstrumentation.getContext();
+ sTargetContext = sInstrumentation.getTargetContext();
+ }
+
+ @Test
+ public void testTestContextPackageName() {
+ assertThat(sTestContext.getPackageName()).isEqualTo(TEST_PACKAGE_NAME);
+ }
+
+ @Test
+ public void testTargetContextPackageName() {
+ assertThat(sTargetContext.getPackageName()).isEqualTo(TARGET_PACKAGE_NAME);
+ }
+
+ @Test
+ public void testTestAppContextPackageName() {
+ assertThat(sTestContext.getApplicationContext().getPackageName())
+ .isEqualTo(TEST_PACKAGE_NAME);
+ }
+
+ @Test
+ public void testTestAppAppContextPackageName() {
+ assertThat(sTestContext.getApplicationContext().getPackageName())
+ .isEqualTo(TEST_PACKAGE_NAME);
+ }
+
+ @Test
+ public void testTargetAppContextPackageName() {
+ assertThat(sTargetContext.getApplicationContext()
+ .getApplicationContext().getPackageName())
+ .isEqualTo(TARGET_PACKAGE_NAME);
+ }
+
+ @Test
+ public void testTargetAppAppContextPackageName() {
+ assertThat(sTargetContext.getApplicationContext()
+ .getApplicationContext().getPackageName())
+ .isEqualTo(TARGET_PACKAGE_NAME);
+ }
+
+ @Test
+ public void testContextSameness() {
+ assertThat(sTargetContext).isNotSameInstanceAs(sTestContext);
+
+ assertThat(sTestContext).isNotSameInstanceAs(sTestContext.getApplicationContext());
+ assertThat(sTargetContext).isNotSameInstanceAs(sTargetContext.getApplicationContext());
+
+ assertThat(sTestContext.getApplicationContext()).isSameInstanceAs(
+ sTestContext.getApplicationContext().getApplicationContext());
+ assertThat(sTargetContext.getApplicationContext()).isSameInstanceAs(
+ sTargetContext.getApplicationContext().getApplicationContext());
+ }
+
+ @Test
+ @DisabledOnRavenwood(reason = "b/366246777")
+ public void testTargetAppResource() {
+ assertThat(sTargetContext.getString(
+ com.android.ravenwood.bivalentinsttest_self_inst.R.string.test_string_in_test))
+ .isEqualTo("String in test APK");
+ }
+
+ @Test
+ @DisabledOnRavenwood(reason = "b/366246777")
+ public void testTestAppResource() {
+ assertThat(sTestContext.getString(
+ com.android.ravenwood.bivalentinsttest_self_inst.R.string.test_string_in_test))
+ .isEqualTo("String in test APK");
+ }
+}
diff --git a/ravenwood/tools/ravenizer/src/com/android/platform/test/ravenwood/ravenizer/Ravenizer.kt b/ravenwood/tools/ravenizer/src/com/android/platform/test/ravenwood/ravenizer/Ravenizer.kt
index a38512e..f7f9a85 100644
--- a/ravenwood/tools/ravenizer/src/com/android/platform/test/ravenwood/ravenizer/Ravenizer.kt
+++ b/ravenwood/tools/ravenizer/src/com/android/platform/test/ravenwood/ravenizer/Ravenizer.kt
@@ -127,7 +127,7 @@
}
}
- stats.totalProcessTime = log.iTime("$executableName processing $inJar") {
+ stats.totalProcessTime = log.vTime("$executableName processing $inJar") {
ZipFile(inJar).use { inZip ->
val inEntries = inZip.entries()
diff --git a/ravenwood/tools/ravenizer/src/com/android/platform/test/ravenwood/ravenizer/RavenizerOptions.kt b/ravenwood/tools/ravenizer/src/com/android/platform/test/ravenwood/ravenizer/RavenizerOptions.kt
index e8341e5..10fe0a3 100644
--- a/ravenwood/tools/ravenizer/src/com/android/platform/test/ravenwood/ravenizer/RavenizerOptions.kt
+++ b/ravenwood/tools/ravenizer/src/com/android/platform/test/ravenwood/ravenizer/RavenizerOptions.kt
@@ -20,6 +20,20 @@
import com.android.hoststubgen.SetOnce
import com.android.hoststubgen.ensureFileExists
import com.android.hoststubgen.log
+import java.nio.file.Paths
+import kotlin.io.path.exists
+
+/**
+ * If this file exits, we also read options from it. This is "unsafe" because it could break
+ * incremental builds, if it sets any flag that affects the output file.
+ * (however, for now, there's no such options.)
+ *
+ * For example, to enable verbose logging, do `echo '-v' > ~/.raveniezr-unsafe`
+ *
+ * (but even the content of this file changes, soong won't rerun the command, so you need to
+ * remove the output first and then do a build again.)
+ */
+private val RAVENIZER_DOTFILE = System.getenv("HOME") + "/.raveniezr-unsafe"
class RavenizerOptions(
/** Input jar file*/
@@ -35,9 +49,16 @@
var fatalValidation: SetOnce<Boolean> = SetOnce(false),
) {
companion object {
- fun parseArgs(args: Array<String>): RavenizerOptions {
+
+ fun parseArgs(origArgs: Array<String>): RavenizerOptions {
+ val args = origArgs.toMutableList()
+ if (Paths.get(RAVENIZER_DOTFILE).exists()) {
+ log.i("Reading options from $RAVENIZER_DOTFILE")
+ args.add(0, "@$RAVENIZER_DOTFILE")
+ }
+
val ret = RavenizerOptions()
- val ai = ArgIterator.withAtFiles(args)
+ val ai = ArgIterator.withAtFiles(args.toTypedArray())
while (true) {
val arg = ai.nextArgOptional()
diff --git a/ravenwood/tools/ravenizer/src/com/android/platform/test/ravenwood/ravenizer/adapter/RunnerRewritingAdapter.kt b/ravenwood/tools/ravenizer/src/com/android/platform/test/ravenwood/ravenizer/adapter/RunnerRewritingAdapter.kt
index bd9d96d..cf6d6f6 100644
--- a/ravenwood/tools/ravenizer/src/com/android/platform/test/ravenwood/ravenizer/adapter/RunnerRewritingAdapter.kt
+++ b/ravenwood/tools/ravenizer/src/com/android/platform/test/ravenwood/ravenizer/adapter/RunnerRewritingAdapter.kt
@@ -184,7 +184,7 @@
av.visit("value", ravenwoodTestRunnerType.type)
av.visitEnd()
}
- log.i("Update the @RunWith: ${classInternalName.toHumanReadableClassName()}")
+ log.v("Update the @RunWith: ${classInternalName.toHumanReadableClassName()}")
}
/*
@@ -442,7 +442,7 @@
// Don't process a class if it has a @NoRavenizer annotation.
classes.findClass(className)?.let { cn ->
if (cn.findAnyAnnotation(noRavenizerAnotType.descAsSet) != null) {
- log.w("Class ${className.toHumanReadableClassName()} has" +
+ log.i("Class ${className.toHumanReadableClassName()} has" +
" @${noRavenizerAnotType.humanReadableName}. Skipping."
)
return false
diff --git a/services/appfunctions/java/com/android/server/appfunctions/AppFunctionManagerServiceImpl.java b/services/appfunctions/java/com/android/server/appfunctions/AppFunctionManagerServiceImpl.java
index 269419f..2362b91 100644
--- a/services/appfunctions/java/com/android/server/appfunctions/AppFunctionManagerServiceImpl.java
+++ b/services/appfunctions/java/com/android/server/appfunctions/AppFunctionManagerServiceImpl.java
@@ -38,6 +38,7 @@
import com.android.server.appfunctions.RemoteServiceCaller.ServiceUsageCompleteListener;
import java.util.Objects;
+import java.util.concurrent.CompletionException;
import java.util.concurrent.LinkedBlockingQueue;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;
@@ -255,6 +256,10 @@
}
private ExecuteAppFunctionResponse mapExceptionToExecuteAppFunctionResponse(Throwable e) {
+ if(e instanceof CompletionException) {
+ e = e.getCause();
+ }
+
if (e instanceof AppSearchException) {
AppSearchException appSearchException = (AppSearchException) e;
return ExecuteAppFunctionResponse.newFailure(
diff --git a/services/appfunctions/java/com/android/server/appfunctions/FutureAppSearchSession.java b/services/appfunctions/java/com/android/server/appfunctions/FutureAppSearchSession.java
index 56f373d..0044b4b 100644
--- a/services/appfunctions/java/com/android/server/appfunctions/FutureAppSearchSession.java
+++ b/services/appfunctions/java/com/android/server/appfunctions/FutureAppSearchSession.java
@@ -75,7 +75,7 @@
* AppSearchSession} database.
*/
AndroidFuture<AppSearchBatchResult<String, GenericDocument>> getByDocumentId(
- GetByDocumentIdRequest getRequest);
+ @NonNull GetByDocumentIdRequest getRequest);
/**
* Retrieves documents from the open {@link AppSearchSession} that match a given query string
diff --git a/services/appfunctions/java/com/android/server/appfunctions/MetadataSyncAdapter.java b/services/appfunctions/java/com/android/server/appfunctions/MetadataSyncAdapter.java
index 5f60804..e2573590 100644
--- a/services/appfunctions/java/com/android/server/appfunctions/MetadataSyncAdapter.java
+++ b/services/appfunctions/java/com/android/server/appfunctions/MetadataSyncAdapter.java
@@ -61,7 +61,8 @@
*/
public class MetadataSyncAdapter {
private static final String TAG = MetadataSyncAdapter.class.getSimpleName();
- private final FutureAppSearchSession mFutureAppSearchSession;
+ private final FutureAppSearchSession mRuntimeMetadataSearchSession;
+ private final FutureAppSearchSession mStaticMetadataSearchSession;
private final Executor mSyncExecutor;
private final PackageManager mPackageManager;
@@ -72,10 +73,12 @@
public MetadataSyncAdapter(
@NonNull Executor syncExecutor,
- @NonNull FutureAppSearchSession futureAppSearchSession,
+ @NonNull FutureAppSearchSession runtimeMetadataSearchSession,
+ @NonNull FutureAppSearchSession staticMetadataSearchSession,
@NonNull PackageManager packageManager) {
mSyncExecutor = Objects.requireNonNull(syncExecutor);
- mFutureAppSearchSession = Objects.requireNonNull(futureAppSearchSession);
+ mRuntimeMetadataSearchSession = Objects.requireNonNull(runtimeMetadataSearchSession);
+ mStaticMetadataSearchSession = Objects.requireNonNull(staticMetadataSearchSession);
mPackageManager = Objects.requireNonNull(packageManager);
}
@@ -104,11 +107,13 @@
throws ExecutionException, InterruptedException {
ArrayMap<String, ArraySet<String>> staticPackageToFunctionMap =
getPackageToFunctionIdMap(
+ mStaticMetadataSearchSession,
AppFunctionStaticMetadataHelper.STATIC_SCHEMA_TYPE,
AppFunctionStaticMetadataHelper.PROPERTY_FUNCTION_ID,
AppFunctionStaticMetadataHelper.PROPERTY_PACKAGE_NAME);
ArrayMap<String, ArraySet<String>> runtimePackageToFunctionMap =
getPackageToFunctionIdMap(
+ mRuntimeMetadataSearchSession,
RUNTIME_SCHEMA_TYPE,
AppFunctionRuntimeMetadata.PROPERTY_FUNCTION_ID,
AppFunctionRuntimeMetadata.PROPERTY_PACKAGE_NAME);
@@ -129,7 +134,7 @@
RemoveByDocumentIdRequest removeByDocumentIdRequest =
buildRemoveRuntimeMetadataRequest(removedFunctionsDiffMap);
AppSearchBatchResult<String, Void> removeDocumentBatchResult =
- mFutureAppSearchSession.remove(removeByDocumentIdRequest).get();
+ mRuntimeMetadataSearchSession.remove(removeByDocumentIdRequest).get();
if (!removeDocumentBatchResult.isSuccess()) {
throw convertFailedAppSearchResultToException(
removeDocumentBatchResult.getFailures().values());
@@ -140,11 +145,12 @@
// TODO(b/357551503): only set schema on package diff
SetSchemaRequest addSetSchemaRequest =
buildSetSchemaRequestForRuntimeMetadataSchemas(appRuntimeMetadataSchemas);
- Objects.requireNonNull(mFutureAppSearchSession.setSchema(addSetSchemaRequest).get());
+ Objects.requireNonNull(
+ mRuntimeMetadataSearchSession.setSchema(addSetSchemaRequest).get());
PutDocumentsRequest putDocumentsRequest =
buildPutRuntimeMetadataRequest(addedFunctionsDiffMap);
AppSearchBatchResult<String, Void> putDocumentBatchResult =
- mFutureAppSearchSession.put(putDocumentsRequest).get();
+ mRuntimeMetadataSearchSession.put(putDocumentsRequest).get();
if (!putDocumentBatchResult.isSuccess()) {
throw convertFailedAppSearchResultToException(
putDocumentBatchResult.getFailures().values());
@@ -174,11 +180,7 @@
ArraySet<String> addedFunctionIds = addedFunctionsDiffMap.valueAt(i);
for (String addedFunctionId : addedFunctionIds) {
putDocumentRequestBuilder.addGenericDocuments(
- new AppFunctionRuntimeMetadata.Builder(
- packageName,
- addedFunctionId,
- AppFunctionRuntimeMetadata
- .PROPERTY_APP_FUNCTION_STATIC_METADATA_QUALIFIED_ID)
+ new AppFunctionRuntimeMetadata.Builder(packageName, addedFunctionId)
.build());
}
}
@@ -226,12 +228,11 @@
runtimeMetadataSchema.getSchemaType(),
true,
new PackageIdentifier(packageName, packageCert));
+ setSchemaRequestBuilder.addRequiredPermissionsForSchemaTypeVisibility(
+ runtimeMetadataSchema.getSchemaType(), Set.of(EXECUTE_APP_FUNCTIONS));
+ setSchemaRequestBuilder.addRequiredPermissionsForSchemaTypeVisibility(
+ runtimeMetadataSchema.getSchemaType(), Set.of(EXECUTE_APP_FUNCTIONS_TRUSTED));
}
-
- setSchemaRequestBuilder.addRequiredPermissionsForSchemaTypeVisibility(
- RUNTIME_SCHEMA_TYPE, Set.of(EXECUTE_APP_FUNCTIONS));
- setSchemaRequestBuilder.addRequiredPermissionsForSchemaTypeVisibility(
- RUNTIME_SCHEMA_TYPE, Set.of(EXECUTE_APP_FUNCTIONS_TRUSTED));
return setSchemaRequestBuilder.build();
}
@@ -326,13 +327,17 @@
* This method returns a map of package names to a set of function ids from the AppFunction
* metadata.
*
- * @param schemaType The name space of the AppFunction metadata.
+ * @param searchSession The {@link FutureAppSearchSession} to search the AppFunction metadata.
+ * @param schemaType The schema type of the AppFunction metadata.
+ * @param propertyFunctionId The property name of the function id in the AppFunction metadata.
+ * @param propertyPackageName The property name of the package name in the AppFunction metadata.
* @return A map of package names to a set of function ids from the AppFunction metadata.
*/
@NonNull
@VisibleForTesting
@WorkerThread
- ArrayMap<String, ArraySet<String>> getPackageToFunctionIdMap(
+ static ArrayMap<String, ArraySet<String>> getPackageToFunctionIdMap(
+ @NonNull FutureAppSearchSession searchSession,
@NonNull String schemaType,
@NonNull String propertyFunctionId,
@NonNull String propertyPackageName)
@@ -343,7 +348,7 @@
ArrayMap<String, ArraySet<String>> packageToFunctionIds = new ArrayMap<>();
FutureSearchResults futureSearchResults =
- mFutureAppSearchSession
+ searchSession
.search(
"",
buildMetadataSearchSpec(
diff --git a/services/autofill/java/com/android/server/autofill/TEST_MAPPING b/services/autofill/java/com/android/server/autofill/TEST_MAPPING
index d8a6917..1dbeebe 100644
--- a/services/autofill/java/com/android/server/autofill/TEST_MAPPING
+++ b/services/autofill/java/com/android/server/autofill/TEST_MAPPING
@@ -1,15 +1,7 @@
{
"presubmit-large": [
{
- "name": "CtsAutoFillServiceTestCases",
- "options": [
- {
- "include-annotation": "android.platform.test.annotations.Presubmit"
- },
- {
- "exclude-annotation": "androidx.test.filters.FlakyTest"
- }
- ]
+ "name": "CtsAutoFillServiceTestCases_android_server_autofill_Presubmit"
}
]
}
diff --git a/services/backup/TEST_MAPPING b/services/backup/TEST_MAPPING
index e153230..0c14e56 100644
--- a/services/backup/TEST_MAPPING
+++ b/services/backup/TEST_MAPPING
@@ -1,12 +1,7 @@
{
"presubmit": [
{
- "name": "FrameworksMockingServicesTests",
- "options": [
- {
- "include-filter": "com.android.server.backup"
- }
- ]
+ "name": "FrameworksMockingServicesTests_backup"
},
{
"name": "CtsBackupTestCases",
diff --git a/services/companion/java/com/android/server/companion/securechannel/AttestationVerifier.java b/services/companion/java/com/android/server/companion/securechannel/AttestationVerifier.java
index 1559a3f..df3071e 100644
--- a/services/companion/java/com/android/server/companion/securechannel/AttestationVerifier.java
+++ b/services/companion/java/com/android/server/companion/securechannel/AttestationVerifier.java
@@ -53,9 +53,8 @@
*
* @param remoteAttestation the full certificate chain containing attestation extension.
* @param attestationChallenge attestation challenge for authentication.
- * @return true if attestation is successfully verified; false otherwise.
+ * @return 1 if attestation is successfully verified; 0 otherwise.
*/
- @NonNull
public int verifyAttestation(
@NonNull byte[] remoteAttestation,
@NonNull byte[] attestationChallenge
diff --git a/services/companion/java/com/android/server/companion/virtual/TEST_MAPPING b/services/companion/java/com/android/server/companion/virtual/TEST_MAPPING
index caa877c..14579c6 100644
--- a/services/companion/java/com/android/server/companion/virtual/TEST_MAPPING
+++ b/services/companion/java/com/android/server/companion/virtual/TEST_MAPPING
@@ -1,81 +1,32 @@
{
"presubmit": [
{
- "name": "CtsVirtualDevicesTestCases",
- "options": [
- {
- "exclude-annotation": "androidx.test.filters.FlakyTest"
- }
- ]
+ "name": "CtsVirtualDevicesTestCases"
},
{
- "name": "CtsVirtualDevicesAudioTestCases",
- "options": [
- {
- "exclude-annotation": "androidx.test.filters.FlakyTest"
- }
- ]
+ "name": "CtsVirtualDevicesAudioTestCases"
},
{
- "name": "CtsVirtualDevicesSensorTestCases",
- "options": [
- {
- "exclude-annotation": "androidx.test.filters.FlakyTest"
- }
- ]
+ "name": "CtsVirtualDevicesSensorTestCases"
},
{
- "name": "CtsVirtualDevicesAppLaunchTestCases",
- "options": [
- {
- "exclude-annotation": "androidx.test.filters.FlakyTest"
- }
- ]
+ "name": "CtsVirtualDevicesAppLaunchTestCases"
},
{
"name": "CtsVirtualDevicesCameraTestCases",
- "options": [
- {
- "exclude-annotation": "androidx.test.filters.FlakyTest"
- }
- ],
"keywords": ["primary-device"]
},
{
- "name": "CtsHardwareTestCases",
- "options": [
- {
- "include-filter": "android.hardware.input.cts.tests"
- },
- {
- "exclude-annotation": "androidx.test.filters.FlakyTest"
- }
- ],
+ "name": "CtsHardwareTestCases_cts_tests",
"file_patterns": ["Virtual[^/]*\\.java"]
},
{
- "name": "CtsAccessibilityServiceTestCases",
- "options": [
- {
- "include-filter": "android.accessibilityservice.cts.AccessibilityDisplayProxyTest"
- },
- {
- "exclude-annotation": "android.support.test.filters.FlakyTest"
- }
- ]
+ "name": "CtsAccessibilityServiceTestCases_cts_accessibilitydisplayproxytest"
}
],
"postsubmit": [
{
- "name": "CtsMediaAudioTestCases",
- "options": [
- {
- "include-filter": "android.media.audio.cts.AudioFocusWithVdmTest"
- },
- {
- "exclude-annotation": "androidx.test.filters.FlakyTest"
- }
- ]
+ "name": "CtsMediaAudioTestCases_cts_audiofocuswithvdmtest"
},
{
"name": "CtsPermissionTestCases",
@@ -92,12 +43,7 @@
]
},
{
- "name": "CtsPermissionMultiDeviceTestCases",
- "options": [
- {
- "exclude-annotation": "androidx.test.filters.FlakyTest"
- }
- ]
+ "name": "CtsPermissionMultiDeviceTestCases"
}
]
}
diff --git a/services/core/Android.bp b/services/core/Android.bp
index 1b5b7e8..4e36e3f 100644
--- a/services/core/Android.bp
+++ b/services/core/Android.bp
@@ -237,6 +237,7 @@
"dreams_flags_lib",
"aconfig_new_storage_flags_lib",
"powerstats_flags_lib",
+ "locksettings_flags_lib",
],
javac_shard_size: 50,
javacflags: [
diff --git a/services/core/java/com/android/server/TEST_MAPPING b/services/core/java/com/android/server/TEST_MAPPING
index 30f3fd2..68d0ad2 100644
--- a/services/core/java/com/android/server/TEST_MAPPING
+++ b/services/core/java/com/android/server/TEST_MAPPING
@@ -1,13 +1,7 @@
{
"presubmit": [
{
- "name": "CtsLocationFineTestCases",
- "options": [
- {
- // TODO: Wait for test to deflake - b/293934372
- "exclude-filter":"android.location.cts.fine.ScanningSettingsTest"
- }
- ]
+ "name": "CtsLocationFineTestCases_android_server_location"
},
{
"name": "CtsLocationCoarseTestCases"
@@ -20,12 +14,7 @@
"file_patterns": ["NotificationManagerService\\.java"]
},
{
- "name": "CtsWindowManagerDeviceWindow",
- "options": [
- {
- "include-filter": "android.server.wm.window.ToastWindowTest"
- }
- ],
+ "name": "CtsWindowManagerDeviceWindow_window_toastwindowtest",
"file_patterns": ["NotificationManagerService\\.java"]
},
{
@@ -103,12 +92,7 @@
"file_patterns": ["VcnManagementService\\.java"]
},
{
- "name": "FrameworksVpnTests",
- "options": [
- {
- "exclude-annotation": "com.android.testutils.SkipPresubmit"
- }
- ],
+ "name": "FrameworksVpnTests_android_server_connectivity",
"file_patterns": ["VpnManagerService\\.java"]
},
{
@@ -123,6 +107,15 @@
"Background.*\\.java",
"Activity.*\\.java"
]
+ },
+ {
+ "name": "CtsOsTestCases",
+ "file_patterns": ["StorageManagerService\\.java"],
+ "options": [
+ {
+ "include-filter": "android.os.storage.cts.StorageManagerTest"
+ }
+ ]
}
],
"presubmit-large": [
@@ -180,15 +173,6 @@
"include-filter": "com.android.server.wm.BackgroundActivityStart*"
}
]
- },
- {
- "name": "CtsOsTestCases",
- "file_patterns": ["StorageManagerService\\.java"],
- "options": [
- {
- "include-filter": "android.os.storage.cts.StorageManagerTest"
- }
- ]
}
]
}
diff --git a/services/core/java/com/android/server/am/TEST_MAPPING b/services/core/java/com/android/server/am/TEST_MAPPING
index ab5e2d0..6383dcb 100644
--- a/services/core/java/com/android/server/am/TEST_MAPPING
+++ b/services/core/java/com/android/server/am/TEST_MAPPING
@@ -22,32 +22,10 @@
]
},
{
- "name": "CtsAppFgsTestCases",
- "options": [
- {
- "include-annotation": "android.platform.test.annotations.Presubmit"
- },
- {
- "exclude-annotation": "androidx.test.filters.LargeTest"
- },
- {
- "exclude-annotation": "androidx.test.filters.FlakyTest"
- }
- ]
+ "name": "CtsAppFgsTestCases_pm_Presubmit"
},
{
- "name": "CtsShortFgsTestCases",
- "options": [
- {
- "include-annotation": "android.platform.test.annotations.Presubmit"
- },
- {
- "exclude-annotation": "androidx.test.filters.LargeTest"
- },
- {
- "exclude-annotation": "androidx.test.filters.FlakyTest"
- }
- ]
+ "name": "CtsShortFgsTestCases_pm_Presubmit"
},
{
"name": "FrameworksServicesTests_android_server_am_Presubmit"
@@ -73,23 +51,14 @@
},
{
"file_patterns": ["Broadcast.*"],
- "name": "CtsBroadcastTestCases",
- "options": [
- { "exclude-annotation": "androidx.test.filters.LargeTest" },
- { "exclude-annotation": "androidx.test.filters.FlakyTest" },
- { "exclude-annotation": "org.junit.Ignore" }
- ]
+ "name": "CtsBroadcastTestCases_android_server_am"
},
{
- "name": "CtsBRSTestCases",
"file_patterns": [
"ActivityManagerService\\.java",
"BroadcastQueue\\.java"
],
- "options": [
- { "exclude-annotation": "androidx.test.filters.FlakyTest" },
- { "exclude-annotation": "org.junit.Ignore" }
- ]
+ "name": "CtsBRSTestCases"
}
],
"postsubmit": [
@@ -110,13 +79,7 @@
]
},
{
- "name": "CtsStatsdAtomHostTestCases",
- "options": [
- { "include-filter": "android.cts.statsdatom.appexit.AppExitHostTest" },
- { "exclude-annotation": "androidx.test.filters.LargeTest" },
- { "exclude-annotation": "androidx.test.filters.FlakyTest" },
- { "exclude-annotation": "org.junit.Ignore" }
- ]
+ "name": "CtsStatsdAtomHostTestCases_appexit_appexithosttest"
},
{
"name": "CtsContentTestCases",
diff --git a/services/core/java/com/android/server/app/TEST_MAPPING b/services/core/java/com/android/server/app/TEST_MAPPING
index b718ce6..9e76175 100644
--- a/services/core/java/com/android/server/app/TEST_MAPPING
+++ b/services/core/java/com/android/server/app/TEST_MAPPING
@@ -1,26 +1,10 @@
{
"presubmit": [
{
- "name": "CtsGameManagerTestCases",
- "options": [
- {
- "exclude-annotation": "androidx.test.filters.FlakyTest"
- }
- ]
+ "name": "CtsGameManagerTestCases"
},
{
- "name": "CtsStatsdAtomHostTestCases",
- "options": [
- {
- "exclude-annotation": "androidx.test.filters.FlakyTest"
- },
- {
- "exclude-annotation": "org.junit.Ignore"
- },
- {
- "include-filter": "android.cts.statsdatom.gamemanager"
- }
- ],
+ "name": "CtsStatsdAtomHostTestCases_statsdatom_gamemanager",
"file_patterns": [
"(/|^)GameManagerService.java"
]
@@ -29,18 +13,7 @@
"name": "FrameworksMockingServicesTests_android_server_app"
},
{
- "name": "FrameworksCoreGameManagerTests",
- "options": [
- {
- "exclude-annotation": "androidx.test.filters.FlakyTest"
- },
- {
- "exclude-annotation": "org.junit.Ignore"
- },
- {
- "include-filter": "android.app"
- }
- ],
+ "name": "FrameworksCoreGameManagerTests_android_app",
"file_patterns": [
"(/|^)GameManagerService.java", "(/|^)GameManagerSettings.java"
]
diff --git a/services/core/java/com/android/server/appop/TEST_MAPPING b/services/core/java/com/android/server/appop/TEST_MAPPING
index 9317c1e..25dd30b 100644
--- a/services/core/java/com/android/server/appop/TEST_MAPPING
+++ b/services/core/java/com/android/server/appop/TEST_MAPPING
@@ -1,12 +1,7 @@
{
"presubmit": [
{
- "name": "CtsAppOpsTestCases",
- "options": [
- {
- "exclude-annotation": "androidx.test.filters.FlakyTest"
- }
- ]
+ "name": "CtsAppOpsTestCases"
},
{
"name": "CtsAppOps2TestCases"
@@ -21,12 +16,7 @@
"name": "CtsPermissionTestCases_Platform"
},
{
- "name": "CtsAppTestCases",
- "options": [
- {
- "include-filter": "android.app.cts.ActivityManagerApi29Test"
- }
- ]
+ "name": "CtsAppTestCases_cts_activitymanagerapi29test"
},
{
"name": "CtsStatsdAtomHostTestCases",
diff --git a/services/core/java/com/android/server/attention/TEST_MAPPING b/services/core/java/com/android/server/attention/TEST_MAPPING
index e5b0344..519ed07 100644
--- a/services/core/java/com/android/server/attention/TEST_MAPPING
+++ b/services/core/java/com/android/server/attention/TEST_MAPPING
@@ -1,24 +1,7 @@
{
"presubmit": [
{
- "name": "CtsVoiceInteractionTestCases",
- "options": [
- {
- "include-filter": "android.voiceinteraction.cts.AlwaysOnHotwordDetectorTest"
- },
- {
- "include-filter": "android.voiceinteraction.cts.unittests.HotwordDetectedResultTest"
- },
- {
- "include-filter": "android.voiceinteraction.cts.HotwordDetectionServiceBasicTest"
- },
- {
- "include-filter": "android.voiceinteraction.cts.HotwordDetectionServiceProximityTest"
- },
- {
- "exclude-annotation": "androidx.test.filters.FlakyTest"
- }
- ]
+ "name": "CtsVoiceInteractionTestCases_android_server_attention"
}
]
}
diff --git a/services/core/java/com/android/server/display/TEST_MAPPING b/services/core/java/com/android/server/display/TEST_MAPPING
index 049b2fd..4d7962f 100644
--- a/services/core/java/com/android/server/display/TEST_MAPPING
+++ b/services/core/java/com/android/server/display/TEST_MAPPING
@@ -1,21 +1,12 @@
{
"presubmit": [
{
- "name": "DisplayServiceTests",
- "options": [
- {"include-filter": "com.android.server.display"},
- {"exclude-annotation": "androidx.test.filters.FlakyTest"},
- {"exclude-annotation": "org.junit.Ignore"}
- ]
+ "name": "DisplayServiceTests_server_display"
}
],
"postsubmit": [
{
- "name": "DisplayServiceTests",
- "options": [
- {"include-filter": "com.android.server.display"},
- {"exclude-annotation": "org.junit.Ignore"}
- ]
+ "name": "DisplayServiceTests_server_display"
}
]
}
diff --git a/services/core/java/com/android/server/hdmi/TEST_MAPPING b/services/core/java/com/android/server/hdmi/TEST_MAPPING
index d116087d..bacacaf 100644
--- a/services/core/java/com/android/server/hdmi/TEST_MAPPING
+++ b/services/core/java/com/android/server/hdmi/TEST_MAPPING
@@ -12,18 +12,7 @@
// Postsubmit tests for TV devices
"tv-postsubmit": [
{
- "name": "HdmiCecTests",
- "options": [
- {
- "exclude-annotation": "androidx.test.filters.FlakyTest"
- },
- {
- "exclude-annotation": "org.junit.Ignore"
- },
- {
- "include-filter": "android.hardware.hdmi"
- }
- ],
+ "name": "HdmiCecTests_hardware_hdmi",
"file_patterns": [
"(/|^)DeviceFeature[^/]*", "(/|^)Hdmi[^/]*"
]
diff --git a/services/core/java/com/android/server/lights/TEST_MAPPING b/services/core/java/com/android/server/lights/TEST_MAPPING
index 1d2cd3c..8abdf00 100644
--- a/services/core/java/com/android/server/lights/TEST_MAPPING
+++ b/services/core/java/com/android/server/lights/TEST_MAPPING
@@ -1,12 +1,7 @@
{
"presubmit": [
{
- "name": "CtsHardwareTestCases",
- "options": [
- {"include-filter": "com.android.hardware.lights"},
- {"exclude-annotation": "androidx.test.filters.FlakyTest"},
- {"exclude-annotation": "androidx.test.filters.LargeTest"}
- ]
+ "name": "CtsHardwareTestCases_hardware_lights"
},
{
"name": "FrameworksServicesTests_android_server_lights"
diff --git a/services/core/java/com/android/server/location/TEST_MAPPING b/services/core/java/com/android/server/location/TEST_MAPPING
index 64b1ed2..b2ac7d1 100644
--- a/services/core/java/com/android/server/location/TEST_MAPPING
+++ b/services/core/java/com/android/server/location/TEST_MAPPING
@@ -1,13 +1,7 @@
{
"presubmit": [
{
- "name": "CtsLocationFineTestCases",
- "options": [
- {
- // TODO: Wait for test to deflake - b/293934372
- "exclude-filter":"android.location.cts.fine.ScanningSettingsTest"
- }
- ]
+ "name": "CtsLocationFineTestCases_android_server_location"
},
{
"name": "CtsLocationCoarseTestCases"
diff --git a/services/core/java/com/android/server/locksettings/Android.bp b/services/core/java/com/android/server/locksettings/Android.bp
new file mode 100644
index 0000000..53f1ac6
--- /dev/null
+++ b/services/core/java/com/android/server/locksettings/Android.bp
@@ -0,0 +1,11 @@
+aconfig_declarations {
+ name: "locksettings_flags",
+ package: "com.android.server.locksettings",
+ container: "system",
+ srcs: ["*.aconfig"],
+}
+
+java_aconfig_library {
+ name: "locksettings_flags_lib",
+ aconfig_declarations: "locksettings_flags",
+}
diff --git a/services/core/java/com/android/server/locksettings/RebootEscrowManager.java b/services/core/java/com/android/server/locksettings/RebootEscrowManager.java
index f44b852..820c0ef 100644
--- a/services/core/java/com/android/server/locksettings/RebootEscrowManager.java
+++ b/services/core/java/com/android/server/locksettings/RebootEscrowManager.java
@@ -273,11 +273,6 @@
"server_based_ror_enabled", false);
}
- public boolean waitForInternet() {
- return DeviceConfig.getBoolean(
- DeviceConfig.NAMESPACE_OTA, "wait_for_internet_ror", false);
- }
-
public boolean isNetworkConnected() {
final ConnectivityManager connectivityManager =
mContext.getSystemService(ConnectivityManager.class);
@@ -433,7 +428,7 @@
/** Wrapper function to set error code serialized through handler, */
private void setLoadEscrowDataErrorCode(@RebootEscrowErrorCode int value, Handler handler) {
- if (mInjector.waitForInternet()) {
+ if (Flags.waitForInternetRor()) {
mInjector.post(
handler,
() -> {
@@ -516,7 +511,7 @@
mWakeLock.acquire(mInjector.getWakeLockTimeoutMillis());
}
- if (mInjector.waitForInternet()) {
+ if (Flags.waitForInternetRor()) {
// Timeout to stop retrying same as the wake lock timeout.
mInjector.postDelayed(
retryHandler,
@@ -553,7 +548,7 @@
return;
}
- if (mInjector.waitForInternet()) {
+ if (Flags.waitForInternetRor()) {
if (mRebootEscrowTimedOut) {
Slog.w(TAG, "Failed to load reboot escrow data within timeout");
compareAndSetLoadEscrowDataErrorCode(
diff --git a/services/core/java/com/android/server/locksettings/TEST_MAPPING b/services/core/java/com/android/server/locksettings/TEST_MAPPING
index ffbdf7f..d338c50 100644
--- a/services/core/java/com/android/server/locksettings/TEST_MAPPING
+++ b/services/core/java/com/android/server/locksettings/TEST_MAPPING
@@ -1,15 +1,7 @@
{
"presubmit-large": [
{
- "name": "CtsDevicePolicyManagerTestCases",
- "options": [
- {
- "include-annotation": "com.android.cts.devicepolicy.annotations.LockSettingsTest"
- },
- {
- "exclude-annotation": "androidx.test.filters.FlakyTest"
- }
- ]
+ "name": "CtsDevicePolicyManagerTestCases_LockSettingsTest"
}
],
"presubmit": [
diff --git a/services/core/java/com/android/server/locksettings/flags.aconfig b/services/core/java/com/android/server/locksettings/flags.aconfig
new file mode 100644
index 0000000..6818de9
--- /dev/null
+++ b/services/core/java/com/android/server/locksettings/flags.aconfig
@@ -0,0 +1,9 @@
+package: "com.android.server.locksettings"
+container: "system"
+
+flag {
+ name: "wait_for_internet_ror"
+ namespace: "sudo"
+ description: "Feature flag to wait for internet connectivity before calling resume on reboot server."
+ bug: "231660348"
+}
\ No newline at end of file
diff --git a/services/core/java/com/android/server/media/projection/TEST_MAPPING b/services/core/java/com/android/server/media/projection/TEST_MAPPING
index 7aa9118..b33097c 100644
--- a/services/core/java/com/android/server/media/projection/TEST_MAPPING
+++ b/services/core/java/com/android/server/media/projection/TEST_MAPPING
@@ -1,15 +1,7 @@
{
"presubmit": [
{
- "name": "MediaProjectionTests",
- "options": [
- {
- "exclude-annotation": "androidx.test.filters.FlakyTest"
- },
- {
- "exclude-annotation": "org.junit.Ignore"
- }
- ]
+ "name": "MediaProjectionTests"
}
]
}
diff --git a/services/core/java/com/android/server/net/TEST_MAPPING b/services/core/java/com/android/server/net/TEST_MAPPING
index ad6b0ca..d95849e 100644
--- a/services/core/java/com/android/server/net/TEST_MAPPING
+++ b/services/core/java/com/android/server/net/TEST_MAPPING
@@ -1,40 +1,16 @@
{
"presubmit-large": [
{
- "name": "CtsHostsideNetworkPolicyTests",
- "options": [
- {
- "exclude-annotation": "androidx.test.filters.FlakyTest"
- },
- {
- "exclude-annotation": "android.platform.test.annotations.FlakyTest"
- }
- ]
+ "name": "CtsHostsideNetworkPolicyTests"
}
],
"presubmit": [
{
- "name": "FrameworksServicesTests",
- "file_patterns": ["(/|^)Network(Policy|Management)[^/]*\\.java"],
- "options": [
- {
- "include-filter": "com.android.server.net."
- },
- {
- "include-annotation": "android.platform.test.annotations.Presubmit"
- },
- {
- "exclude-annotation": "androidx.test.filters.FlakyTest"
- }
- ]
+ "name": "FrameworksServicesTests_android_server_net_Presubmit",
+ "file_patterns": ["(/|^)Network(Policy|Management)[^/]*\\.java"]
},
{
- "name": "FrameworksVpnTests",
- "options": [
- {
- "exclude-annotation": "com.android.testutils.SkipPresubmit"
- }
- ],
+ "name": "FrameworksVpnTests_android_server_connectivity",
"file_patterns": ["VpnManagerService\\.java"]
}
]
diff --git a/services/core/java/com/android/server/notification/TEST_MAPPING b/services/core/java/com/android/server/notification/TEST_MAPPING
index 468c451..dc7129cd 100644
--- a/services/core/java/com/android/server/notification/TEST_MAPPING
+++ b/services/core/java/com/android/server/notification/TEST_MAPPING
@@ -1,32 +1,10 @@
{
"presubmit": [
{
- "name": "CtsNotificationTestCases",
- "options": [
- {
- "exclude-annotation": "androidx.test.filters.FlakyTest"
- },
- {
- "exclude-annotation": "org.junit.Ignore"
- },
- {
- "exclude-annotation": "androidx.test.filters.LargeTest"
- }
- ]
+ "name": "CtsNotificationTestCases_notification"
},
{
- "name": "FrameworksUiServicesTests",
- "options": [
- {
- "exclude-annotation": "androidx.test.filters.FlakyTest"
- },
- {
- "exclude-annotation": "org.junit.Ignore"
- },
- {
- "exclude-annotation": "androidx.test.filters.LargeTest"
- }
- ]
+ "name": "FrameworksUiServicesTests_notification"
}
],
"postsubmit": [
diff --git a/services/core/java/com/android/server/os/TEST_MAPPING b/services/core/java/com/android/server/os/TEST_MAPPING
index 50c8964..3ffcd18 100644
--- a/services/core/java/com/android/server/os/TEST_MAPPING
+++ b/services/core/java/com/android/server/os/TEST_MAPPING
@@ -2,36 +2,18 @@
"presubmit": [
{
"file_patterns": ["Bugreport[^/]*\\.java"],
- "name": "BugreportManagerTestCases",
- "options": [
- {
- "exclude-annotation": "androidx.test.filters.LargeTest"
- }
- ]
+ "name": "BugreportManagerTestCases_android_server_os"
},
{
"file_patterns": ["Bugreport[^/]*\\.java"],
- "name": "CtsBugreportTestCases",
- "options": [
- {
- "exclude-annotation": "androidx.test.filters.LargeTest"
- }
- ]
+ "name": "CtsBugreportTestCases_android_server_os"
},
{
"name": "CtsUsbTests"
},
{
"file_patterns": ["Bugreport[^/]*\\.java"],
- "name": "ShellTests",
- "options": [
- {
- "exclude-annotation": "androidx.test.filters.LargeTest"
- },
- {
- "exclude-annotation": "androidx.test.filters.FlakyTest"
- }
- ]
+ "name": "ShellTests_android_server_os"
}
],
"postsubmit": [
diff --git a/services/core/java/com/android/server/pm/verify/domain/TEST_MAPPING b/services/core/java/com/android/server/pm/verify/domain/TEST_MAPPING
index 8a1982a..db98c40 100644
--- a/services/core/java/com/android/server/pm/verify/domain/TEST_MAPPING
+++ b/services/core/java/com/android/server/pm/verify/domain/TEST_MAPPING
@@ -1,12 +1,7 @@
{
"presubmit": [
{
- "name": "PackageManagerServiceUnitTests",
- "options": [
- {
- "include-filter": "com.android.server.pm.test.verify.domain"
- }
- ]
+ "name": "PackageManagerServiceUnitTests_verify_domain"
},
{
"name": "CtsDomainVerificationDeviceStandaloneTestCases"
diff --git a/services/core/java/com/android/server/policy/TEST_MAPPING b/services/core/java/com/android/server/policy/TEST_MAPPING
index bdb174d..76a0503 100644
--- a/services/core/java/com/android/server/policy/TEST_MAPPING
+++ b/services/core/java/com/android/server/policy/TEST_MAPPING
@@ -1,32 +1,10 @@
{
"presubmit": [
{
- "name": "FrameworksServicesTests",
- "options": [
- {
- "include-filter": "com.android.server.policy."
- },
- {
- "include-annotation": "android.platform.test.annotations.Presubmit"
- },
- {
- "exclude-annotation": "androidx.test.filters.FlakyTest"
- }
- ]
+ "name": "FrameworksServicesTests_android_server_policy_Presubmit"
},
{
- "name": "WmTests",
- "options": [
- {
- "include-filter": "com.android.server.policy."
- },
- {
- "include-annotation": "android.platform.test.annotations.Presubmit"
- },
- {
- "exclude-annotation": "androidx.test.filters.FlakyTest"
- }
- ]
+ "name": "WmTests_server_policy_Presubmit"
},
{
"name": "CtsPermissionPolicyTestCases",
@@ -49,30 +27,15 @@
"name": "CtsPermissionTestCases_Platform"
},
{
- "name": "CtsBackupTestCases",
- "options": [
- {
- "include-filter": "android.backup.cts.PermissionTest"
- }
- ]
+ "name": "CtsBackupTestCases_cts_permissiontest"
}
],
"postsubmit": [
{
- "name": "FrameworksServicesTests",
- "options": [
- {
- "include-filter": "com.android.server.policy."
- }
- ]
+ "name": "FrameworksServicesTests_android_server_policy"
},
{
- "name": "WmTests",
- "options": [
- {
- "include-filter": "com.android.server.policy."
- }
- ]
+ "name": "WmTests_server_policy"
},
{
"name": "CtsPermissionPolicyTestCases",
diff --git a/services/core/java/com/android/server/power/TEST_MAPPING b/services/core/java/com/android/server/power/TEST_MAPPING
index 935a238..f67f56d 100644
--- a/services/core/java/com/android/server/power/TEST_MAPPING
+++ b/services/core/java/com/android/server/power/TEST_MAPPING
@@ -1,22 +1,13 @@
{
"presubmit": [
{
- "name": "CtsBatterySavingTestCases",
- "options": [
- {"exclude-annotation": "androidx.test.filters.FlakyTest"},
- {"exclude-annotation": "androidx.test.filters.LargeTest"}
- ]
+ "name": "CtsBatterySavingTestCases_android_server_power"
},
{
"name": "FrameworksMockingServicesTests_android_server_power_Presubmit"
},
{
- "name": "PowerServiceTests",
- "options": [
- {"include-filter": "com.android.server.power"},
- {"exclude-annotation": "androidx.test.filters.FlakyTest"},
- {"exclude-annotation": "org.junit.Ignore"}
- ]
+ "name": "PowerServiceTests_server_power"
}
],
"postsubmit": [
@@ -24,28 +15,16 @@
"name": "CtsBatterySavingTestCases"
},
{
- "name": "FrameworksMockingServicesTests",
- "options": [
- {"include-filter": "com.android.server.power"}
- ]
+ "name": "FrameworksMockingServicesTests_android_server_power"
},
{
"name": "FrameworksServicesTests_android_server_power"
},
{
- "name": "PowerServiceTests",
- "options": [
- {"include-filter": "com.android.server.power"},
- {"exclude-annotation": "org.junit.Ignore"}
- ]
+ "name": "PowerServiceTests_server_power"
},
{
- "name": "CtsStatsdAtomHostTestCases",
- "options": [
- {"exclude-annotation": "androidx.test.filters.FlakyTest"},
- {"exclude-annotation": "org.junit.Ignore"},
- {"include-filter": "android.cts.statsdatom.powermanager"}
- ],
+ "name": "CtsStatsdAtomHostTestCases_statsdatom_powermanager",
"file_patterns": [
"(/|^)ThermalManagerService.java"
]
diff --git a/services/core/java/com/android/server/security/AttestationVerificationPeerDeviceVerifier.java b/services/core/java/com/android/server/security/AttestationVerificationPeerDeviceVerifier.java
index 945a340..41e3d00 100644
--- a/services/core/java/com/android/server/security/AttestationVerificationPeerDeviceVerifier.java
+++ b/services/core/java/com/android/server/security/AttestationVerificationPeerDeviceVerifier.java
@@ -17,6 +17,7 @@
package com.android.server.security;
import static android.security.attestationverification.AttestationVerificationManager.PARAM_CHALLENGE;
+import static android.security.attestationverification.AttestationVerificationManager.PARAM_MAX_PATCH_LEVEL_DIFF_MONTHS;
import static android.security.attestationverification.AttestationVerificationManager.PARAM_PUBLIC_KEY;
import static android.security.attestationverification.AttestationVerificationManager.RESULT_FAILURE;
import static android.security.attestationverification.AttestationVerificationManager.RESULT_SUCCESS;
@@ -174,8 +175,8 @@
MyDumpData dumpData = new MyDumpData();
- int result =
- verifyAttestationInternal(localBindingType, requirements, attestation, dumpData);
+ int result = verifyAttestationInternal(localBindingType, requirements, attestation,
+ dumpData);
dumpData.mResult = result;
mDumpLogger.logAttempt(dumpData);
return result;
@@ -222,7 +223,8 @@
final var attestationExtension = fromCertificate(leafCertificate);
// Second: verify if the attestation satisfies the "peer device" profile.
- if (!checkAttestationForPeerDeviceProfile(attestationExtension, dumpData)) {
+ if (!checkAttestationForPeerDeviceProfile(requirements, attestationExtension,
+ dumpData)) {
failed = true;
}
@@ -400,6 +402,7 @@
}
private boolean checkAttestationForPeerDeviceProfile(
+ @NonNull Bundle requirements,
@NonNull AndroidKeystoreAttestationVerificationAttributes attestationAttributes,
MyDumpData dumpData) {
boolean result = true;
@@ -461,30 +464,37 @@
result = false;
}
- // Patch level integer YYYYMM is expected to be within 1 year of today.
- if (!isValidPatchLevel(attestationAttributes.getKeyOsPatchLevel())) {
+ int maxPatchLevelDiffMonths = requirements.getInt(PARAM_MAX_PATCH_LEVEL_DIFF_MONTHS,
+ MAX_PATCH_AGE_MONTHS);
+
+ // Patch level integer YYYYMM is expected to be within maxPatchLevelDiffMonths of today.
+ if (!isValidPatchLevel(attestationAttributes.getKeyOsPatchLevel(),
+ maxPatchLevelDiffMonths)) {
debugVerboseLog("OS patch level is not within valid range.");
result = false;
} else {
dumpData.mOsPatchLevelInRange = true;
}
- // Patch level integer YYYYMMDD is expected to be within 1 year of today.
- if (!isValidPatchLevel(attestationAttributes.getKeyBootPatchLevel())) {
+ // Patch level integer YYYYMMDD is expected to be within maxPatchLevelDiffMonths of today.
+ if (!isValidPatchLevel(attestationAttributes.getKeyBootPatchLevel(),
+ maxPatchLevelDiffMonths)) {
debugVerboseLog("Boot patch level is not within valid range.");
result = false;
} else {
dumpData.mKeyBootPatchLevelInRange = true;
}
- if (!isValidPatchLevel(attestationAttributes.getKeyVendorPatchLevel())) {
+ if (!isValidPatchLevel(attestationAttributes.getKeyVendorPatchLevel(),
+ maxPatchLevelDiffMonths)) {
debugVerboseLog("Vendor patch level is not within valid range.");
result = false;
} else {
dumpData.mKeyVendorPatchLevelInRange = true;
}
- if (!isValidPatchLevel(attestationAttributes.getKeyBootPatchLevel())) {
+ if (!isValidPatchLevel(attestationAttributes.getKeyBootPatchLevel(),
+ maxPatchLevelDiffMonths)) {
debugVerboseLog("Boot patch level is not within valid range.");
result = false;
} else {
@@ -525,7 +535,7 @@
* is not enough. Therefore, we also confirm the patch level for the remote and local device are
* similar.
*/
- private boolean isValidPatchLevel(int patchLevel) {
+ private boolean isValidPatchLevel(int patchLevel, int maxPatchLevelDiffMonths) {
LocalDate currentDate = mTestSystemDate != null
? mTestSystemDate : LocalDate.now(ZoneId.systemDefault());
@@ -543,7 +553,9 @@
return false;
}
- // Check local patch date is not in last year of system clock.
+ // Check local patch date is not in last year of system clock. If the local patch already
+ // has a year's worth of bugs and vulnerabilities, it has no security meanings to check the
+ // remote patch level.
if (ChronoUnit.MONTHS.between(localPatchDate, currentDate) > MAX_PATCH_AGE_MONTHS) {
return true;
}
@@ -559,19 +571,9 @@
int patchMonth = Integer.parseInt(remoteDeviceDateStr.substring(4, 6));
LocalDate remotePatchDate = LocalDate.of(patchYear, patchMonth, 1);
- // Check patch dates are within 1 year of each other
- boolean IsRemotePatchWithinOneYearOfLocalPatch;
- if (remotePatchDate.compareTo(localPatchDate) > 0) {
- IsRemotePatchWithinOneYearOfLocalPatch = ChronoUnit.MONTHS.between(
- localPatchDate, remotePatchDate) <= MAX_PATCH_AGE_MONTHS;
- } else if (remotePatchDate.compareTo(localPatchDate) < 0) {
- IsRemotePatchWithinOneYearOfLocalPatch = ChronoUnit.MONTHS.between(
- remotePatchDate, localPatchDate) <= MAX_PATCH_AGE_MONTHS;
- } else {
- IsRemotePatchWithinOneYearOfLocalPatch = true;
- }
-
- return IsRemotePatchWithinOneYearOfLocalPatch;
+ // Check patch dates are within the max patch level diff of each other
+ return Math.abs(ChronoUnit.MONTHS.between(localPatchDate, remotePatchDate))
+ <= maxPatchLevelDiffMonths;
}
/**
diff --git a/services/core/java/com/android/server/security/TEST_MAPPING b/services/core/java/com/android/server/security/TEST_MAPPING
index 29d52ff..284e08e 100644
--- a/services/core/java/com/android/server/security/TEST_MAPPING
+++ b/services/core/java/com/android/server/security/TEST_MAPPING
@@ -1,12 +1,7 @@
{
"presubmit": [
{
- "name": "CtsSecurityTestCases",
- "options": [
- {
- "include-filter": "android.security.cts.FileIntegrityManagerTest"
- }
- ],
+ "name": "CtsSecurityTestCases_cts_fileintegritymanagertest",
"file_patterns": ["FileIntegrity[^/]*\\.java"]
}
]
diff --git a/services/core/java/com/android/server/statusbar/TEST_MAPPING b/services/core/java/com/android/server/statusbar/TEST_MAPPING
index 67ea557..8c7e74c 100644
--- a/services/core/java/com/android/server/statusbar/TEST_MAPPING
+++ b/services/core/java/com/android/server/statusbar/TEST_MAPPING
@@ -1,29 +1,10 @@
{
"presubmit": [
{
- "name": "CtsTileServiceTestCases",
- "options": [
- {
- "exclude-annotation": "org.junit.Ignore"
- },
- {
- "exclude-annotation": "androidx.test.filters.FlakyTest"
- }
- ]
+ "name": "CtsTileServiceTestCases"
},
{
- "name": "CtsAppTestCases",
- "options": [
- {
- "exclude-annotation": "org.junit.Ignore"
- },
- {
- "exclude-annotation": "androidx.test.filters.FlakyTest"
- },
- {
- "include-filter": "android.app.cts.RequestTileServiceAddTest"
- }
- ]
+ "name": "CtsAppTestCases_cts_requesttileserviceaddtest"
}
]
}
\ No newline at end of file
diff --git a/services/core/java/com/android/server/timedetector/TEST_MAPPING b/services/core/java/com/android/server/timedetector/TEST_MAPPING
index 17d327e..f57b819 100644
--- a/services/core/java/com/android/server/timedetector/TEST_MAPPING
+++ b/services/core/java/com/android/server/timedetector/TEST_MAPPING
@@ -1,12 +1,7 @@
{
"presubmit": [
{
- "name": "CtsTimeTestCases",
- "options": [
- {
- "exclude-annotation": "androidx.test.filters.FlakyTest"
- }
- ]
+ "name": "CtsTimeTestCases"
},
{
"name": "FrameworksTimeServicesTests"
diff --git a/services/core/java/com/android/server/timezonedetector/TEST_MAPPING b/services/core/java/com/android/server/timezonedetector/TEST_MAPPING
index 004d7996..a237c34 100644
--- a/services/core/java/com/android/server/timezonedetector/TEST_MAPPING
+++ b/services/core/java/com/android/server/timezonedetector/TEST_MAPPING
@@ -1,12 +1,7 @@
{
"presubmit": [
{
- "name": "CtsTimeTestCases",
- "options": [
- {
- "exclude-annotation": "androidx.test.filters.FlakyTest"
- }
- ]
+ "name": "CtsTimeTestCases"
},
{
"name": "FrameworksTimeServicesTests"
diff --git a/services/core/java/com/android/server/trust/TEST_MAPPING b/services/core/java/com/android/server/trust/TEST_MAPPING
index 0de7c28..4c08455 100644
--- a/services/core/java/com/android/server/trust/TEST_MAPPING
+++ b/services/core/java/com/android/server/trust/TEST_MAPPING
@@ -1,41 +1,17 @@
{
"presubmit": [
{
- "name": "TrustTests",
- "options": [
- {
- "include-filter": "android.trust.test"
- },
- {
- "exclude-annotation": "androidx.test.filters.FlakyTest"
- }
- ]
+ "name": "TrustTests_trust_test"
}
],
"postsubmit": [
{
- "name": "FrameworksMockingServicesTests",
- "options": [
- {
- "include-filter": "com.android.server.trust"
- },
- {
- "exclude-annotation": "androidx.test.filters.FlakyTest"
- }
- ]
+ "name": "FrameworksMockingServicesTests_android_server_trust"
}
],
"trust-tablet": [
{
- "name": "TrustTests",
- "options": [
- {
- "include-filter": "android.trust.test"
- },
- {
- "exclude-annotation": "androidx.test.filters.FlakyTest"
- }
- ]
+ "name": "TrustTests_trust_test"
}
]
}
\ No newline at end of file
diff --git a/services/core/java/com/android/server/uri/TEST_MAPPING b/services/core/java/com/android/server/uri/TEST_MAPPING
index 0d756bb..45e3051 100644
--- a/services/core/java/com/android/server/uri/TEST_MAPPING
+++ b/services/core/java/com/android/server/uri/TEST_MAPPING
@@ -4,24 +4,7 @@
"name": "FrameworksServicesTests_android_server_uri"
},
{
- "name": "CtsStorageHostTestCases",
- "options": [
- {
- "include-filter": "android.appsecurity.cts.ExternalStorageHostTest#testGrantUriPermission"
- },
- {
- "include-filter": "android.appsecurity.cts.ExternalStorageHostTest#testGrantUriPermission29"
- },
- {
- "include-filter": "android.appsecurity.cts.ExternalStorageHostTest#testMediaNone"
- },
- {
- "include-filter": "android.appsecurity.cts.ExternalStorageHostTest#testMediaNone28"
- },
- {
- "include-filter": "android.appsecurity.cts.ExternalStorageHostTest#testMediaNone29"
- }
- ]
+ "name": "CtsStorageHostTestCases_android_server_uri"
}
],
"postsubmit": [
@@ -34,12 +17,7 @@
]
},
{
- "name": "CtsWindowManagerDeviceWindow",
- "options": [
- {
- "include-filter": "android.server.wm.window.CrossAppDragAndDropTests"
- }
- ]
+ "name": "CtsWindowManagerDeviceWindow_window_crossappdraganddroptests"
}
]
}
diff --git a/services/core/java/com/android/server/wm/ActivityRecord.java b/services/core/java/com/android/server/wm/ActivityRecord.java
index 8c23eaa..185dd0c 100644
--- a/services/core/java/com/android/server/wm/ActivityRecord.java
+++ b/services/core/java/com/android/server/wm/ActivityRecord.java
@@ -8152,13 +8152,17 @@
* into account orientation per-app overrides applied by the device manufacturers.
*/
@Override
+ @ActivityInfo.ScreenOrientation
protected int getOverrideOrientation() {
- if (mWmService.mConstants.mIgnoreActivityOrientationRequest
- && info.applicationInfo.category != ApplicationInfo.CATEGORY_GAME) {
- return ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED;
+ final int candidateOrientation;
+ if (!mWmService.mConstants.mIgnoreActivityOrientationRequest
+ || info.applicationInfo.category == ApplicationInfo.CATEGORY_GAME) {
+ candidateOrientation = super.getOverrideOrientation();
+ } else {
+ candidateOrientation = ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED;
}
return mAppCompatController.getOrientationPolicy()
- .overrideOrientationIfNeeded(super.getOverrideOrientation());
+ .overrideOrientationIfNeeded(candidateOrientation);
}
/**
diff --git a/services/core/java/com/android/server/wm/AppCompatConfigurationPersister.java b/services/core/java/com/android/server/wm/AppCompatConfigurationPersister.java
index 852ce04..9c861fe 100644
--- a/services/core/java/com/android/server/wm/AppCompatConfigurationPersister.java
+++ b/services/core/java/com/android/server/wm/AppCompatConfigurationPersister.java
@@ -16,16 +16,13 @@
package com.android.server.wm;
-import static android.os.StrictMode.setThreadPolicy;
-
import static com.android.server.wm.WindowManagerDebugConfig.TAG_WITH_CLASS_NAME;
import static com.android.server.wm.WindowManagerDebugConfig.TAG_WM;
+import android.annotation.MainThread;
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.os.Environment;
-import android.os.StrictMode;
-import android.os.StrictMode.ThreadPolicy;
import android.util.AtomicFile;
import android.util.Slog;
@@ -122,7 +119,7 @@
final File prefFiles = new File(configFolder, letterboxConfigurationFileName);
mConfigurationFile = new AtomicFile(prefFiles);
mPersisterQueue = persisterQueue;
- runWithDiskReadsThreadPolicy(this::readCurrentConfiguration);
+ readCurrentConfiguration();
}
/**
@@ -212,6 +209,7 @@
mDefaultTabletopModeReachabilitySupplier.get();
}
+ @MainThread
private void readCurrentConfiguration() {
if (!mConfigurationFile.exists()) {
useDefaultValue();
@@ -272,20 +270,6 @@
}
}
- // The LetterboxConfigurationDeviceConfig needs to access the
- // file with the current reachability position once when the
- // device boots. Because DisplayThread uses allowIo=false
- // accessing a file triggers a DiskReadViolation.
- // Here we use StrictMode to allow the current thread to read
- // the AtomicFile once in the current thread restoring the
- // original ThreadPolicy after that.
- private void runWithDiskReadsThreadPolicy(Runnable runnable) {
- final ThreadPolicy currentPolicy = StrictMode.getThreadPolicy();
- setThreadPolicy(new ThreadPolicy.Builder().permitDiskReads().build());
- runnable.run();
- setThreadPolicy(currentPolicy);
- }
-
private static class UpdateValuesCommand implements
PersisterQueue.WriteQueueItem<UpdateValuesCommand> {
diff --git a/services/core/java/com/android/server/wm/DisplayContent.java b/services/core/java/com/android/server/wm/DisplayContent.java
index 10e0641..21212e5 100644
--- a/services/core/java/com/android/server/wm/DisplayContent.java
+++ b/services/core/java/com/android/server/wm/DisplayContent.java
@@ -707,6 +707,8 @@
@Retention(RetentionPolicy.SOURCE)
@interface InputMethodTarget {}
+ /** The surface parent window of the IME container. */
+ private WindowContainer mInputMethodSurfaceParentWindow;
/** The surface parent of the IME container. */
@VisibleForTesting
SurfaceControl mInputMethodSurfaceParent;
@@ -1529,6 +1531,10 @@
return mDisplayRotation.getLastOrientation();
}
+ WindowContainer getImeParentWindow() {
+ return mInputMethodSurfaceParentWindow;
+ }
+
void registerRemoteAnimations(RemoteAnimationDefinition definition) {
mAppTransitionController.registerRemoteAnimations(definition);
}
@@ -4733,13 +4739,17 @@
Slog.i(TAG_WM, "ImeContainer is organized. Skip updateImeParent.");
}
// Leave the ImeContainer where the DisplayAreaPolicy placed it.
- // FEATURE_IME is organized by vendor so they are responible for placing the surface.
+ // FEATURE_IME is organized by vendor so they are responsible for placing the surface.
+ mInputMethodSurfaceParentWindow = null;
mInputMethodSurfaceParent = null;
return;
}
- final SurfaceControl newParent = computeImeParent();
+ final var newParentWindow = computeImeParent();
+ final SurfaceControl newParent =
+ newParentWindow != null ? newParentWindow.getSurfaceControl() : null;
if (newParent != null && newParent != mInputMethodSurfaceParent) {
+ mInputMethodSurfaceParentWindow = newParentWindow;
mInputMethodSurfaceParent = newParent;
getSyncTransaction().reparent(mImeWindowsContainer.mSurfaceControl, newParent);
if (DEBUG_IME_VISIBILITY) {
@@ -4800,7 +4810,7 @@
* Computes the window the IME should be attached to.
*/
@VisibleForTesting
- SurfaceControl computeImeParent() {
+ WindowContainer computeImeParent() {
if (!ImeTargetVisibilityPolicy.canComputeImeParent(mImeLayeringTarget, mImeInputTarget)) {
return null;
}
@@ -4808,11 +4818,10 @@
// screen. If it's not covering the entire screen the IME might extend beyond the apps
// bounds.
if (shouldImeAttachedToApp()) {
- return mImeLayeringTarget.mActivityRecord.getSurfaceControl();
+ return mImeLayeringTarget.mActivityRecord;
}
// Otherwise, we just attach it to where the display area policy put it.
- return mImeWindowsContainer.getParent() != null
- ? mImeWindowsContainer.getParent().getSurfaceControl() : null;
+ return mImeWindowsContainer.getParent();
}
void setLayoutNeeded() {
diff --git a/services/core/java/com/android/server/wm/EmbeddedWindowController.java b/services/core/java/com/android/server/wm/EmbeddedWindowController.java
index 169a76f..5514294e 100644
--- a/services/core/java/com/android/server/wm/EmbeddedWindowController.java
+++ b/services/core/java/com/android/server/wm/EmbeddedWindowController.java
@@ -33,6 +33,7 @@
import android.util.proto.ProtoOutputStream;
import android.view.InputApplicationHandle;
import android.view.InputChannel;
+import android.view.WindowInsets;
import android.window.InputTransferToken;
import com.android.internal.protolog.ProtoLog;
@@ -222,6 +223,10 @@
private boolean mIsFocusable;
+ // The EmbeddedWindow can only request the IME. All other insets types are requested by
+ // the host window.
+ private @WindowInsets.Type.InsetsType int mRequestedVisibleTypes = 0;
+
/**
* @param session calling session to check ownership of the window
* @param clientToken client token used to clean up the map if the embedding process dies
@@ -311,6 +316,27 @@
}
@Override
+ public boolean isRequestedVisible(@WindowInsets.Type.InsetsType int types) {
+ return (mRequestedVisibleTypes & types) != 0;
+ }
+
+ @Override
+ public @WindowInsets.Type.InsetsType int getRequestedVisibleTypes() {
+ return mRequestedVisibleTypes;
+ }
+
+ /**
+ * Only the IME can be requested from the EmbeddedWindow.
+ * @param requestedVisibleTypes other types than {@link WindowInsets.Type.IME} are
+ * not sent to system server via WindowlessWindowManager.
+ */
+ void setRequestedVisibleTypes(@WindowInsets.Type.InsetsType int requestedVisibleTypes) {
+ if (mRequestedVisibleTypes != requestedVisibleTypes) {
+ mRequestedVisibleTypes = requestedVisibleTypes;
+ }
+ }
+
+ @Override
public int getPid() {
return mOwnerPid;
}
@@ -375,6 +401,11 @@
@Override
public boolean shouldControlIme() {
+ if (android.view.inputmethod.Flags.refactorInsetsController()) {
+ // EmbeddedWindow should never be able to control the IME directly, but only the
+ // RemoteInsetsControlTarget.
+ return false;
+ }
return mHostWindowState != null;
}
diff --git a/services/core/java/com/android/server/wm/ImeInsetsSourceProvider.java b/services/core/java/com/android/server/wm/ImeInsetsSourceProvider.java
index 43c3d05..e178203 100644
--- a/services/core/java/com/android/server/wm/ImeInsetsSourceProvider.java
+++ b/services/core/java/com/android/server/wm/ImeInsetsSourceProvider.java
@@ -268,7 +268,7 @@
// TODO(b/353463205) change statsToken to be NonNull, after the flag is permanently enabled
@Override
- protected boolean updateClientVisibility(InsetsControlTarget caller,
+ protected boolean updateClientVisibility(InsetsTarget caller,
@Nullable ImeTracker.Token statsToken) {
InsetsControlTarget controlTarget = getControlTarget();
if (caller != controlTarget) {
@@ -283,12 +283,13 @@
ImeTracker.forLogging().onProgress(statsToken,
ImeTracker.PHASE_WM_SET_REMOTE_TARGET_IME_VISIBILITY);
controlTarget.setImeInputTargetRequestedVisibility(imeVisible);
- } else {
+ } else if (caller instanceof InsetsControlTarget) {
// In case of a virtual display that cannot show the IME, the
// controlTarget will be null here, as no controlTarget was set yet. In
// that case, proceed similar to the multi window mode (fallback =
// RemoteInsetsControlTarget of the default display)
- controlTarget = mDisplayContent.getImeHostOrFallback(caller.getWindow());
+ controlTarget = mDisplayContent.getImeHostOrFallback(
+ ((InsetsControlTarget) caller).getWindow());
if (controlTarget != caller) {
ImeTracker.forLogging().onProgress(statsToken,
@@ -300,8 +301,7 @@
}
}
- WindowState windowState = caller.getWindow();
- invokeOnImeRequestedChangedListener(windowState, statsToken);
+ invokeOnImeRequestedChangedListener(caller, statsToken);
} else {
// TODO(b/353463205) add ImeTracker?
}
@@ -309,20 +309,16 @@
return false;
}
boolean changed = super.updateClientVisibility(caller, statsToken);
- if (!Flags.refactorInsetsController()) {
+ if (!Flags.refactorInsetsController() && caller instanceof InsetsControlTarget) {
if (changed && caller.isRequestedVisible(mSource.getType())) {
- reportImeDrawnForOrganizerIfNeeded(caller);
+ reportImeDrawnForOrganizerIfNeeded((InsetsControlTarget) caller);
}
}
changed |= mDisplayContent.onImeInsetsClientVisibilityUpdate();
if (Flags.refactorInsetsController()) {
if (changed) {
- // RemoteInsetsControlTarget does not have a window. In this case, we use the
- // windowState from the imeInputTarget
- WindowState windowState = caller.getWindow() != null ? caller.getWindow()
- : ((mDisplayContent.getImeInputTarget() != null)
- ? mDisplayContent.getImeInputTarget().getWindowState() : null);
- invokeOnImeRequestedChangedListener(windowState, statsToken);
+ invokeOnImeRequestedChangedListener(mDisplayContent.getImeInputTarget(),
+ statsToken);
} else {
// TODO(b/329229469) change phase and check cancelled / failed
ImeTracker.forLogging().onCancelled(statsToken,
@@ -334,32 +330,31 @@
void onInputTargetChanged(InputTarget target) {
if (Flags.refactorInsetsController() && target != null) {
- WindowState targetWin = target.getWindowState();
InsetsControlTarget imeControlTarget = getControlTarget();
- if (target != imeControlTarget && targetWin != null) {
+ if (target != imeControlTarget) {
// If the targetWin is not the imeControlTarget (=RemoteInsetsControlTarget) let it
// know about the new requestedVisibleTypes for the IME.
if (imeControlTarget != null) {
imeControlTarget.setImeInputTargetRequestedVisibility(
- (targetWin.getRequestedVisibleTypes() & WindowInsets.Type.ime()) != 0);
+ (target.getRequestedVisibleTypes() & WindowInsets.Type.ime()) != 0);
}
}
}
}
// TODO(b/353463205) check callers to see if we can make statsToken @NonNull
- private void invokeOnImeRequestedChangedListener(WindowState windowState,
+ private void invokeOnImeRequestedChangedListener(InsetsTarget insetsTarget,
@Nullable ImeTracker.Token statsToken) {
final var imeListener = mDisplayContent.mWmService.mOnImeRequestedChangedListener;
if (imeListener != null) {
- if (windowState != null) {
+ if (insetsTarget != null) {
ImeTracker.forLogging().onProgress(statsToken,
ImeTracker.PHASE_WM_POSTING_CHANGED_IME_VISIBILITY);
mDisplayContent.mWmService.mH.post(() -> {
ImeTracker.forLogging().onProgress(statsToken,
ImeTracker.PHASE_WM_INVOKING_IME_REQUESTED_LISTENER);
- imeListener.onImeRequestedChanged(windowState.mClient.asBinder(),
- windowState.isRequestedVisible(WindowInsets.Type.ime()), statsToken);
+ imeListener.onImeRequestedChanged(insetsTarget.getWindowToken(),
+ insetsTarget.isRequestedVisible(WindowInsets.Type.ime()), statsToken);
});
} else {
ImeTracker.forLogging().onFailed(statsToken,
@@ -676,7 +671,7 @@
return target == mDisplayContent.getImeFallback();
}
- private boolean isImeInputTarget(@NonNull InsetsControlTarget target) {
+ private boolean isImeInputTarget(@NonNull InsetsTarget target) {
return target == mDisplayContent.getImeInputTarget();
}
diff --git a/services/core/java/com/android/server/wm/InputTarget.java b/services/core/java/com/android/server/wm/InputTarget.java
index 0c0b794..40ce9db 100644
--- a/services/core/java/com/android/server/wm/InputTarget.java
+++ b/services/core/java/com/android/server/wm/InputTarget.java
@@ -16,7 +16,6 @@
package com.android.server.wm;
-import android.os.IBinder;
import android.util.proto.ProtoOutputStream;
/**
@@ -25,16 +24,13 @@
* Both WindowState and EmbeddedWindows can receive input. This consolidates some common properties
* of both targets.
*/
-interface InputTarget {
+interface InputTarget extends InsetsTarget {
/* Get the WindowState associated with the target. */
WindowState getWindowState();
/* Display id of the target. */
int getDisplayId();
- /* Client IWindow for the target. */
- IBinder getWindowToken();
-
/* Owning pid of the target. */
int getPid();
int getUid();
diff --git a/services/core/java/com/android/server/wm/InsetsControlTarget.java b/services/core/java/com/android/server/wm/InsetsControlTarget.java
index 07e249a..7043aacf 100644
--- a/services/core/java/com/android/server/wm/InsetsControlTarget.java
+++ b/services/core/java/com/android/server/wm/InsetsControlTarget.java
@@ -18,6 +18,7 @@
import android.annotation.Nullable;
import android.inputmethodservice.InputMethodService;
+import android.os.IBinder;
import android.view.WindowInsets;
import android.view.WindowInsets.Type.InsetsType;
import android.view.inputmethod.ImeTracker;
@@ -25,7 +26,7 @@
/**
* Generalization of an object that can control insets state.
*/
-interface InsetsControlTarget {
+interface InsetsControlTarget extends InsetsTarget {
/**
* Notifies the control target that the insets control has changed.
@@ -42,16 +43,17 @@
return null;
}
- /**
- * @return {@code true} if any of the {@link InsetsType} is requested visible by this target.
- */
+ @Override
+ default IBinder getWindowToken() {
+ return null;
+ }
+
+ @Override
default boolean isRequestedVisible(@InsetsType int types) {
return (WindowInsets.Type.defaultVisible() & types) != 0;
}
- /**
- * @return {@link InsetsType}s which are requested visible by this target.
- */
+ @Override
default @InsetsType int getRequestedVisibleTypes() {
return WindowInsets.Type.defaultVisible();
}
diff --git a/services/core/java/com/android/server/wm/InsetsPolicy.java b/services/core/java/com/android/server/wm/InsetsPolicy.java
index 129078b..b414a862 100644
--- a/services/core/java/com/android/server/wm/InsetsPolicy.java
+++ b/services/core/java/com/android/server/wm/InsetsPolicy.java
@@ -434,7 +434,7 @@
return originalState;
}
- void onRequestedVisibleTypesChanged(InsetsControlTarget caller,
+ void onRequestedVisibleTypesChanged(InsetsTarget caller,
@Nullable ImeTracker.Token statsToken) {
mStateController.onRequestedVisibleTypesChanged(caller, statsToken);
checkAbortTransient(caller);
@@ -449,7 +449,7 @@
*
* @param caller who changed the insets state.
*/
- private void checkAbortTransient(InsetsControlTarget caller) {
+ private void checkAbortTransient(InsetsTarget caller) {
if (mShowingTransientTypes == 0) {
return;
}
diff --git a/services/core/java/com/android/server/wm/InsetsSourceProvider.java b/services/core/java/com/android/server/wm/InsetsSourceProvider.java
index 8f90b2d..f0a4763 100644
--- a/services/core/java/com/android/server/wm/InsetsSourceProvider.java
+++ b/services/core/java/com/android/server/wm/InsetsSourceProvider.java
@@ -529,13 +529,27 @@
setClientVisible((WindowInsets.Type.defaultVisible() & mSource.getType()) != 0);
return;
}
+ boolean initiallyVisible = mClientVisible;
final Point surfacePosition = getWindowFrameSurfacePosition();
mAdapter = new ControlAdapter(surfacePosition);
if (mSource.getType() == WindowInsets.Type.ime()) {
+ if (android.view.inputmethod.Flags.refactorInsetsController()) {
+ if (mClientVisible && mServerVisible) {
+ WindowContainer imeParentWindow = mDisplayContent.getImeParentWindow();
+ // If the IME is attached to an app window, only consider it initially visible
+ // if the parent is visible and wasn't part of a transition.
+ initiallyVisible =
+ imeParentWindow != null && !imeParentWindow.inTransitionSelfOrParent()
+ && imeParentWindow.isVisible()
+ && imeParentWindow.isVisibleRequested();
+ } else {
+ initiallyVisible = false;
+ }
+ }
setClientVisible(target.isRequestedVisible(WindowInsets.Type.ime()));
}
final Transaction t = mWindowContainer.getSyncTransaction();
- mWindowContainer.startAnimation(t, mAdapter, !mClientVisible /* hidden */,
+ mWindowContainer.startAnimation(t, mAdapter, !initiallyVisible /* hidden */,
ANIMATION_TYPE_INSETS_CONTROL);
// The leash was just created. We cannot dispatch it until its surface transaction is
@@ -545,14 +559,16 @@
final SurfaceControl leash = mAdapter.mCapturedLeash;
mControlTarget = target;
updateVisibility();
- boolean initiallyVisible = mClientVisible;
if (mSource.getType() == WindowInsets.Type.ime()) {
- // The IME cannot be initially visible, see ControlAdapter#startAnimation below.
- // Also, the ImeInsetsSourceConsumer clears the client visibility upon losing control,
- // but this won't have reached here yet by the time the new control is created.
- // Note: The DisplayImeController needs the correct previous client's visibility, so we
- // only override the initiallyVisible here.
- initiallyVisible = false;
+ if (!android.view.inputmethod.Flags.refactorInsetsController()) {
+ // The IME cannot be initially visible, see ControlAdapter#startAnimation below.
+ // Also, the ImeInsetsSourceConsumer clears the client visibility upon losing
+ // control, but this won't have reached here yet by the time the new control is
+ // created.
+ // Note: The DisplayImeController needs the correct previous client's visibility,
+ // so we only override the initiallyVisible here.
+ initiallyVisible = false;
+ }
}
mControl = new InsetsSourceControl(mSource.getId(), mSource.getType(), leash,
initiallyVisible, surfacePosition, getInsetsHint());
@@ -598,7 +614,7 @@
mSeamlessRotating = false;
}
- boolean updateClientVisibility(InsetsControlTarget caller,
+ boolean updateClientVisibility(InsetsTarget caller,
@Nullable ImeTracker.Token statsToken) {
final boolean requestedVisible = caller.isRequestedVisible(mSource.getType());
if (caller != mControlTarget || requestedVisible == mClientVisible) {
@@ -799,7 +815,7 @@
@AnimationType int type, @NonNull OnAnimationFinishedCallback finishCallback) {
// TODO(b/166736352): Check if we still need to control the IME visibility here.
if (mSource.getType() == WindowInsets.Type.ime()) {
- if (!android.view.inputmethod.Flags.refactorInsetsController() || !mClientVisible) {
+ if (!android.view.inputmethod.Flags.refactorInsetsController()) {
// TODO: use 0 alpha and remove t.hide() once b/138459974 is fixed.
t.setAlpha(animationLeash, 1 /* alpha */);
t.hide(animationLeash);
diff --git a/services/core/java/com/android/server/wm/InsetsStateController.java b/services/core/java/com/android/server/wm/InsetsStateController.java
index 481ecd3..3e39a45 100644
--- a/services/core/java/com/android/server/wm/InsetsStateController.java
+++ b/services/core/java/com/android/server/wm/InsetsStateController.java
@@ -219,7 +219,7 @@
}
}
- void onRequestedVisibleTypesChanged(InsetsControlTarget caller,
+ void onRequestedVisibleTypesChanged(InsetsTarget caller,
@Nullable ImeTracker.Token statsToken) {
boolean changed = false;
for (int i = mProviders.size() - 1; i >= 0; i--) {
@@ -238,7 +238,7 @@
}
}
- @InsetsType int getFakeControllingTypes(InsetsControlTarget target) {
+ @InsetsType int getFakeControllingTypes(InsetsTarget target) {
@InsetsType int types = 0;
for (int i = mProviders.size() - 1; i >= 0; i--) {
final InsetsSourceProvider provider = mProviders.valueAt(i);
diff --git a/services/core/java/com/android/server/wm/InsetsTarget.java b/services/core/java/com/android/server/wm/InsetsTarget.java
new file mode 100644
index 0000000..b918ca3
--- /dev/null
+++ b/services/core/java/com/android/server/wm/InsetsTarget.java
@@ -0,0 +1,48 @@
+/*
+ * 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 com.android.server.wm;
+
+import android.annotation.Nullable;
+import android.os.IBinder;
+import android.view.WindowInsets;
+
+/**
+ * A common parent for {@link InputTarget} and {@link InsetsControlTarget}: Some types (like the
+ * {@link EmbeddedWindowController.EmbeddedWindow}) should not be a control target for insets in
+ * general, but should be able to request the IME. To archive this, the InsetsTarget contains the
+ * minimal information that those interfaces share (and what is needed to show the IME.
+ */
+public interface InsetsTarget {
+
+ /**
+ * @return Client IWindow token for the target.
+ */
+ @Nullable
+ IBinder getWindowToken();
+
+ /**
+ * @param types The {@link WindowInsets.Type}s which requestedVisibility status is returned.
+ * @return {@code true} if any of the {@link WindowInsets.Type.InsetsType} is requested
+ * visible by this target.
+ */
+ boolean isRequestedVisible(@WindowInsets.Type.InsetsType int types);
+
+ /**
+ * @return {@link WindowInsets.Type.InsetsType}s which are requested visible by this target.
+ */
+ @WindowInsets.Type.InsetsType int getRequestedVisibleTypes();
+}
diff --git a/services/core/java/com/android/server/wm/Session.java b/services/core/java/com/android/server/wm/Session.java
index 2ea2aeb..5550f3e 100644
--- a/services/core/java/com/android/server/wm/Session.java
+++ b/services/core/java/com/android/server/wm/Session.java
@@ -705,8 +705,25 @@
win.getDisplayContent().getInsetsPolicy().onRequestedVisibleTypesChanged(win,
imeStatsToken);
} else {
- ImeTracker.forLogging().onFailed(imeStatsToken,
- ImeTracker.PHASE_WM_UPDATE_REQUESTED_VISIBLE_TYPES);
+ EmbeddedWindowController.EmbeddedWindow embeddedWindow = null;
+ if (android.view.inputmethod.Flags.refactorInsetsController()) {
+ embeddedWindow = mService.mEmbeddedWindowController.getByWindowToken(
+ window.asBinder());
+ }
+ if (embeddedWindow != null) {
+ // If there is no WindowState for the IWindow, it could be still an
+ // EmbeddedWindow. Therefore, check the EmbeddedWindowController as well
+ // TODO(b/329229469) Use different phase here
+ ImeTracker.forLogging().onProgress(imeStatsToken,
+ ImeTracker.PHASE_WM_UPDATE_REQUESTED_VISIBLE_TYPES);
+ embeddedWindow.setRequestedVisibleTypes(
+ requestedVisibleTypes & WindowInsets.Type.ime());
+ embeddedWindow.getDisplayContent().getInsetsPolicy()
+ .onRequestedVisibleTypesChanged(embeddedWindow, imeStatsToken);
+ } else {
+ ImeTracker.forLogging().onFailed(imeStatsToken,
+ ImeTracker.PHASE_WM_UPDATE_REQUESTED_VISIBLE_TYPES);
+ }
}
}
}
diff --git a/services/core/java/com/android/server/wm/Transition.java b/services/core/java/com/android/server/wm/Transition.java
index 4eba36f..655a6fb 100644
--- a/services/core/java/com/android/server/wm/Transition.java
+++ b/services/core/java/com/android/server/wm/Transition.java
@@ -2875,19 +2875,12 @@
return out;
}
- // Get the animation theme from the top-most application window
- // when Flags.customAnimationsBehindTranslucent() is false.
final AnimationOptions animOptionsForActivityTransition =
calculateAnimationOptionsForActivityTransition(type, sortedTargets);
-
if (!Flags.moveAnimationOptionsToChange() && animOptionsForActivityTransition != null) {
out.setAnimationOptions(animOptionsForActivityTransition);
}
- // Store the animation options of the topmost non-translucent change
- // (Used when Flags.customAnimationsBehindTranslucent() is true)
- AnimationOptions activityAboveAnimationOptions = null;
-
final ArraySet<WindowContainer> occludedAtEndContainers = new ArraySet<>();
// Convert all the resolved ChangeInfos into TransactionInfo.Change objects in order.
final int count = sortedTargets.size();
@@ -3006,26 +2999,9 @@
change.setBackgroundColor(ColorUtils.setAlphaComponent(backgroundColor, 255));
}
- // Calculate the animation options for this change
+ AnimationOptions animOptions = null;
if (Flags.moveAnimationOptionsToChange()) {
- AnimationOptions animOptions = null;
- if (Flags.customAnimationsBehindTranslucent() && activityRecord != null) {
- if (activityAboveAnimationOptions != null) {
- // Inherit the options from one of the changes on top of this
- animOptions = activityAboveAnimationOptions;
- } else {
- // Create the options based on this change's custom animations and layout
- // parameters
- animOptions = getOptions(activityRecord /* customAnimActivity */,
- activityRecord /* animLpActivity */);
- if (!change.hasFlags(FLAG_TRANSLUCENT)) {
- // If this change is not translucent, its options are going to be
- // inherited by the changes below
- activityAboveAnimationOptions = animOptions;
- }
- }
- } else if (activityRecord != null && animOptionsForActivityTransition != null) {
- // Use the same options from the top activity for all the activities
+ if (activityRecord != null && animOptionsForActivityTransition != null) {
animOptions = animOptionsForActivityTransition;
} else if (Flags.activityEmbeddingOverlayPresentationFlag()
&& isEmbeddedTaskFragment) {
@@ -3074,42 +3050,28 @@
@Nullable
private static AnimationOptions calculateAnimationOptionsForActivityTransition(
@TransitionType int type, @NonNull ArrayList<ChangeInfo> sortedTargets) {
+ TransitionInfo.AnimationOptions animOptions = null;
+
+ // Check if the top-most app is an activity (ie. activity->activity). If so, make sure
+ // to honor its custom transition options.
WindowContainer<?> topApp = null;
for (int i = 0; i < sortedTargets.size(); i++) {
- if (!isWallpaper(sortedTargets.get(i).mContainer)) {
- topApp = sortedTargets.get(i).mContainer;
- break;
- }
+ if (isWallpaper(sortedTargets.get(i).mContainer)) continue;
+ topApp = sortedTargets.get(i).mContainer;
+ break;
}
- ActivityRecord animLpActivity = findAnimLayoutParamsActivityRecord(type, sortedTargets);
- return getOptions(topApp.asActivityRecord() /* customAnimActivity */,
- animLpActivity /* animLpActivity */);
- }
-
- /**
- * Updates and returns animOptions with the layout parameters of animLpActivity
- * @param customAnimActivity the activity that drives the custom animation options
- * @param animLpActivity the activity that drives the animation options with its layout
- * parameters
- * @return the options extracted from the provided activities
- */
- @Nullable
- private static AnimationOptions getOptions(@Nullable ActivityRecord customAnimActivity,
- @Nullable ActivityRecord animLpActivity) {
- AnimationOptions animOptions = null;
- // Custom
- if (customAnimActivity != null) {
- animOptions = addCustomActivityTransition(customAnimActivity, true /* open */,
- animOptions);
- animOptions = addCustomActivityTransition(customAnimActivity, false /* open */,
+ if (topApp.asActivityRecord() != null) {
+ final ActivityRecord topActivity = topApp.asActivityRecord();
+ animOptions = addCustomActivityTransition(topActivity, true/* open */,
+ null /* animOptions */);
+ animOptions = addCustomActivityTransition(topActivity, false/* open */,
animOptions);
}
-
- // Layout parameters
+ final ActivityRecord animLpActivity =
+ findAnimLayoutParamsActivityRecord(type, sortedTargets);
final WindowState mainWindow = animLpActivity != null
? animLpActivity.findMainWindow() : null;
- final WindowManager.LayoutParams animLp = mainWindow != null ? mainWindow.mAttrs : null;
-
+ WindowManager.LayoutParams animLp = mainWindow != null ? mainWindow.mAttrs : null;
if (animLp != null && animLp.type != TYPE_APPLICATION_STARTING
&& animLp.windowAnimations != 0) {
// Don't send animation options if no windowAnimations have been set or if the we
@@ -3249,9 +3211,10 @@
return ancestor;
}
- @Nullable
- private static ActivityRecord findAnimLayoutParamsActivityRecord(
- @TransitionType int transit, @NonNull List<ChangeInfo> sortedTargets) {
+ private static ActivityRecord findAnimLayoutParamsActivityRecord(int type,
+ ArrayList<ChangeInfo> sortedTargets) {
+ // Find the layout params of the top-most application window that is part of the
+ // transition, which is what will control the animation theme.
final ArraySet<Integer> activityTypes = new ArraySet<>();
final int targetCount = sortedTargets.size();
for (int i = 0; i < targetCount; ++i) {
@@ -3271,7 +3234,12 @@
// activity through the layout parameter animation style.
return null;
}
+ return findAnimLayoutParamsActivityRecord(sortedTargets, type, activityTypes);
+ }
+ private static ActivityRecord findAnimLayoutParamsActivityRecord(
+ List<ChangeInfo> sortedTargets,
+ @TransitionType int transit, ArraySet<Integer> activityTypes) {
// Remote animations always win, but fullscreen windows override non-fullscreen windows.
ActivityRecord result = lookForTopWindowWithFilter(sortedTargets,
w -> w.getRemoteAnimationDefinition() != null
diff --git a/services/core/java/com/android/server/wm/WindowManagerService.java b/services/core/java/com/android/server/wm/WindowManagerService.java
index 459a509..33f2dd1 100644
--- a/services/core/java/com/android/server/wm/WindowManagerService.java
+++ b/services/core/java/com/android/server/wm/WindowManagerService.java
@@ -1186,9 +1186,13 @@
public static WindowManagerService main(final Context context, final InputManagerService im,
final boolean showBootMsgs, WindowManagerPolicy policy,
ActivityTaskManagerService atm) {
+ // Using SysUI context to have access to Material colors extracted from Wallpaper.
+ final AppCompatConfiguration appCompat = new AppCompatConfiguration(
+ ActivityThread.currentActivityThread().getSystemUiContext());
+
final WindowManagerService wms = main(context, im, showBootMsgs, policy, atm,
new DisplayWindowSettingsProvider(), SurfaceControl.Transaction::new,
- SurfaceControl.Builder::new);
+ SurfaceControl.Builder::new, appCompat);
WindowManagerGlobal.setWindowManagerServiceForSystemProcess(wms);
return wms;
}
@@ -1202,12 +1206,14 @@
final boolean showBootMsgs, WindowManagerPolicy policy, ActivityTaskManagerService atm,
DisplayWindowSettingsProvider displayWindowSettingsProvider,
Supplier<SurfaceControl.Transaction> transactionFactory,
- Supplier<SurfaceControl.Builder> surfaceControlFactory) {
+ Supplier<SurfaceControl.Builder> surfaceControlFactory,
+ AppCompatConfiguration appCompat) {
+
final WindowManagerService[] wms = new WindowManagerService[1];
DisplayThread.getHandler().runWithScissors(() ->
wms[0] = new WindowManagerService(context, im, showBootMsgs, policy, atm,
displayWindowSettingsProvider, transactionFactory,
- surfaceControlFactory), 0);
+ surfaceControlFactory, appCompat), 0);
return wms[0];
}
@@ -1231,7 +1237,8 @@
boolean showBootMsgs, WindowManagerPolicy policy, ActivityTaskManagerService atm,
DisplayWindowSettingsProvider displayWindowSettingsProvider,
Supplier<SurfaceControl.Transaction> transactionFactory,
- Supplier<SurfaceControl.Builder> surfaceControlFactory) {
+ Supplier<SurfaceControl.Builder> surfaceControlFactory,
+ AppCompatConfiguration appCompat) {
installLock(this, INDEX_WINDOW);
mGlobalLock = atm.getGlobalLock();
mAtmService = atm;
@@ -1283,9 +1290,7 @@
| WindowInsets.Type.navigationBars();
}
- mAppCompatConfiguration = new AppCompatConfiguration(
- // Using SysUI context to have access to Material colors extracted from Wallpaper.
- ActivityThread.currentActivityThread().getSystemUiContext());
+ mAppCompatConfiguration = appCompat;
mInputManager = inputManager; // Must be before createDisplayContentLocked.
mDisplayManagerInternal = LocalServices.getService(DisplayManagerInternal.class);
diff --git a/services/core/java/com/android/server/wm/WindowState.java b/services/core/java/com/android/server/wm/WindowState.java
index b527630..1640ad3 100644
--- a/services/core/java/com/android/server/wm/WindowState.java
+++ b/services/core/java/com/android/server/wm/WindowState.java
@@ -2754,10 +2754,16 @@
* @param outRegion The region to update.
*/
private void updateRegionForModalActivityWindow(Region outRegion) {
- // If the inner bounds of letterbox is available, then it will be used as the
- // touchable region so it won't cover the touchable letterbox and the touch
- // events can slip to activity from letterbox.
- mActivityRecord.getLetterboxInnerBounds(mTmpRect);
+ if (Flags.scrollingFromLetterbox()) {
+ // Touchable region expands to the letterbox area to react to scrolls from letterbox.
+ mTmpRect.setEmpty();
+ } else {
+ // If the activity is letterboxed and scrolling from letterbox is disabled, limit the
+ // touchable region to the activity. This way, the letterbox area is exposed to react
+ // to touch events, and the touch events can slip from the activity from letterbox.
+ mActivityRecord.getLetterboxInnerBounds(mTmpRect);
+ }
+
if (mTmpRect.isEmpty()) {
final Rect transformedBounds = mActivityRecord.getFixedRotationTransformDisplayBounds();
if (transformedBounds != null) {
diff --git a/services/core/java/com/android/server/wm/utils/TEST_MAPPING b/services/core/java/com/android/server/wm/utils/TEST_MAPPING
index aa69d2a..6f34cd0 100644
--- a/services/core/java/com/android/server/wm/utils/TEST_MAPPING
+++ b/services/core/java/com/android/server/wm/utils/TEST_MAPPING
@@ -1,18 +1,7 @@
{
"presubmit": [
{
- "name": "WmTests",
- "options": [
- {
- "include-filter": "com.android.server.wm.utils"
- },
- {
- "include-annotation": "android.platform.test.annotations.Presubmit"
- },
- {
- "exclude-annotation": "androidx.test.filters.FlakyTest"
- }
- ]
+ "name": "WmTests_wm_utils_Presubmit"
}
]
}
diff --git a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
index b6e45fc8..6314b85 100644
--- a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
+++ b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
@@ -10625,8 +10625,16 @@
final DevicePolicyData policyData = getUserData(userId);
if (transitionCheckNeeded) {
// Optional state transition check for non-ADB case.
- checkUserProvisioningStateTransition(policyData.mUserProvisioningState,
- newState);
+ try {
+ checkUserProvisioningStateTransition(
+ policyData.mUserProvisioningState,
+ newState);
+
+ } catch (IllegalStateException e) {
+ Slogf.e(LOG_TAG,
+ "Exception caught while changing provisioning state", e);
+ throw e;
+ }
}
policyData.mUserProvisioningState = newState;
saveSettingsLocked(userId);
@@ -10637,6 +10645,10 @@
}
private void checkUserProvisioningStateTransition(int currentState, int newState) {
+ if (Flags.userProvisioningSameState()) {
+ Preconditions.checkState(newState != currentState, "New state cannot"
+ + " be the same as the current state: [" + newState + "]");
+ }
// Valid transitions for normal use-cases.
switch (currentState) {
case DevicePolicyManager.STATE_USER_UNMANAGED:
diff --git a/services/foldables/devicestateprovider/TEST_MAPPING b/services/foldables/devicestateprovider/TEST_MAPPING
index 47de131..0538381 100644
--- a/services/foldables/devicestateprovider/TEST_MAPPING
+++ b/services/foldables/devicestateprovider/TEST_MAPPING
@@ -1,12 +1,7 @@
{
"presubmit": [
{
- "name": "foldable-device-state-provider-tests",
- "options": [
- {
- "exclude-annotation": "androidx.test.filters.FlakyTest"
- }
- ]
+ "name": "foldable-device-state-provider-tests"
}
]
}
diff --git a/services/foldables/devicestateprovider/src/com/android/server/policy/feature/Android.bp b/services/foldables/devicestateprovider/src/com/android/server/policy/feature/Android.bp
index 1db9e8d..6393e11 100644
--- a/services/foldables/devicestateprovider/src/com/android/server/policy/feature/Android.bp
+++ b/services/foldables/devicestateprovider/src/com/android/server/policy/feature/Android.bp
@@ -1,7 +1,7 @@
aconfig_declarations {
name: "device_state_flags",
package: "com.android.server.policy.feature.flags",
- container: "system_ext",
+ container: "system",
srcs: [
"device_state_flags.aconfig",
],
diff --git a/services/foldables/devicestateprovider/src/com/android/server/policy/feature/device_state_flags.aconfig b/services/foldables/devicestateprovider/src/com/android/server/policy/feature/device_state_flags.aconfig
index f827b55..21e33dd 100644
--- a/services/foldables/devicestateprovider/src/com/android/server/policy/feature/device_state_flags.aconfig
+++ b/services/foldables/devicestateprovider/src/com/android/server/policy/feature/device_state_flags.aconfig
@@ -1,5 +1,5 @@
package: "com.android.server.policy.feature.flags"
-container: "system_ext"
+container: "system"
flag {
name: "enable_dual_display_blocking"
diff --git a/services/incremental/TEST_MAPPING b/services/incremental/TEST_MAPPING
index 4c9403c..cbb9962 100644
--- a/services/incremental/TEST_MAPPING
+++ b/services/incremental/TEST_MAPPING
@@ -1,12 +1,7 @@
{
"presubmit": [
{
- "name": "CtsPackageManagerStatsHostTestCases",
- "options": [
- {
- "include-filter": "com.android.cts.packagemanager.stats.host.PackageInstallerV2StatsTests"
- }
- ]
+ "name": "CtsPackageManagerStatsHostTestCases_host_packageinstallerv2statstests"
},
{
"name": "CtsPackageManagerIncrementalStatsHostTestCases",
diff --git a/services/people/java/com/android/server/people/TEST_MAPPING b/services/people/java/com/android/server/people/TEST_MAPPING
index 55b355c..8677337 100644
--- a/services/people/java/com/android/server/people/TEST_MAPPING
+++ b/services/people/java/com/android/server/people/TEST_MAPPING
@@ -1,12 +1,7 @@
{
"presubmit": [
{
- "name": "FrameworksServicesTests",
- "options": [
- {
- "include-filter": "com.android.server.people.data"
- }
- ]
+ "name": "FrameworksServicesTests_people_data"
}
]
}
\ No newline at end of file
diff --git a/services/permission/TEST_MAPPING b/services/permission/TEST_MAPPING
index 4de4a56..af4aaf9 100644
--- a/services/permission/TEST_MAPPING
+++ b/services/permission/TEST_MAPPING
@@ -105,26 +105,10 @@
]
},
{
- "name": "CtsVirtualDevicesAudioTestCases",
- "options": [
- {
- "exclude-annotation": "androidx.test.filters.FlakyTest"
- },
- {
- "include-filter": "android.virtualdevice.cts.audio.VirtualAudioPermissionTest"
- }
- ]
+ "name": "CtsVirtualDevicesAudioTestCases_audio_virtualaudiopermissiontest"
},
{
- "name": "CtsVirtualDevicesAppLaunchTestCases",
- "options": [
- {
- "exclude-annotation": "androidx.test.filters.FlakyTest"
- },
- {
- "include-filter": "android.virtualdevice.cts.applaunch.VirtualDevicePermissionTest"
- }
- ]
+ "name": "CtsVirtualDevicesAppLaunchTestCases_applaunch_virtualdevicepermissiontest"
}
],
"imports": [
diff --git a/services/print/java/com/android/server/print/TEST_MAPPING b/services/print/java/com/android/server/print/TEST_MAPPING
index 4fa8822..1033b1a 100644
--- a/services/print/java/com/android/server/print/TEST_MAPPING
+++ b/services/print/java/com/android/server/print/TEST_MAPPING
@@ -1,12 +1,7 @@
{
"presubmit": [
{
- "name": "CtsPrintTestCases",
- "options": [
- {
- "include-annotation": "android.platform.test.annotations.Presubmit"
- }
- ]
+ "name": "CtsPrintTestCases_Presubmit"
}
]
}
diff --git a/services/tests/InputMethodSystemServerTests/TEST_MAPPING b/services/tests/InputMethodSystemServerTests/TEST_MAPPING
index de9f771..7313941 100644
--- a/services/tests/InputMethodSystemServerTests/TEST_MAPPING
+++ b/services/tests/InputMethodSystemServerTests/TEST_MAPPING
@@ -1,22 +1,12 @@
{
"presubmit": [
{
- "name": "FrameworksInputMethodSystemServerTests",
- "options": [
- {"include-filter": "com.android.server.inputmethod"},
- {"exclude-annotation": "androidx.test.filters.FlakyTest"},
- {"exclude-annotation": "org.junit.Ignore"}
- ]
+ "name": "FrameworksInputMethodSystemServerTests_server_inputmethod"
}
],
"postsubmit": [
{
- "name": "FrameworksImeTests",
- "options": [
- {"include-filter": "com.android.inputmethodservice"},
- {"exclude-annotation": "androidx.test.filters.FlakyTest"},
- {"exclude-annotation": "org.junit.Ignore"}
- ]
+ "name": "FrameworksImeTests_android_inputmethodservice"
}
]
}
diff --git a/services/tests/PackageManagerServiceTests/TEST_MAPPING b/services/tests/PackageManagerServiceTests/TEST_MAPPING
index 5d96af9..13ba317 100644
--- a/services/tests/PackageManagerServiceTests/TEST_MAPPING
+++ b/services/tests/PackageManagerServiceTests/TEST_MAPPING
@@ -4,21 +4,7 @@
"name": "AppEnumerationInternalTests"
},
{
- "name": "PackageManagerServiceServerTests",
- "options": [
- {
- "include-filter": "com.android.server.pm."
- },
- {
- "include-annotation": "android.platform.test.annotations.Presubmit"
- },
- {
- "exclude-annotation": "androidx.test.filters.FlakyTest"
- },
- {
- "exclude-annotation": "org.junit.Ignore"
- }
- ]
+ "name": "PackageManagerServiceServerTests_server_pm_Presubmit"
}
],
"postsubmit": [
@@ -26,21 +12,7 @@
"name": "PackageManagerServiceHostTests"
},
{
- "name": "PackageManagerServiceServerTests",
- "options": [
- {
- "include-filter": "com.android.server.pm."
- },
- {
- "include-annotation": "android.platform.test.annotations.Postsubmit"
- },
- {
- "exclude-annotation": "androidx.test.filters.FlakyTest"
- },
- {
- "exclude-annotation": "org.junit.Ignore"
- }
- ]
+ "name": "PackageManagerServiceServerTests_server_pm_Postsubmit"
}
],
"kernel-presubmit": [
diff --git a/services/tests/appfunctions/src/android/app/appfunctions/AppFunctionRuntimeMetadataTest.kt b/services/tests/appfunctions/src/android/app/appfunctions/AppFunctionRuntimeMetadataTest.kt
index 650e520..dbbb2fe 100644
--- a/services/tests/appfunctions/src/android/app/appfunctions/AppFunctionRuntimeMetadataTest.kt
+++ b/services/tests/appfunctions/src/android/app/appfunctions/AppFunctionRuntimeMetadataTest.kt
@@ -101,4 +101,15 @@
assertThat(actualPackageName).isEqualTo(expectedPackageName)
}
+
+ @Test
+ fun testBuild() {
+ val runtimeMetadata = AppFunctionRuntimeMetadata.Builder("com.pkg", "funcId").build()
+
+ assertThat(runtimeMetadata.packageName).isEqualTo("com.pkg")
+ assertThat(runtimeMetadata.functionId).isEqualTo("funcId")
+ assertThat(runtimeMetadata.enabled).isNull()
+ assertThat(runtimeMetadata.appFunctionStaticMetadataQualifiedId)
+ .isEqualTo("android\$apps-db/app_functions#com.pkg/funcId")
+ }
}
diff --git a/services/tests/appfunctions/src/com/android/server/appfunctions/FutureAppSearchSessionTest.kt b/services/tests/appfunctions/src/com/android/server/appfunctions/FutureAppSearchSessionTest.kt
index edcbb9e..e761e8d 100644
--- a/services/tests/appfunctions/src/com/android/server/appfunctions/FutureAppSearchSessionTest.kt
+++ b/services/tests/appfunctions/src/com/android/server/appfunctions/FutureAppSearchSessionTest.kt
@@ -84,7 +84,7 @@
val schema = session.setSchema(setSchemaRequest)
assertThat(schema.get()).isNotNull()
val appFunctionRuntimeMetadata =
- AppFunctionRuntimeMetadata.Builder(TEST_PACKAGE_NAME, TEST_FUNCTION_ID, "").build()
+ AppFunctionRuntimeMetadata.Builder(TEST_PACKAGE_NAME, TEST_FUNCTION_ID).build()
val putDocumentsRequest: PutDocumentsRequest =
PutDocumentsRequest.Builder()
.addGenericDocuments(appFunctionRuntimeMetadata)
@@ -110,7 +110,7 @@
val schema = session.setSchema(setSchemaRequest)
assertThat(schema.get()).isNotNull()
val appFunctionRuntimeMetadata =
- AppFunctionRuntimeMetadata.Builder(TEST_PACKAGE_NAME, TEST_FUNCTION_ID, "").build()
+ AppFunctionRuntimeMetadata.Builder(TEST_PACKAGE_NAME, TEST_FUNCTION_ID).build()
val putDocumentsRequest: PutDocumentsRequest =
PutDocumentsRequest.Builder()
.addGenericDocuments(appFunctionRuntimeMetadata)
@@ -144,7 +144,7 @@
val schema = session.setSchema(setSchemaRequest)
assertThat(schema.get()).isNotNull()
val appFunctionRuntimeMetadata =
- AppFunctionRuntimeMetadata.Builder(TEST_PACKAGE_NAME, TEST_FUNCTION_ID, "").build()
+ AppFunctionRuntimeMetadata.Builder(TEST_PACKAGE_NAME, TEST_FUNCTION_ID).build()
val putDocumentsRequest: PutDocumentsRequest =
PutDocumentsRequest.Builder()
.addGenericDocuments(appFunctionRuntimeMetadata)
@@ -175,7 +175,7 @@
.build()
session.setSchema(setSchemaRequest).get()
val appFunctionRuntimeMetadata =
- AppFunctionRuntimeMetadata.Builder(TEST_PACKAGE_NAME, TEST_FUNCTION_ID, "").build()
+ AppFunctionRuntimeMetadata.Builder(TEST_PACKAGE_NAME, TEST_FUNCTION_ID).build()
val putDocumentsRequest: PutDocumentsRequest =
PutDocumentsRequest.Builder()
.addGenericDocuments(appFunctionRuntimeMetadata)
diff --git a/services/tests/appfunctions/src/com/android/server/appfunctions/FutureGlobalSearchSessionTest.kt b/services/tests/appfunctions/src/com/android/server/appfunctions/FutureGlobalSearchSessionTest.kt
index 38cba65..7fe7263 100644
--- a/services/tests/appfunctions/src/com/android/server/appfunctions/FutureGlobalSearchSessionTest.kt
+++ b/services/tests/appfunctions/src/com/android/server/appfunctions/FutureGlobalSearchSessionTest.kt
@@ -94,8 +94,7 @@
val schema = session.setSchema(setSchemaRequest)
assertThat(schema.get()).isNotNull()
val appFunctionRuntimeMetadata =
- AppFunctionRuntimeMetadata.Builder(TEST_TARGET_PKG_NAME, TEST_FUNCTION_ID, "")
- .build()
+ AppFunctionRuntimeMetadata.Builder(TEST_TARGET_PKG_NAME, TEST_FUNCTION_ID).build()
val putDocumentsRequest: PutDocumentsRequest =
PutDocumentsRequest.Builder()
.addGenericDocuments(appFunctionRuntimeMetadata)
diff --git a/services/tests/appfunctions/src/com/android/server/appfunctions/MetadataSyncAdapterTest.kt b/services/tests/appfunctions/src/com/android/server/appfunctions/MetadataSyncAdapterTest.kt
index b938c3c..63cf7bf 100644
--- a/services/tests/appfunctions/src/com/android/server/appfunctions/MetadataSyncAdapterTest.kt
+++ b/services/tests/appfunctions/src/com/android/server/appfunctions/MetadataSyncAdapterTest.kt
@@ -16,26 +16,28 @@
package com.android.server.appfunctions
import android.app.appfunctions.AppFunctionRuntimeMetadata
-import android.app.appfunctions.AppFunctionRuntimeMetadata.createParentAppFunctionRuntimeSchema
-import android.app.appfunctions.AppFunctionStaticMetadataHelper
+import android.app.appsearch.AppSearchBatchResult
import android.app.appsearch.AppSearchManager
-import android.app.appsearch.AppSearchManager.SearchContext
+import android.app.appsearch.AppSearchResult
+import android.app.appsearch.AppSearchSchema
import android.app.appsearch.GenericDocument
+import android.app.appsearch.GetByDocumentIdRequest
+import android.app.appsearch.GetSchemaResponse
import android.app.appsearch.PutDocumentsRequest
+import android.app.appsearch.RemoveByDocumentIdRequest
import android.app.appsearch.SearchResult
import android.app.appsearch.SearchSpec
import android.app.appsearch.SetSchemaRequest
+import android.app.appsearch.SetSchemaResponse
import android.util.ArrayMap
import android.util.ArraySet
+import android.util.Log
import androidx.test.platform.app.InstrumentationRegistry
import com.android.internal.infra.AndroidFuture
import com.android.server.appfunctions.FutureAppSearchSession.FutureSearchResults
import com.google.common.truth.Truth.assertThat
import com.google.common.util.concurrent.MoreExecutors
-import java.util.concurrent.Executor
import java.util.concurrent.atomic.AtomicBoolean
-import org.junit.After
-import org.junit.Before
import org.junit.Test
import org.junit.runner.RunWith
import org.junit.runners.JUnit4
@@ -47,46 +49,19 @@
private val testExecutor = MoreExecutors.directExecutor()
private val packageManager = context.packageManager
- @Before
- @After
- fun clearData() {
- val searchContext = SearchContext.Builder(TEST_DB).build()
- FutureAppSearchSessionImpl(appSearchManager, testExecutor, searchContext).use {
- val setSchemaRequest = SetSchemaRequest.Builder().setForceOverride(true).build()
- it.setSchema(setSchemaRequest).get()
- }
- }
-
@Test
fun getPackageToFunctionIdMap() {
- val searchContext: SearchContext = SearchContext.Builder(TEST_DB).build()
+ val searchSession = FakeSearchSession()
val functionRuntimeMetadata =
- AppFunctionRuntimeMetadata.Builder(TEST_TARGET_PKG_NAME, "testFunctionId", "").build()
- val setSchemaRequest =
- SetSchemaRequest.Builder()
- .addSchemas(AppFunctionRuntimeMetadata.createParentAppFunctionRuntimeSchema())
- .addSchemas(
- AppFunctionRuntimeMetadata.createAppFunctionRuntimeSchema(TEST_TARGET_PKG_NAME)
- )
- .build()
+ AppFunctionRuntimeMetadata.Builder(TEST_TARGET_PKG_NAME, "testFunctionId").build()
val putDocumentsRequest: PutDocumentsRequest =
PutDocumentsRequest.Builder().addGenericDocuments(functionRuntimeMetadata).build()
- FutureAppSearchSessionImpl(appSearchManager, testExecutor, searchContext).use {
- val setSchemaResponse = it.setSchema(setSchemaRequest).get()
- assertThat(setSchemaResponse).isNotNull()
- val appSearchBatchResult = it.put(putDocumentsRequest).get()
- assertThat(appSearchBatchResult.isSuccess).isTrue()
- }
+ searchSession.put(putDocumentsRequest).get()
- val metadataSyncAdapter =
- MetadataSyncAdapter(
- testExecutor,
- FutureAppSearchSessionImpl(appSearchManager, testExecutor, searchContext),
- packageManager,
- )
val packageToFunctionIdMap =
- metadataSyncAdapter.getPackageToFunctionIdMap(
- AppFunctionRuntimeMetadata.RUNTIME_SCHEMA_TYPE,
+ MetadataSyncAdapter.getPackageToFunctionIdMap(
+ searchSession,
+ "fakeSchema",
AppFunctionRuntimeMetadata.PROPERTY_FUNCTION_ID,
AppFunctionRuntimeMetadata.PROPERTY_PACKAGE_NAME,
)
@@ -97,22 +72,15 @@
@Test
fun getPackageToFunctionIdMap_multipleDocuments() {
- val searchContext: SearchContext = SearchContext.Builder(TEST_DB).build()
+ val searchSession = FakeSearchSession()
val functionRuntimeMetadata =
- AppFunctionRuntimeMetadata.Builder(TEST_TARGET_PKG_NAME, "testFunctionId", "").build()
+ AppFunctionRuntimeMetadata.Builder(TEST_TARGET_PKG_NAME, "testFunctionId").build()
val functionRuntimeMetadata1 =
- AppFunctionRuntimeMetadata.Builder(TEST_TARGET_PKG_NAME, "testFunctionId1", "").build()
+ AppFunctionRuntimeMetadata.Builder(TEST_TARGET_PKG_NAME, "testFunctionId1").build()
val functionRuntimeMetadata2 =
- AppFunctionRuntimeMetadata.Builder(TEST_TARGET_PKG_NAME, "testFunctionId2", "").build()
+ AppFunctionRuntimeMetadata.Builder(TEST_TARGET_PKG_NAME, "testFunctionId2").build()
val functionRuntimeMetadata3 =
- AppFunctionRuntimeMetadata.Builder(TEST_TARGET_PKG_NAME, "testFunctionId3", "").build()
- val setSchemaRequest =
- SetSchemaRequest.Builder()
- .addSchemas(AppFunctionRuntimeMetadata.createParentAppFunctionRuntimeSchema())
- .addSchemas(
- AppFunctionRuntimeMetadata.createAppFunctionRuntimeSchema(TEST_TARGET_PKG_NAME)
- )
- .build()
+ AppFunctionRuntimeMetadata.Builder(TEST_TARGET_PKG_NAME, "testFunctionId3").build()
val putDocumentsRequest: PutDocumentsRequest =
PutDocumentsRequest.Builder()
.addGenericDocuments(
@@ -122,21 +90,11 @@
functionRuntimeMetadata3,
)
.build()
- FutureAppSearchSessionImpl(appSearchManager, testExecutor, searchContext).use {
- val setSchemaResponse = it.setSchema(setSchemaRequest).get()
- assertThat(setSchemaResponse).isNotNull()
- val appSearchBatchResult = it.put(putDocumentsRequest).get()
- assertThat(appSearchBatchResult.isSuccess).isTrue()
- }
+ searchSession.put(putDocumentsRequest).get()
- val metadataSyncAdapter =
- MetadataSyncAdapter(
- testExecutor,
- FutureAppSearchSessionImpl(appSearchManager, testExecutor, searchContext),
- packageManager,
- )
val packageToFunctionIdMap =
- metadataSyncAdapter.getPackageToFunctionIdMap(
+ MetadataSyncAdapter.getPackageToFunctionIdMap(
+ searchSession,
AppFunctionRuntimeMetadata.RUNTIME_SCHEMA_TYPE,
AppFunctionRuntimeMetadata.PROPERTY_FUNCTION_ID,
AppFunctionRuntimeMetadata.PROPERTY_PACKAGE_NAME,
@@ -172,62 +130,21 @@
@Test
fun syncMetadata_noDiff() {
- val searchContext: SearchContext = SearchContext.Builder(TEST_DB).build()
- val appSearchSession =
- PartialFakeFutureAppSearchSession(appSearchManager, testExecutor, searchContext)
- val fakeFunctionId = "syncMetadata_noDiff"
- val fakeStaticMetadata: GenericDocument =
- GenericDocument.Builder<GenericDocument.Builder<*>>(
- AppFunctionStaticMetadataHelper.APP_FUNCTION_STATIC_NAMESPACE,
- AppFunctionStaticMetadataHelper.getDocumentIdForAppFunction(
- TEST_TARGET_PKG_NAME,
- fakeFunctionId,
- ),
- AppFunctionStaticMetadataHelper.STATIC_SCHEMA_TYPE,
- )
- .setPropertyString(
- AppFunctionStaticMetadataHelper.PROPERTY_PACKAGE_NAME,
- TEST_TARGET_PKG_NAME,
- )
- .setPropertyString(
- AppFunctionStaticMetadataHelper.PROPERTY_FUNCTION_ID,
- fakeFunctionId,
- )
- .build()
- appSearchSession.overrideStaticMetadataSearchResult = mutableListOf(fakeStaticMetadata)
- val putCorrespondingSchema =
- appSearchSession
- .setSchema(
- SetSchemaRequest.Builder()
- .addSchemas(
- createParentAppFunctionRuntimeSchema(),
- AppFunctionRuntimeMetadata.createAppFunctionRuntimeSchema(
- TEST_TARGET_PKG_NAME
- ),
- )
- .setForceOverride(true)
- .build()
- )
- .get()
- assertThat(putCorrespondingSchema).isNotNull()
- val putCorrespondingRuntimeMetadata =
- appSearchSession
- .put(
- PutDocumentsRequest.Builder()
- .addGenericDocuments(
- AppFunctionRuntimeMetadata.Builder(
- TEST_TARGET_PKG_NAME,
- fakeFunctionId,
- "",
- )
- .build()
- )
- .build()
- )
- .get()
- assertThat(putCorrespondingRuntimeMetadata.isSuccess).isTrue()
+ val runtimeSearchSession = FakeSearchSession()
+ val staticSearchSession = FakeSearchSession()
+ val functionRuntimeMetadata =
+ AppFunctionRuntimeMetadata.Builder(TEST_TARGET_PKG_NAME, "testFunctionId").build()
+ val putDocumentsRequest: PutDocumentsRequest =
+ PutDocumentsRequest.Builder().addGenericDocuments(functionRuntimeMetadata).build()
+ runtimeSearchSession.put(putDocumentsRequest).get()
+ staticSearchSession.put(putDocumentsRequest).get()
val metadataSyncAdapter =
- MetadataSyncAdapter(testExecutor, appSearchSession, context.packageManager)
+ MetadataSyncAdapter(
+ testExecutor,
+ runtimeSearchSession,
+ staticSearchSession,
+ packageManager,
+ )
val submitSyncRequest = metadataSyncAdapter.submitSyncRequest()
@@ -257,31 +174,20 @@
@Test
fun syncMetadata_addedFunction() {
- val searchContext: SearchContext = SearchContext.Builder(TEST_DB).build()
- val appSearchSession =
- PartialFakeFutureAppSearchSession(appSearchManager, testExecutor, searchContext)
- val fakeFunctionId = "addedFunction1"
- val fakeStaticMetadata: GenericDocument =
- GenericDocument.Builder<GenericDocument.Builder<*>>(
- AppFunctionStaticMetadataHelper.APP_FUNCTION_STATIC_NAMESPACE,
- AppFunctionStaticMetadataHelper.getDocumentIdForAppFunction(
- TEST_TARGET_PKG_NAME,
- fakeFunctionId,
- ),
- AppFunctionStaticMetadataHelper.STATIC_SCHEMA_TYPE,
- )
- .setPropertyString(
- AppFunctionStaticMetadataHelper.PROPERTY_PACKAGE_NAME,
- TEST_TARGET_PKG_NAME,
- )
- .setPropertyString(
- AppFunctionStaticMetadataHelper.PROPERTY_FUNCTION_ID,
- fakeFunctionId,
- )
- .build()
- appSearchSession.overrideStaticMetadataSearchResult = mutableListOf(fakeStaticMetadata)
+ val runtimeSearchSession = FakeSearchSession()
+ val staticSearchSession = FakeSearchSession()
+ val functionRuntimeMetadata =
+ AppFunctionRuntimeMetadata.Builder(TEST_TARGET_PKG_NAME, "testFunctionId").build()
+ val putDocumentsRequest: PutDocumentsRequest =
+ PutDocumentsRequest.Builder().addGenericDocuments(functionRuntimeMetadata).build()
+ staticSearchSession.put(putDocumentsRequest).get()
val metadataSyncAdapter =
- MetadataSyncAdapter(testExecutor, appSearchSession, context.packageManager)
+ MetadataSyncAdapter(
+ testExecutor,
+ runtimeSearchSession,
+ staticSearchSession,
+ packageManager,
+ )
val submitSyncRequest = metadataSyncAdapter.submitSyncRequest()
@@ -325,43 +231,20 @@
@Test
fun syncMetadata_removedFunction() {
- val searchContext: SearchContext = SearchContext.Builder(TEST_DB).build()
- val appSearchSession =
- PartialFakeFutureAppSearchSession(appSearchManager, testExecutor, searchContext)
- val fakeFunctionId = "syncMetadata_removedFunction"
- val putCorrespondingSchema =
- appSearchSession
- .setSchema(
- SetSchemaRequest.Builder()
- .addSchemas(
- createParentAppFunctionRuntimeSchema(),
- AppFunctionRuntimeMetadata.createAppFunctionRuntimeSchema(
- TEST_TARGET_PKG_NAME
- ),
- )
- .setForceOverride(true)
- .build()
- )
- .get()
- assertThat(putCorrespondingSchema).isNotNull()
- val putStaleRuntimeMetadata =
- appSearchSession
- .put(
- PutDocumentsRequest.Builder()
- .addGenericDocuments(
- AppFunctionRuntimeMetadata.Builder(
- TEST_TARGET_PKG_NAME,
- fakeFunctionId,
- "",
- )
- .build()
- )
- .build()
- )
- .get()
- assertThat(putStaleRuntimeMetadata.isSuccess).isTrue()
+ val runtimeSearchSession = FakeSearchSession()
+ val staticSearchSession = FakeSearchSession()
+ val functionRuntimeMetadata =
+ AppFunctionRuntimeMetadata.Builder(TEST_TARGET_PKG_NAME, "testFunctionId").build()
+ val putDocumentsRequest: PutDocumentsRequest =
+ PutDocumentsRequest.Builder().addGenericDocuments(functionRuntimeMetadata).build()
+ runtimeSearchSession.put(putDocumentsRequest).get()
val metadataSyncAdapter =
- MetadataSyncAdapter(testExecutor, appSearchSession, context.packageManager)
+ MetadataSyncAdapter(
+ testExecutor,
+ runtimeSearchSession,
+ staticSearchSession,
+ packageManager,
+ )
val submitSyncRequest = metadataSyncAdapter.submitSyncRequest()
@@ -426,48 +309,99 @@
const val TEST_TARGET_PKG_NAME = "com.android.frameworks.appfunctionstests"
}
- class PartialFakeFutureAppSearchSession(
- appSearchManager: AppSearchManager,
- executor: Executor,
- appSearchContext: SearchContext,
- ) : FutureAppSearchSessionImpl(appSearchManager, executor, appSearchContext) {
- var overrideStaticMetadataSearchResult: MutableList<GenericDocument> = mutableListOf()
- private val overrideUsed = AtomicBoolean(false)
+ class FakeSearchSession : FutureAppSearchSession {
+ private val schemas: MutableSet<AppSearchSchema> = mutableSetOf()
+ private val genericDocumentMutableMap: MutableMap<String, GenericDocument> = mutableMapOf()
- // Overriding this method to fake searching for static metadata.
- // Static metadata is the source of truth for the metadata sync behaviour since the sync is
- // updating the runtime metadata to match the existing static metadata.
+ override fun close() {
+ Log.d("FakeRuntimeMetadataSearchSession", "Closing session")
+ }
+
+ override fun setSchema(
+ setSchemaRequest: SetSchemaRequest
+ ): AndroidFuture<SetSchemaResponse> {
+ schemas.addAll(setSchemaRequest.schemas)
+ return AndroidFuture.completedFuture(SetSchemaResponse.Builder().build())
+ }
+
+ override fun getSchema(): AndroidFuture<GetSchemaResponse> {
+ val resultBuilder = GetSchemaResponse.Builder()
+ for (schema in schemas) {
+ resultBuilder.addSchema(schema)
+ }
+ return AndroidFuture.completedFuture(resultBuilder.build())
+ }
+
+ override fun put(
+ putDocumentsRequest: PutDocumentsRequest
+ ): AndroidFuture<AppSearchBatchResult<String, Void>> {
+ for (document in putDocumentsRequest.genericDocuments) {
+ genericDocumentMutableMap[document.id] = document
+ }
+ val batchResultBuilder = AppSearchBatchResult.Builder<String, Void>()
+ for (document in putDocumentsRequest.genericDocuments) {
+ batchResultBuilder.setResult(document.id, AppSearchResult.newSuccessfulResult(null))
+ }
+ return AndroidFuture.completedFuture(batchResultBuilder.build())
+ }
+
+ override fun remove(
+ removeRequest: RemoveByDocumentIdRequest
+ ): AndroidFuture<AppSearchBatchResult<String, Void>> {
+ for (documentId in removeRequest.ids) {
+ if (!genericDocumentMutableMap.keys.contains(documentId)) {
+ throw IllegalStateException("Document $documentId does not exist")
+ }
+ }
+ val batchResultBuilder = AppSearchBatchResult.Builder<String, Void>()
+ for (id in removeRequest.ids) {
+ batchResultBuilder.setResult(id, AppSearchResult.newSuccessfulResult(null))
+ }
+ return AndroidFuture.completedFuture(batchResultBuilder.build())
+ }
+
+ override fun getByDocumentId(
+ getRequest: GetByDocumentIdRequest
+ ): AndroidFuture<AppSearchBatchResult<String, GenericDocument>> {
+ val batchResultBuilder = AppSearchBatchResult.Builder<String, GenericDocument>()
+ for (documentId in getRequest.ids) {
+ if (!genericDocumentMutableMap.keys.contains(documentId)) {
+ throw IllegalStateException("Document $documentId does not exist")
+ }
+ batchResultBuilder.setResult(
+ documentId,
+ AppSearchResult.newSuccessfulResult(genericDocumentMutableMap[documentId]),
+ )
+ }
+ return AndroidFuture.completedFuture(batchResultBuilder.build())
+ }
+
override fun search(
queryExpression: String,
searchSpec: SearchSpec,
): AndroidFuture<FutureSearchResults> {
- if (
- searchSpec.filterSchemas.contains(
- AppFunctionStaticMetadataHelper.STATIC_SCHEMA_TYPE
- )
- ) {
- val futureSearchResults =
- object : FutureSearchResults {
- override fun getNextPage(): AndroidFuture<MutableList<SearchResult>> {
- if (overrideUsed.get()) {
- overrideStaticMetadataSearchResult.clear()
- return AndroidFuture.completedFuture(mutableListOf())
- }
- overrideUsed.set(true)
- return AndroidFuture.completedFuture(
- overrideStaticMetadataSearchResult
- .map {
- SearchResult.Builder(TEST_TARGET_PKG_NAME, TEST_DB)
- .setGenericDocument(it)
- .build()
- }
- .toMutableList()
- )
+ val futureSearchResults =
+ object : FutureSearchResults {
+ val hasNextPage = AtomicBoolean(false)
+
+ override fun getNextPage(): AndroidFuture<MutableList<SearchResult>> {
+ val searchResultMutableList: MutableList<SearchResult> =
+ genericDocumentMutableMap.values
+ .map {
+ SearchResult.Builder(TEST_TARGET_PKG_NAME, TEST_DB)
+ .setGenericDocument(it)
+ .build()
+ }
+ .toMutableList()
+ if (!hasNextPage.get()) {
+ hasNextPage.set(true)
+ return AndroidFuture.completedFuture(searchResultMutableList)
+ } else {
+ return AndroidFuture.completedFuture(mutableListOf())
}
}
- return AndroidFuture.completedFuture(futureSearchResults)
- }
- return super.search(queryExpression, searchSpec)
+ }
+ return AndroidFuture.completedFuture(futureSearchResults)
}
}
}
diff --git a/services/tests/dreamservicetests/TEST_MAPPING b/services/tests/dreamservicetests/TEST_MAPPING
index a644ea6..38d7000 100644
--- a/services/tests/dreamservicetests/TEST_MAPPING
+++ b/services/tests/dreamservicetests/TEST_MAPPING
@@ -1,21 +1,12 @@
{
"presubmit": [
{
- "name": "DreamServiceTests",
- "options": [
- {"include-filter": "com.android.server.dreams"},
- {"exclude-annotation": "androidx.test.filters.FlakyTest"},
- {"exclude-annotation": "org.junit.Ignore"}
- ]
+ "name": "DreamServiceTests_server_dreams"
}
],
"postsubmit": [
{
- "name": "DreamServiceTests",
- "options": [
- {"include-filter": "com.android.server.dreams"},
- {"exclude-annotation": "org.junit.Ignore"}
- ]
+ "name": "DreamServiceTests_server_dreams"
}
]
}
diff --git a/services/tests/mockingservicestests/src/com/android/server/rollback/TEST_MAPPING b/services/tests/mockingservicestests/src/com/android/server/rollback/TEST_MAPPING
index 4ac4484..ef2d605 100644
--- a/services/tests/mockingservicestests/src/com/android/server/rollback/TEST_MAPPING
+++ b/services/tests/mockingservicestests/src/com/android/server/rollback/TEST_MAPPING
@@ -1,12 +1,7 @@
{
"presubmit": [
{
- "name": "RollbackPackageHealthObserverTests",
- "options": [
- {
- "include-filter": "com.android.server.rollback"
- }
- ]
+ "name": "RollbackPackageHealthObserverTests_server_rollback"
}
]
}
\ No newline at end of file
diff --git a/services/tests/ondeviceintelligencetests/Android.bp b/services/tests/ondeviceintelligencetests/Android.bp
index aa85942..a31a3fb 100644
--- a/services/tests/ondeviceintelligencetests/Android.bp
+++ b/services/tests/ondeviceintelligencetests/Android.bp
@@ -47,9 +47,9 @@
],
libs: [
- "android.test.mock",
- "android.test.base",
- "android.test.runner",
+ "android.test.mock.stubs.system",
+ "android.test.base.stubs.system",
+ "android.test.runner.stubs.system",
],
certificate: "platform",
diff --git a/services/tests/powerstatstests/TEST_MAPPING b/services/tests/powerstatstests/TEST_MAPPING
index 1e8d2de..d3d3cf6 100644
--- a/services/tests/powerstatstests/TEST_MAPPING
+++ b/services/tests/powerstatstests/TEST_MAPPING
@@ -1,12 +1,7 @@
{
"presubmit": [
{
- "name": "PowerStatsTests",
- "options": [
- {"include-filter": "com.android.server.power.stats"},
- {"exclude-annotation": "androidx.test.filters.FlakyTest"},
- {"exclude-annotation": "org.junit.Ignore"}
- ]
+ "name": "PowerStatsTests_power_stats"
}
],
"ravenwood-presubmit": [
@@ -20,11 +15,7 @@
],
"postsubmit": [
{
- "name": "PowerStatsTests",
- "options": [
- {"include-filter": "com.android.server.power.stats"},
- {"exclude-annotation": "org.junit.Ignore"}
- ]
+ "name": "PowerStatsTests_power_stats"
}
]
}
diff --git a/services/tests/selinux/Android.bp b/services/tests/selinux/Android.bp
index 12a7038..048978a 100644
--- a/services/tests/selinux/Android.bp
+++ b/services/tests/selinux/Android.bp
@@ -42,9 +42,9 @@
"mockito_extended",
],
libs: [
- "android.test.base",
- "android.test.mock",
- "android.test.runner",
+ "android.test.base.stubs.system",
+ "android.test.mock.stubs.system",
+ "android.test.runner.stubs.system",
"servicestests-core-utils",
],
static_libs: [
diff --git a/services/tests/servicestests/Android.bp b/services/tests/servicestests/Android.bp
index b41b30c..bbe0755 100644
--- a/services/tests/servicestests/Android.bp
+++ b/services/tests/servicestests/Android.bp
@@ -91,6 +91,7 @@
"net_flags_lib",
"CtsVirtualDeviceCommonLib",
"com_android_server_accessibility_flags_lib",
+ "locksettings_flags_lib",
],
libs: [
diff --git a/services/tests/servicestests/src/com/android/server/location/contexthub/TEST_MAPPING b/services/tests/servicestests/src/com/android/server/location/contexthub/TEST_MAPPING
index 58f5bb3..9b23b49 100644
--- a/services/tests/servicestests/src/com/android/server/location/contexthub/TEST_MAPPING
+++ b/services/tests/servicestests/src/com/android/server/location/contexthub/TEST_MAPPING
@@ -6,23 +6,7 @@
],
"postsubmit": [
{
- "name": "FrameworksServicesTests",
- "options": [
- {
- "include-filter": "com.android.server.location.contexthub."
- },
- {
- // I believe this include annotation is preventing tests from being run
- // as there are no matching tests with the Postsubmit annotation.
- "include-annotation": "android.platform.test.annotations.Postsubmit"
- },
- {
- "exclude-annotation": "androidx.test.filters.FlakyTest"
- },
- {
- "exclude-annotation": "org.junit.Ignore"
- }
- ]
+ "name": "FrameworksServicesTests_com_android_server_location_contexthub"
}
]
}
diff --git a/services/tests/servicestests/src/com/android/server/locksettings/RebootEscrowManagerTests.java b/services/tests/servicestests/src/com/android/server/locksettings/RebootEscrowManagerTests.java
index d6f7e21..d071c15 100644
--- a/services/tests/servicestests/src/com/android/server/locksettings/RebootEscrowManagerTests.java
+++ b/services/tests/servicestests/src/com/android/server/locksettings/RebootEscrowManagerTests.java
@@ -60,6 +60,9 @@
import android.os.ServiceSpecificException;
import android.os.UserManager;
import android.platform.test.annotations.Presubmit;
+import android.platform.test.annotations.RequiresFlagsEnabled;
+import android.platform.test.flag.junit.CheckFlagsRule;
+import android.platform.test.flag.junit.DeviceFlagsValueProvider;
import androidx.test.InstrumentationRegistry;
import androidx.test.filters.SmallTest;
@@ -70,6 +73,7 @@
import com.android.server.pm.UserManagerInternal;
import org.junit.Before;
+import org.junit.Rule;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.ArgumentCaptor;
@@ -108,6 +112,9 @@
0x26, 0x52, 0x72, 0x63, 0x63, 0x61, 0x78, 0x23,
};
+ @Rule
+ public final CheckFlagsRule mCheckFlagsRule = DeviceFlagsValueProvider.createCheckFlagsRule();
+
private Context mContext;
private UserManager mUserManager;
private UserManagerInternal mUserManagerInternal;
@@ -145,7 +152,6 @@
private RebootEscrowProviderInterface mRebootEscrowProviderInUse;
private ConnectivityManager.NetworkCallback mNetworkCallback;
private Consumer<ConnectivityManager.NetworkCallback> mNetworkConsumer;
- private boolean mWaitForInternet;
MockInjector(
Context context,
@@ -159,7 +165,6 @@
super(context, storage, userManagerInternal);
mRebootEscrow = rebootEscrow;
mServerBased = false;
- mWaitForInternet = false;
RebootEscrowProviderHalImpl.Injector halInjector =
new RebootEscrowProviderHalImpl.Injector() {
@Override
@@ -185,7 +190,6 @@
super(context, storage, userManagerInternal);
mRebootEscrow = null;
mServerBased = true;
- mWaitForInternet = false;
RebootEscrowProviderServerBasedImpl.Injector injector =
new RebootEscrowProviderServerBasedImpl.Injector(serviceConnection) {
@Override
@@ -227,15 +231,6 @@
}
@Override
- public boolean waitForInternet() {
- return mWaitForInternet;
- }
-
- public void setWaitForNetwork(boolean waitForNetworkEnabled) {
- mWaitForInternet = waitForNetworkEnabled;
- }
-
- @Override
public boolean isNetworkConnected() {
return false;
}
@@ -934,10 +929,10 @@
}
@Test
+ @RequiresFlagsEnabled(Flags.FLAG_WAIT_FOR_INTERNET_ROR)
public void loadRebootEscrowDataIfAvailable_serverBasedWaitForInternet_success()
throws Exception {
setServerBasedRebootEscrowProvider();
- mMockInjector.setWaitForNetwork(true);
when(mInjected.getBootCount()).thenReturn(0);
RebootEscrowListener mockListener = mock(RebootEscrowListener.class);
@@ -987,10 +982,10 @@
}
@Test
+ @RequiresFlagsEnabled(Flags.FLAG_WAIT_FOR_INTERNET_ROR)
public void loadRebootEscrowDataIfAvailable_serverBasedWaitForInternetRemoteException_Failure()
throws Exception {
setServerBasedRebootEscrowProvider();
- mMockInjector.setWaitForNetwork(true);
when(mInjected.getBootCount()).thenReturn(0);
RebootEscrowListener mockListener = mock(RebootEscrowListener.class);
@@ -1042,10 +1037,10 @@
}
@Test
+ @RequiresFlagsEnabled(Flags.FLAG_WAIT_FOR_INTERNET_ROR)
public void loadRebootEscrowDataIfAvailable_waitForInternet_networkUnavailable()
throws Exception {
setServerBasedRebootEscrowProvider();
- mMockInjector.setWaitForNetwork(true);
when(mInjected.getBootCount()).thenReturn(0);
RebootEscrowListener mockListener = mock(RebootEscrowListener.class);
@@ -1090,9 +1085,9 @@
}
@Test
+ @RequiresFlagsEnabled(Flags.FLAG_WAIT_FOR_INTERNET_ROR)
public void loadRebootEscrowDataIfAvailable_waitForInternet_networkLost() throws Exception {
setServerBasedRebootEscrowProvider();
- mMockInjector.setWaitForNetwork(true);
when(mInjected.getBootCount()).thenReturn(0);
RebootEscrowListener mockListener = mock(RebootEscrowListener.class);
@@ -1145,10 +1140,10 @@
}
@Test
+ @RequiresFlagsEnabled(Flags.FLAG_WAIT_FOR_INTERNET_ROR)
public void loadRebootEscrowDataIfAvailable_waitForInternet_networkAvailableWithDelay()
throws Exception {
setServerBasedRebootEscrowProvider();
- mMockInjector.setWaitForNetwork(true);
when(mInjected.getBootCount()).thenReturn(0);
RebootEscrowListener mockListener = mock(RebootEscrowListener.class);
@@ -1204,10 +1199,10 @@
}
@Test
+ @RequiresFlagsEnabled(Flags.FLAG_WAIT_FOR_INTERNET_ROR)
public void loadRebootEscrowDataIfAvailable_waitForInternet_timeoutExhausted()
throws Exception {
setServerBasedRebootEscrowProvider();
- mMockInjector.setWaitForNetwork(true);
when(mInjected.getBootCount()).thenReturn(0);
RebootEscrowListener mockListener = mock(RebootEscrowListener.class);
@@ -1264,10 +1259,10 @@
}
@Test
+ @RequiresFlagsEnabled(Flags.FLAG_WAIT_FOR_INTERNET_ROR)
public void loadRebootEscrowDataIfAvailable_serverBasedWaitForNetwork_retryCountExhausted()
throws Exception {
setServerBasedRebootEscrowProvider();
- mMockInjector.setWaitForNetwork(true);
when(mInjected.getBootCount()).thenReturn(0);
RebootEscrowListener mockListener = mock(RebootEscrowListener.class);
@@ -1320,10 +1315,10 @@
}
@Test
+ @RequiresFlagsEnabled(Flags.FLAG_WAIT_FOR_INTERNET_ROR)
public void loadRebootEscrowDataIfAvailable_ServerBasedWaitForInternet_RetrySuccess()
throws Exception {
setServerBasedRebootEscrowProvider();
- mMockInjector.setWaitForNetwork(true);
when(mInjected.getBootCount()).thenReturn(0);
RebootEscrowListener mockListener = mock(RebootEscrowListener.class);
diff --git a/services/tests/servicestests/src/com/android/server/om/TEST_MAPPING b/services/tests/servicestests/src/com/android/server/om/TEST_MAPPING
index 944c1df..dc3b144 100644
--- a/services/tests/servicestests/src/com/android/server/om/TEST_MAPPING
+++ b/services/tests/servicestests/src/com/android/server/om/TEST_MAPPING
@@ -4,12 +4,7 @@
"name": "FrameworksServicesTests_om"
},
{
- "name": "PackageManagerServiceHostTests",
- "options": [
- {
- "include-filter": "com.android.server.pm.test.OverlayActorVisibilityTest"
- }
- ]
+ "name": "PackageManagerServiceHostTests_test_overlayactorvisibilitytest"
}
]
}
diff --git a/services/tests/vibrator/TEST_MAPPING b/services/tests/vibrator/TEST_MAPPING
index 39bd238..b17b96a 100644
--- a/services/tests/vibrator/TEST_MAPPING
+++ b/services/tests/vibrator/TEST_MAPPING
@@ -1,12 +1,7 @@
{
"presubmit": [
{
- "name": "FrameworksVibratorServicesTests",
- "options": [
- {"exclude-annotation": "androidx.test.filters.FlakyTest"},
- {"exclude-annotation": "androidx.test.filters.LargeTest"},
- {"exclude-annotation": "org.junit.Ignore"}
- ]
+ "name": "FrameworksVibratorServicesTests"
}
],
"postsubmit": [
diff --git a/services/tests/voiceinteractiontests/TEST_MAPPING b/services/tests/voiceinteractiontests/TEST_MAPPING
index 6cbc49a..466ba54 100644
--- a/services/tests/voiceinteractiontests/TEST_MAPPING
+++ b/services/tests/voiceinteractiontests/TEST_MAPPING
@@ -1,12 +1,7 @@
{
"presubmit": [
{
- "name": "FrameworksVoiceInteractionTests",
- "options": [
- {
- "exclude-annotation": "androidx.test.filters.FlakyTest"
- }
- ]
+ "name": "FrameworksVoiceInteractionTests"
}
],
"postsubmit": [
diff --git a/services/tests/wmtests/src/com/android/server/wm/ActivityRecordTests.java b/services/tests/wmtests/src/com/android/server/wm/ActivityRecordTests.java
index e2e76d6..577b02a 100644
--- a/services/tests/wmtests/src/com/android/server/wm/ActivityRecordTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/ActivityRecordTests.java
@@ -39,6 +39,8 @@
import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_REVERSE_LANDSCAPE;
import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_UNSET;
import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED;
+import static android.content.pm.ApplicationInfo.CATEGORY_SOCIAL;
+import static android.content.pm.ApplicationInfo.CATEGORY_GAME;
import static android.content.res.Configuration.ORIENTATION_LANDSCAPE;
import static android.content.res.Configuration.ORIENTATION_PORTRAIT;
import static android.content.res.Configuration.UI_MODE_TYPE_DESK;
@@ -137,6 +139,7 @@
import android.os.Process;
import android.os.RemoteException;
import android.platform.test.annotations.Presubmit;
+import android.platform.test.annotations.RequiresFlagsEnabled;
import android.provider.DeviceConfig;
import android.util.MutableBoolean;
import android.view.DisplayInfo;
@@ -2655,21 +2658,43 @@
@Test
public void testSetOrientation() {
+ assertSetOrientation(Build.VERSION_CODES.VANILLA_ICE_CREAM, CATEGORY_SOCIAL, true);
+ }
+
+ @Test
+ @RequiresFlagsEnabled(Flags.FLAG_UNIVERSAL_RESIZABLE_BY_DEFAULT)
+ public void testSetOrientation_restrictedByTargetSdk() {
+ assertSetOrientation(Build.VERSION_CODES.CUR_DEVELOPMENT, CATEGORY_SOCIAL, false);
+ assertSetOrientation(Build.VERSION_CODES.CUR_DEVELOPMENT, CATEGORY_GAME, true);
+
+ // Blanket application, also ignoring Target SDK
+ mWm.mConstants.mIgnoreActivityOrientationRequest = true;
+ assertSetOrientation(Build.VERSION_CODES.VANILLA_ICE_CREAM, CATEGORY_SOCIAL, false);
+ }
+
+ private void assertSetOrientation(int targetSdk, int category, boolean expectRotate) {
final ActivityRecord activity = new ActivityBuilder(mAtm).setCreateTask(true).build();
+ activity.mTargetSdk = targetSdk;
+ activity.info.applicationInfo.category = category;
+
activity.setVisible(true);
// Assert orientation is unspecified to start.
assertEquals(SCREEN_ORIENTATION_UNSPECIFIED, activity.getOrientation());
+ // Request orientation and see if it can be applied.
activity.setOrientation(SCREEN_ORIENTATION_LANDSCAPE);
- assertEquals(SCREEN_ORIENTATION_LANDSCAPE, activity.getOrientation());
+ if (expectRotate) {
+ assertEquals("targetSdk=" + targetSdk + " should be able to enter landscape",
+ SCREEN_ORIENTATION_LANDSCAPE, activity.getOrientation());
+ } else {
+ assertEquals("targetSdk=" + targetSdk + " should not be able to enter landscape",
+ SCREEN_ORIENTATION_UNSPECIFIED, activity.getOrientation());
+ }
mDisplayContent.removeAppToken(activity.token);
// Assert orientation is unset to after container is removed.
assertEquals(SCREEN_ORIENTATION_UNSET, activity.getOrientation());
-
- // Reset display frozen state
- mWm.mDisplayFrozen = false;
}
@Test
diff --git a/services/tests/wmtests/src/com/android/server/wm/DisplayContentTests.java b/services/tests/wmtests/src/com/android/server/wm/DisplayContentTests.java
index eca4d21..85cb1bc 100644
--- a/services/tests/wmtests/src/com/android/server/wm/DisplayContentTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/DisplayContentTests.java
@@ -369,8 +369,10 @@
"startingWin");
startingWin.setHasSurface(true);
assertTrue(startingWin.canBeImeTarget());
+ final WindowContainer imeSurfaceParentWindow = mock(WindowContainer.class);
final SurfaceControl imeSurfaceParent = mock(SurfaceControl.class);
- doReturn(imeSurfaceParent).when(mDisplayContent).computeImeParent();
+ doReturn(imeSurfaceParent).when(imeSurfaceParentWindow).getSurfaceControl();
+ doReturn(imeSurfaceParentWindow).when(mDisplayContent).computeImeParent();
spyOn(imeContainer);
mDisplayContent.setImeInputTarget(startingWin);
@@ -406,8 +408,11 @@
"startingWin");
startingWin.setHasSurface(true);
assertTrue(startingWin.canBeImeTarget());
+ final WindowContainer imeSurfaceParentWindow = mock(WindowContainer.class);
final SurfaceControl imeSurfaceParent = mock(SurfaceControl.class);
- doReturn(imeSurfaceParent).when(mDisplayContent).computeImeParent();
+ doReturn(imeSurfaceParent).when(imeSurfaceParentWindow).getSurfaceControl();
+ doReturn(imeSurfaceParentWindow).when(mDisplayContent).computeImeParent();
+
// Main precondition for this test: organize the ImeContainer.
final IDisplayAreaOrganizer mockImeOrganizer = mock(IDisplayAreaOrganizer.class);
@@ -639,10 +644,11 @@
ws.matchesDisplayAreaBounds());
assertTrue("IME shouldn't be attached to app",
- dc.computeImeParent() != dc.getImeTarget(IME_TARGET_LAYERING).getWindow()
- .mActivityRecord.getSurfaceControl());
+ dc.computeImeParent().getSurfaceControl() != dc.getImeTarget(
+ IME_TARGET_LAYERING).getWindow().mActivityRecord.getSurfaceControl());
assertEquals("IME should be attached to display",
- dc.getImeContainer().getParent().getSurfaceControl(), dc.computeImeParent());
+ dc.getImeContainer().getParent().getSurfaceControl(),
+ dc.computeImeParent().getSurfaceControl());
}
private WindowState[] createNotDrawnWindowsOn(DisplayContent displayContent, int... types) {
@@ -1191,8 +1197,9 @@
final DisplayContent dc = createNewDisplay();
dc.setImeLayeringTarget(createWindow(null, TYPE_BASE_APPLICATION, "app"));
dc.setImeInputTarget(dc.getImeTarget(IME_TARGET_LAYERING).getWindow());
- assertEquals(dc.getImeTarget(IME_TARGET_LAYERING).getWindow()
- .mActivityRecord.getSurfaceControl(), dc.computeImeParent());
+ assertEquals(dc.getImeTarget(
+ IME_TARGET_LAYERING).getWindow().mActivityRecord.getSurfaceControl(),
+ dc.computeImeParent().getSurfaceControl());
}
@Test
@@ -1202,7 +1209,8 @@
dc.getImeTarget(IME_TARGET_LAYERING).getWindow().setWindowingMode(
WindowConfiguration.WINDOWING_MODE_MULTI_WINDOW);
dc.setImeInputTarget(dc.getImeTarget(IME_TARGET_LAYERING).getWindow());
- assertEquals(dc.getImeContainer().getParentSurfaceControl(), dc.computeImeParent());
+ assertEquals(dc.getImeContainer().getParentSurfaceControl(),
+ dc.computeImeParent().getSurfaceControl());
}
@SetupWindows(addWindows = W_ACTIVITY)
@@ -1213,7 +1221,7 @@
mDisplayContent.setImeLayeringTarget(mAppWindow);
// The surface parent of IME should be the display instead of app window.
assertEquals(mDisplayContent.getImeContainer().getParentSurfaceControl(),
- mDisplayContent.computeImeParent());
+ mDisplayContent.computeImeParent().getSurfaceControl());
}
@Test
@@ -1221,7 +1229,8 @@
final DisplayContent dc = createNewDisplay();
dc.setImeLayeringTarget(createWindow(null, TYPE_STATUS_BAR, "statusBar"));
dc.setImeInputTarget(dc.getImeTarget(IME_TARGET_LAYERING).getWindow());
- assertEquals(dc.getImeContainer().getParentSurfaceControl(), dc.computeImeParent());
+ assertEquals(dc.getImeContainer().getParentSurfaceControl(),
+ dc.computeImeParent().getSurfaceControl());
}
@SetupWindows(addWindows = W_ACTIVITY)
@@ -1232,7 +1241,8 @@
doReturn(true).when(mDisplayContent).shouldImeAttachedToApp();
mDisplayContent.setImeLayeringTarget(app1);
mDisplayContent.setImeInputTarget(app1);
- assertEquals(app1.mActivityRecord.getSurfaceControl(), mDisplayContent.computeImeParent());
+ assertEquals(app1.mActivityRecord.getSurfaceControl(),
+ mDisplayContent.computeImeParent().getSurfaceControl());
mDisplayContent.setImeLayeringTarget(app2);
// Expect null means no change IME parent when the IME layering target not yet
// request IME to be the input target.
@@ -1250,7 +1260,7 @@
mDisplayContent.setImeInputTarget(app);
assertFalse(mDisplayContent.shouldImeAttachedToApp());
assertEquals(mDisplayContent.getImeContainer().getParentSurfaceControl(),
- mDisplayContent.computeImeParent());
+ mDisplayContent.computeImeParent().getSurfaceControl());
}
@Test
@@ -1275,7 +1285,8 @@
assertEquals(dc.getImeTarget(IME_TARGET_LAYERING), dc.getImeInputTarget());
// The ImeParent should be the display.
- assertEquals(dc.getImeContainer().getParent().getSurfaceControl(), dc.computeImeParent());
+ assertEquals(dc.getImeContainer().getParent().getSurfaceControl(),
+ dc.computeImeParent().getSurfaceControl());
}
@Test
diff --git a/services/tests/wmtests/src/com/android/server/wm/DisplayWindowSettingsProviderTests.java b/services/tests/wmtests/src/com/android/server/wm/DisplayWindowSettingsProviderTests.java
index 2f2b473..b7aa730 100644
--- a/services/tests/wmtests/src/com/android/server/wm/DisplayWindowSettingsProviderTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/DisplayWindowSettingsProviderTests.java
@@ -45,6 +45,7 @@
import com.android.modules.utils.TypedXmlPullParser;
import com.android.server.wm.DisplayWindowSettings.SettingsProvider.SettingsEntry;
+import com.android.server.wm.TestDisplayWindowSettingsProvider.TestStorage;
import org.junit.After;
import org.junit.Before;
@@ -516,81 +517,4 @@
}
return fullyDeleted;
}
-
- /** In-memory storage implementation. */
- public class TestStorage implements DisplayWindowSettingsProvider.WritableSettingsStorage {
- private InputStream mReadStream;
- private ByteArrayOutputStream mWriteStream;
-
- private boolean mWasSuccessful;
-
- /**
- * Returns input stream for reading. By default tries forward the output stream if previous
- * write was successful.
- * @see #closeRead()
- */
- @Override
- public InputStream openRead() throws FileNotFoundException {
- if (mReadStream == null && mWasSuccessful) {
- mReadStream = new ByteArrayInputStream(mWriteStream.toByteArray());
- }
- if (mReadStream == null) {
- throw new FileNotFoundException();
- }
- if (mReadStream.markSupported()) {
- mReadStream.mark(Integer.MAX_VALUE);
- }
- return mReadStream;
- }
-
- /** Must be called after each {@link #openRead} to reset the position in the stream. */
- void closeRead() throws IOException {
- if (mReadStream == null) {
- throw new FileNotFoundException();
- }
- if (mReadStream.markSupported()) {
- mReadStream.reset();
- }
- mReadStream = null;
- }
-
- /**
- * Creates new or resets existing output stream for write. Automatically closes previous
- * read stream, since following reads should happen based on this new write.
- */
- @Override
- public OutputStream startWrite() throws IOException {
- if (mWriteStream == null) {
- mWriteStream = new ByteArrayOutputStream();
- } else {
- mWriteStream.reset();
- }
- if (mReadStream != null) {
- closeRead();
- }
- return mWriteStream;
- }
-
- @Override
- public void finishWrite(OutputStream os, boolean success) {
- mWasSuccessful = success;
- try {
- os.close();
- } catch (IOException e) {
- // This method can't throw IOException since the super implementation doesn't, so
- // we just wrap it in a RuntimeException so we end up crashing the test all the
- // same.
- throw new RuntimeException(e);
- }
- }
-
- /** Overrides the read stream of the injector. By default it uses current write stream. */
- private void setReadStream(InputStream is) {
- mReadStream = is;
- }
-
- private boolean wasWriteSuccessful() {
- return mWasSuccessful;
- }
- }
}
diff --git a/services/tests/wmtests/src/com/android/server/wm/SystemServicesTestRule.java b/services/tests/wmtests/src/com/android/server/wm/SystemServicesTestRule.java
index 71cfbfd..08622e6 100644
--- a/services/tests/wmtests/src/com/android/server/wm/SystemServicesTestRule.java
+++ b/services/tests/wmtests/src/com/android/server/wm/SystemServicesTestRule.java
@@ -133,6 +133,7 @@
private final ArrayList<DeviceConfig.OnPropertiesChangedListener> mDeviceConfigListeners =
new ArrayList<>();
+ private AppCompatConfiguration mAppCompat;
private Description mDescription;
private Context mContext;
private StaticMockitoSession mMockitoSession;
@@ -379,6 +380,11 @@
mock(ActivityManagerService.class, withSettings().stubOnly());
mAtmService = new TestActivityTaskManagerService(mContext, amService);
LocalServices.addService(ActivityTaskManagerInternal.class, mAtmService.getAtmInternal());
+
+ // AppCompatConfiguration
+ mAppCompat = new AppCompatConfiguration(
+ ActivityThread.currentActivityThread().getSystemUiContext());
+
// Create a fake WindowProcessController for the system process.
final WindowProcessController wpc =
addProcess("android", "system", 1485 /* pid */, 1000 /* uid */);
@@ -394,7 +400,7 @@
mWmService = WindowManagerService.main(
mContext, mImService, false, wmPolicy, mAtmService,
testDisplayWindowSettingsProvider, StubTransaction::new,
- MockSurfaceControlBuilder::new);
+ MockSurfaceControlBuilder::new, mAppCompat);
spyOn(mWmService);
spyOn(mWmService.mRoot);
// Invoked during {@link ActivityStack} creation.
diff --git a/services/tests/wmtests/src/com/android/server/wm/TaskFragmentTest.java b/services/tests/wmtests/src/com/android/server/wm/TaskFragmentTest.java
index fd959b9..65a6a69 100644
--- a/services/tests/wmtests/src/com/android/server/wm/TaskFragmentTest.java
+++ b/services/tests/wmtests/src/com/android/server/wm/TaskFragmentTest.java
@@ -884,7 +884,7 @@
// The ImeParent should be the display.
assertEquals(mDisplayContent.getImeContainer().getParent().getSurfaceControl(),
- mDisplayContent.computeImeParent());
+ mDisplayContent.computeImeParent().getSurfaceControl());
}
@Test
diff --git a/services/tests/wmtests/src/com/android/server/wm/TestDisplayWindowSettingsProvider.java b/services/tests/wmtests/src/com/android/server/wm/TestDisplayWindowSettingsProvider.java
index e11df98..877f65c 100644
--- a/services/tests/wmtests/src/com/android/server/wm/TestDisplayWindowSettingsProvider.java
+++ b/services/tests/wmtests/src/com/android/server/wm/TestDisplayWindowSettingsProvider.java
@@ -22,6 +22,16 @@
import java.util.HashMap;
import java.util.Map;
+import com.android.server.wm.DisplayWindowSettingsProvider.WritableSettingsStorage;
+import com.android.server.wm.DisplayWindowSettings.SettingsProvider.SettingsEntry;
+
+import java.io.ByteArrayInputStream;
+import java.io.ByteArrayOutputStream;
+import java.io.FileNotFoundException;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+
/**
* In-memory DisplayWindowSettingsProvider used in tests. Ensures no settings are read from or
* written to device-specific display settings files.
@@ -30,6 +40,10 @@
private final Map<String, SettingsEntry> mOverrideSettingsMap = new HashMap<>();
+ public TestDisplayWindowSettingsProvider() {
+ super(new TestStorage(), new TestStorage());
+ }
+
@Override
@NonNull
public SettingsEntry getSettings(@NonNull DisplayInfo info) {
@@ -76,4 +90,81 @@
private static String getIdentifier(DisplayInfo displayInfo) {
return displayInfo.uniqueId;
}
+
+ /** In-memory storage implementation. */
+ public static class TestStorage implements WritableSettingsStorage {
+ private InputStream mReadStream;
+ private ByteArrayOutputStream mWriteStream;
+
+ private boolean mWasSuccessful;
+
+ /**
+ * Returns input stream for reading. By default tries forward the output stream if previous
+ * write was successful.
+ * @see #closeRead()
+ */
+ @Override
+ public InputStream openRead() throws FileNotFoundException {
+ if (mReadStream == null && mWasSuccessful) {
+ mReadStream = new ByteArrayInputStream(mWriteStream.toByteArray());
+ }
+ if (mReadStream == null) {
+ throw new FileNotFoundException();
+ }
+ if (mReadStream.markSupported()) {
+ mReadStream.mark(Integer.MAX_VALUE);
+ }
+ return mReadStream;
+ }
+
+ /** Must be called after each {@link #openRead} to reset the position in the stream. */
+ public void closeRead() throws IOException {
+ if (mReadStream == null) {
+ throw new FileNotFoundException();
+ }
+ if (mReadStream.markSupported()) {
+ mReadStream.reset();
+ }
+ mReadStream = null;
+ }
+
+ /**
+ * Creates new or resets existing output stream for write. Automatically closes previous
+ * read stream, since following reads should happen based on this new write.
+ */
+ @Override
+ public OutputStream startWrite() throws IOException {
+ if (mWriteStream == null) {
+ mWriteStream = new ByteArrayOutputStream();
+ } else {
+ mWriteStream.reset();
+ }
+ if (mReadStream != null) {
+ closeRead();
+ }
+ return mWriteStream;
+ }
+
+ @Override
+ public void finishWrite(OutputStream os, boolean success) {
+ mWasSuccessful = success;
+ try {
+ os.close();
+ } catch (IOException e) {
+ // This method can't throw IOException since the super implementation doesn't, so
+ // we just wrap it in a RuntimeException so we end up crashing the test all the
+ // same.
+ throw new RuntimeException(e);
+ }
+ }
+
+ /** Overrides the read stream of the injector. By default it uses current write stream. */
+ public void setReadStream(InputStream is) {
+ mReadStream = is;
+ }
+
+ public boolean wasWriteSuccessful() {
+ return mWasSuccessful;
+ }
+ }
}
diff --git a/services/tests/wmtests/src/com/android/server/wm/WindowStateTests.java b/services/tests/wmtests/src/com/android/server/wm/WindowStateTests.java
index 5a54af1..2d5e5da 100644
--- a/services/tests/wmtests/src/com/android/server/wm/WindowStateTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/WindowStateTests.java
@@ -80,6 +80,7 @@
import static org.mockito.Mockito.atLeast;
import static org.mockito.Mockito.atMost;
import static org.mockito.Mockito.clearInvocations;
+import static org.mockito.Mockito.doAnswer;
import static org.mockito.Mockito.reset;
import static org.mockito.Mockito.when;
@@ -88,9 +89,12 @@
import android.graphics.Matrix;
import android.graphics.Point;
import android.graphics.Rect;
+import android.graphics.Region;
import android.os.IBinder;
import android.os.InputConfig;
import android.os.RemoteException;
+import android.platform.test.annotations.DisableFlags;
+import android.platform.test.annotations.EnableFlags;
import android.platform.test.annotations.Presubmit;
import android.platform.test.annotations.RequiresFlagsEnabled;
import android.util.ArraySet;
@@ -116,6 +120,7 @@
import com.android.server.inputmethod.InputMethodManagerInternal;
import com.android.server.testutils.StubTransaction;
import com.android.server.wm.SensitiveContentPackages.PackageInfo;
+import com.android.window.flags.Flags;
import org.junit.After;
import org.junit.Test;
@@ -965,6 +970,88 @@
assertTrue(testFlag(handle.inputConfig, InputConfig.NO_INPUT_CHANNEL));
}
+ @DisableFlags(Flags.FLAG_SCROLLING_FROM_LETTERBOX)
+ @Test
+ public void testTouchRegionUsesLetterboxBoundsIfTransformedBoundsAndLetterboxScrolling() {
+ final WindowState win = createWindow(null, TYPE_APPLICATION, "win");
+
+ // Transformed bounds used for size of touchable region if letterbox inner bounds are empty.
+ final Rect transformedBounds = new Rect(0, 0, 300, 500);
+ doReturn(transformedBounds).when(win.mToken).getFixedRotationTransformDisplayBounds();
+
+ // Otherwise, touchable region should match letterbox inner bounds.
+ final Rect letterboxInnerBounds = new Rect(30, 0, 270, 500);
+ doAnswer(invocation -> {
+ Rect rect = invocation.getArgument(0);
+ rect.set(letterboxInnerBounds);
+ return null;
+ }).when(win.mActivityRecord).getLetterboxInnerBounds(any());
+
+ Region outRegion = new Region();
+ win.getSurfaceTouchableRegion(outRegion, win.mAttrs);
+
+ // Because scrollingFromLetterbox flag is disabled and letterboxInnerBounds is not empty,
+ // touchable region should match letterboxInnerBounds always.
+ assertEquals(letterboxInnerBounds, outRegion.getBounds());
+ }
+
+ @DisableFlags(Flags.FLAG_SCROLLING_FROM_LETTERBOX)
+ @Test
+ public void testTouchRegionUsesLetterboxBoundsIfNullTransformedBoundsAndLetterboxScrolling() {
+ final WindowState win = createWindow(null, TYPE_APPLICATION, "win");
+
+ // Fragment bounds used for size of touchable region if letterbox inner bounds are empty
+ // and Transform bounds are null.
+ doReturn(null).when(win.mToken).getFixedRotationTransformDisplayBounds();
+ final Rect fragmentBounds = new Rect(0, 0, 300, 500);
+ final TaskFragment taskFragment = win.mActivityRecord.getTaskFragment();
+ doAnswer(invocation -> {
+ Rect rect = invocation.getArgument(0);
+ rect.set(fragmentBounds);
+ return null;
+ }).when(taskFragment).getDimBounds(any());
+
+ // Otherwise, touchable region should match letterbox inner bounds.
+ final Rect letterboxInnerBounds = new Rect(30, 0, 270, 500);
+ doAnswer(invocation -> {
+ Rect rect = invocation.getArgument(0);
+ rect.set(letterboxInnerBounds);
+ return null;
+ }).when(win.mActivityRecord).getLetterboxInnerBounds(any());
+
+ Region outRegion = new Region();
+ win.getSurfaceTouchableRegion(outRegion, win.mAttrs);
+
+ // Because scrollingFromLetterbox flag is disabled and letterboxInnerBounds is not empty,
+ // touchable region should match letterboxInnerBounds always.
+ assertEquals(letterboxInnerBounds, outRegion.getBounds());
+ }
+
+ @EnableFlags(Flags.FLAG_SCROLLING_FROM_LETTERBOX)
+ @Test
+ public void testTouchRegionUsesTransformedBoundsIfLetterboxScrolling() {
+ final WindowState win = createWindow(null, TYPE_APPLICATION, "win");
+
+ // Transformed bounds used for size of touchable region if letterbox inner bounds are empty.
+ final Rect transformedBounds = new Rect(0, 0, 300, 500);
+ doReturn(transformedBounds).when(win.mToken).getFixedRotationTransformDisplayBounds();
+
+ // Otherwise, touchable region should match letterbox inner bounds.
+ final Rect letterboxInnerBounds = new Rect(30, 0, 270, 500);
+ doAnswer(invocation -> {
+ Rect rect = invocation.getArgument(0);
+ rect.set(letterboxInnerBounds);
+ return null;
+ }).when(win.mActivityRecord).getLetterboxInnerBounds(any());
+
+ Region outRegion = new Region();
+ win.getSurfaceTouchableRegion(outRegion, win.mAttrs);
+
+ // Because scrollingFromLetterbox flag is enabled and transformedBounds are non-null,
+ // touchable region should match transformedBounds.
+ assertEquals(transformedBounds, outRegion.getBounds());
+ }
+
@Test
public void testHasActiveVisibleWindow() {
final int uid = ActivityBuilder.DEFAULT_FAKE_UID;
diff --git a/services/translation/java/com/android/server/translation/TEST_MAPPING b/services/translation/java/com/android/server/translation/TEST_MAPPING
index 4090b4a..0b97358 100644
--- a/services/translation/java/com/android/server/translation/TEST_MAPPING
+++ b/services/translation/java/com/android/server/translation/TEST_MAPPING
@@ -1,12 +1,7 @@
{
"presubmit": [
{
- "name": "CtsTranslationTestCases",
- "options": [
- {
- "exclude-annotation": "androidx.test.filters.FlakyTest"
- }
- ]
+ "name": "CtsTranslationTestCases"
}
]
}
diff --git a/services/usage/java/com/android/server/usage/TEST_MAPPING b/services/usage/java/com/android/server/usage/TEST_MAPPING
index c878054..79b294c 100644
--- a/services/usage/java/com/android/server/usage/TEST_MAPPING
+++ b/services/usage/java/com/android/server/usage/TEST_MAPPING
@@ -7,33 +7,15 @@
"name": "FrameworksServicesTests_android_server_usage"
},
{
- "name": "CtsBRSTestCases",
- "options": [
- {
- "exclude-annotation": "androidx.test.filters.FlakyTest"
- },
- {
- "exclude-annotation": "org.junit.Ignore"
- }
- ]
+ "name": "CtsBRSTestCases"
}
],
"postsubmit": [
{
- "name": "CtsUsageStatsTestCases",
- "options": [
- {
- "include-filter": "android.app.usage.cts.UsageStatsTest"
- }
- ]
+ "name": "CtsUsageStatsTestCases_cts_usagestatstest_ExcludeMediumAndLarge"
},
{
- "name": "CtsShortcutManagerTestCases",
- "options": [
- {
- "include-filter": "android.content.pm.cts.shortcutmanager.ShortcutManagerUsageTest"
- }
- ]
+ "name": "CtsShortcutManagerTestCases_shortcutmanager_shortcutmanagerusagetest"
}
]
}
diff --git a/services/voiceinteraction/TEST_MAPPING b/services/voiceinteraction/TEST_MAPPING
index e3d2549..3a68b33 100644
--- a/services/voiceinteraction/TEST_MAPPING
+++ b/services/voiceinteraction/TEST_MAPPING
@@ -12,44 +12,19 @@
]
},
{
- "name": "CtsAssistTestCases",
- "options": [
- {
- "exclude-annotation": "androidx.test.filters.FlakyTest"
- }
- ]
+ "name": "CtsAssistTestCases"
},
{
- "name": "CtsVoiceInteractionHostTestCases",
- "options": [
- {
- "exclude-annotation": "androidx.test.filters.FlakyTest"
- }
- ]
+ "name": "CtsVoiceInteractionHostTestCases"
},
{
- "name": "CtsLocalVoiceInteraction",
- "options": [
- {
- "exclude-annotation": "androidx.test.filters.FlakyTest"
- }
- ]
+ "name": "CtsLocalVoiceInteraction"
},
{
- "name": "FrameworksVoiceInteractionTests",
- "options": [
- {
- "exclude-annotation": "androidx.test.filters.FlakyTest"
- }
- ]
+ "name": "FrameworksVoiceInteractionTests"
},
{
- "name": "CtsSoundTriggerTestCases",
- "options": [
- {
- "exclude-annotation": "androidx.test.filters.FlakyTest"
- }
- ]
+ "name": "CtsSoundTriggerTestCases"
}
]
}
diff --git a/telecomm/TEST_MAPPING b/telecomm/TEST_MAPPING
index 775f1b8..4f6e558 100644
--- a/telecomm/TEST_MAPPING
+++ b/telecomm/TEST_MAPPING
@@ -1,70 +1,30 @@
{
"presubmit": [
{
- "name": "TeleServiceTests",
- "options": [
- {
- "exclude-annotation": "androidx.test.filters.FlakyTest"
- }
- ]
+ "name": "TeleServiceTests"
},
{
- "name": "TelecomUnitTests",
- "options": [
- {
- "exclude-annotation": "androidx.test.filters.FlakyTest"
- }
- ]
+ "name": "TelecomUnitTests"
},
{
- "name": "TelephonyProviderTests",
- "options": [
- {
- "exclude-annotation": "androidx.test.filters.FlakyTest"
- }
- ]
+ "name": "TelephonyProviderTests"
},
{
- "name": "CtsTelephony2TestCases",
- "options": [
- {
- "exclude-annotation": "androidx.test.filters.FlakyTest"
- }
- ]
+ "name": "CtsTelephony2TestCases"
},
{
- "name": "CtsTelephony3TestCases",
- "options": [
- {
- "exclude-annotation": "androidx.test.filters.FlakyTest"
- }
- ]
+ "name": "CtsTelephony3TestCases"
},
{
- "name": "CtsSimRestrictedApisTestCases",
- "options": [
- {
- "exclude-annotation": "androidx.test.filters.FlakyTest"
- }
- ]
+ "name": "CtsSimRestrictedApisTestCases"
},
{
- "name": "CtsTelephonyProviderTestCases",
- "options": [
- {
- "exclude-annotation": "androidx.test.filters.FlakyTest"
- }
- ]
+ "name": "CtsTelephonyProviderTestCases"
}
],
"presubmit-large": [
{
- "name": "CtsTelecomTestCases",
- "options": [
- {
- "exclude-annotation": "androidx.test.filters.FlakyTest"
- }
- ]
+ "name": "CtsTelecomTestCases"
}
]
}
diff --git a/telephony/TEST_MAPPING b/telephony/TEST_MAPPING
index 73e3dcd..4a4bae3 100644
--- a/telephony/TEST_MAPPING
+++ b/telephony/TEST_MAPPING
@@ -1,60 +1,25 @@
{
"presubmit": [
{
- "name": "TeleServiceTests",
- "options": [
- {
- "exclude-annotation": "androidx.test.filters.FlakyTest"
- }
- ]
+ "name": "TeleServiceTests"
},
{
- "name": "TelecomUnitTests",
- "options": [
- {
- "exclude-annotation": "androidx.test.filters.FlakyTest"
- }
- ]
+ "name": "TelecomUnitTests"
},
{
- "name": "TelephonyProviderTests",
- "options": [
- {
- "exclude-annotation": "androidx.test.filters.FlakyTest"
- }
- ]
+ "name": "TelephonyProviderTests"
},
{
- "name": "CtsTelephony2TestCases",
- "options": [
- {
- "exclude-annotation": "androidx.test.filters.FlakyTest"
- }
- ]
+ "name": "CtsTelephony2TestCases"
},
{
- "name": "CtsTelephony3TestCases",
- "options": [
- {
- "exclude-annotation": "androidx.test.filters.FlakyTest"
- }
- ]
+ "name": "CtsTelephony3TestCases"
},
{
- "name": "CtsSimRestrictedApisTestCases",
- "options": [
- {
- "exclude-annotation": "androidx.test.filters.FlakyTest"
- }
- ]
+ "name": "CtsSimRestrictedApisTestCases"
},
{
- "name": "CtsTelephonyProviderTestCases",
- "options": [
- {
- "exclude-annotation": "androidx.test.filters.FlakyTest"
- }
- ]
+ "name": "CtsTelephonyProviderTestCases"
}
]
}
diff --git a/telephony/common/com/android/internal/telephony/util/TelephonyUtils.java b/telephony/common/com/android/internal/telephony/util/TelephonyUtils.java
index f31a87f..4224338 100644
--- a/telephony/common/com/android/internal/telephony/util/TelephonyUtils.java
+++ b/telephony/common/com/android/internal/telephony/util/TelephonyUtils.java
@@ -60,6 +60,7 @@
public final class TelephonyUtils {
private static final String LOG_TAG = "TelephonyUtils";
+ public static final boolean FORCE_VERBOSE_STATE_LOGGING = false; /* stopship if true */
public static boolean IS_USER = "user".equals(android.os.Build.TYPE);
public static boolean IS_DEBUGGABLE = SystemProperties.getInt("ro.debuggable", 0) == 1;
diff --git a/tests/AttestationVerificationTest/src/com/android/server/security/AttestationVerificationPeerDeviceVerifierTest.kt b/tests/AttestationVerificationTest/src/com/android/server/security/AttestationVerificationPeerDeviceVerifierTest.kt
index afb3593..4712d6b 100644
--- a/tests/AttestationVerificationTest/src/com/android/server/security/AttestationVerificationPeerDeviceVerifierTest.kt
+++ b/tests/AttestationVerificationTest/src/com/android/server/security/AttestationVerificationPeerDeviceVerifierTest.kt
@@ -4,6 +4,7 @@
import android.content.Context
import android.os.Bundle
import android.security.attestationverification.AttestationVerificationManager.PARAM_CHALLENGE
+import android.security.attestationverification.AttestationVerificationManager.PARAM_MAX_PATCH_LEVEL_DIFF_MONTHS
import android.security.attestationverification.AttestationVerificationManager.PARAM_PUBLIC_KEY
import android.security.attestationverification.AttestationVerificationManager.RESULT_FAILURE
import android.security.attestationverification.AttestationVerificationManager.RESULT_SUCCESS
@@ -162,6 +163,41 @@
}
@Test
+ fun verifyAttestation_returnsSuccessPatchDataWithinMaxPatchDiff() {
+ val verifier = AttestationVerificationPeerDeviceVerifier(
+ context, dumpLogger, trustAnchors, false, LocalDate.of(2023, 3, 1),
+ LocalDate.of(2023, 2, 1)
+ )
+ val challengeRequirements = Bundle()
+ challengeRequirements.putByteArray(PARAM_CHALLENGE, "player456".encodeToByteArray())
+ challengeRequirements.putInt(PARAM_MAX_PATCH_LEVEL_DIFF_MONTHS, 24)
+
+ val result = verifier.verifyAttestation(
+ TYPE_CHALLENGE, challengeRequirements,
+ TEST_ATTESTATION_WITH_ROOT_CERT_FILENAME.fromPEMFileToByteArray()
+ )
+ assertThat(result).isEqualTo(RESULT_SUCCESS)
+ }
+
+ @Test
+ fun verifyAttestation_returnsFailurePatchDataNotWithinMaxPatchDiff() {
+ val verifier = AttestationVerificationPeerDeviceVerifier(
+ context, dumpLogger, trustAnchors, false, LocalDate.of(2024, 10, 1),
+ LocalDate.of(2024, 9, 1)
+ )
+ val challengeRequirements = Bundle()
+ challengeRequirements.putByteArray(PARAM_CHALLENGE, "player456".encodeToByteArray())
+ challengeRequirements.putInt(PARAM_MAX_PATCH_LEVEL_DIFF_MONTHS, 24)
+
+ val result = verifier.verifyAttestation(
+ TYPE_CHALLENGE, challengeRequirements,
+ // The patch date of this file is early 2022
+ TEST_ATTESTATION_WITH_ROOT_CERT_FILENAME.fromPEMFileToByteArray()
+ )
+ assertThat(result).isEqualTo(RESULT_FAILURE)
+ }
+
+ @Test
fun verifyAttestation_returnsFailureTrustedAnchorEmpty() {
val verifier = AttestationVerificationPeerDeviceVerifier(
context, dumpLogger, HashSet(), false, LocalDate.of(2022, 1, 1),
diff --git a/tests/FlickerTests/test-apps/flickerapp/Android.bp b/tests/FlickerTests/test-apps/flickerapp/Android.bp
index e3b23b9..a186679 100644
--- a/tests/FlickerTests/test-apps/flickerapp/Android.bp
+++ b/tests/FlickerTests/test-apps/flickerapp/Android.bp
@@ -19,6 +19,7 @@
// to get the below license kinds:
// SPDX-license-identifier-Apache-2.0
default_applicable_licenses: ["frameworks_base_license"],
+ default_team: "trendy_team_windowing_tools",
}
android_test {
diff --git a/tests/Input/AndroidManifest.xml b/tests/Input/AndroidManifest.xml
index a05d08c..914adc4 100644
--- a/tests/Input/AndroidManifest.xml
+++ b/tests/Input/AndroidManifest.xml
@@ -32,6 +32,14 @@
android:process=":externalProcess">
</activity>
+ <activity android:name="com.android.test.input.CaptureEventActivity"
+ android:label="Capture events"
+ android:configChanges="touchscreen|uiMode|orientation|screenSize|screenLayout|keyboardHidden|uiMode|navigation|keyboard|density|fontScale|layoutDirection|locale|mcc|mnc|smallestScreenSize"
+ android:enableOnBackInvokedCallback="false"
+ android:turnScreenOn="true"
+ android:exported="true">
+ </activity>
+
</application>
<instrumentation android:name="androidx.test.runner.AndroidJUnitRunner"
android:targetPackage="com.android.test.input"
diff --git a/tests/Input/res/raw/google_pixel_tablet_touchscreen.evemu b/tests/Input/res/raw/google_pixel_tablet_touchscreen.evemu
new file mode 100644
index 0000000..1a9112b
--- /dev/null
+++ b/tests/Input/res/raw/google_pixel_tablet_touchscreen.evemu
@@ -0,0 +1,150 @@
+# EVEMU 1.2
+# One finger swipe gesture on the Google Pixel Tablet touchscreen
+N: NVTCapacitiveTouchScreen
+I: 001c 0603 7806 0100
+P: 02 00 00 00 00 00 00 00
+B: 00 0b 00 00 00 00 00 00 00
+B: 01 00 00 00 00 00 00 00 00
+B: 01 00 00 00 00 00 00 00 00
+B: 01 00 80 00 00 00 00 00 00
+B: 01 00 00 00 00 00 00 00 00
+B: 01 00 00 00 00 00 00 00 00
+B: 01 00 04 00 00 00 00 00 00
+B: 01 00 00 00 00 00 00 00 00
+B: 01 00 00 00 00 00 00 00 00
+B: 01 00 00 00 00 00 00 00 00
+B: 01 00 00 00 00 00 00 00 00
+B: 01 00 00 00 00 00 00 00 00
+B: 01 00 00 00 00 00 00 00 00
+B: 02 00 00 00 00 00 00 00 00
+B: 03 00 00 00 00 00 80 f3 46
+B: 04 00 00 00 00 00 00 00 00
+B: 05 00 00 00 00 00 00 00 00
+B: 11 00 00 00 00 00 00 00 00
+B: 12 00 00 00 00 00 00 00 00
+A: 2f 0 9 0 0 0
+A: 30 0 2559 0 0 11
+A: 31 0 1599 0 0 11
+A: 34 -4096 4096 0 0 0
+A: 35 0 1599 0 0 11
+A: 36 0 2559 0 0 11
+A: 37 0 2 0 0 0
+A: 39 0 65535 0 0 0
+A: 3a 0 256 0 0 0
+A: 3e 0 8 0 0 0
+E: 0.000001 0001 014a 0001
+E: 0.000001 0003 0039 0003
+E: 0.000001 0003 0035 0810
+E: 0.000001 0003 0036 1650
+E: 0.000001 0003 0030 0082
+E: 0.000001 0003 0031 0077
+E: 0.000001 0003 003a 0215
+E: 0.000001 0003 0034 3218
+E: 0.000001 0000 0000 0000
+E: 0.008818 0003 0035 0825
+E: 0.008818 0003 0036 1645
+E: 0.008818 0003 0034 3217
+E: 0.008818 0000 0000 0000
+E: 0.016306 0003 0035 0841
+E: 0.016306 0003 0036 1639
+E: 0.016306 0003 0034 3102
+E: 0.016306 0000 0000 0000
+E: 0.025653 0003 0035 0862
+E: 0.025653 0003 0036 1630
+E: 0.025653 0003 0034 3092
+E: 0.025653 0000 0000 0000
+E: 0.032936 0003 0035 0883
+E: 0.032936 0003 0036 1619
+E: 0.032936 0003 0034 3030
+E: 0.032936 0000 0000 0000
+E: 0.042072 0003 0035 0905
+E: 0.042072 0003 0036 1604
+E: 0.042072 0003 0034 2848
+E: 0.042072 0000 0000 0000
+E: 0.049569 0003 0035 0924
+E: 0.049569 0003 0036 1591
+E: 0.049569 0003 0034 2830
+E: 0.049569 0000 0000 0000
+E: 0.058706 0003 0035 0942
+E: 0.058706 0003 0036 1573
+E: 0.058706 0000 0000 0000
+E: 0.066207 0003 0035 0954
+E: 0.066207 0003 0036 1557
+E: 0.066207 0003 0034 2790
+E: 0.066207 0000 0000 0000
+E: 0.075337 0003 0035 0966
+E: 0.075337 0003 0036 1535
+E: 0.075337 0000 0000 0000
+E: 0.082841 0003 0035 0973
+E: 0.082841 0003 0036 1511
+E: 0.082841 0003 0034 2788
+E: 0.082841 0000 0000 0000
+E: 0.091972 0003 0035 0971
+E: 0.091972 0003 0036 1480
+E: 0.091972 0003 0034 2770
+E: 0.091972 0000 0000 0000
+E: 0.099474 0003 0035 0961
+E: 0.099474 0003 0036 1445
+E: 0.099474 0003 0034 2644
+E: 0.099474 0000 0000 0000
+E: 0.108631 0003 0035 0937
+E: 0.108631 0003 0036 1400
+E: 0.108631 0003 0030 0083
+E: 0.108631 0003 0034 2461
+E: 0.108631 0000 0000 0000
+E: 0.116109 0003 0035 0909
+E: 0.116109 0003 0036 1361
+E: 0.116109 0003 0034 2278
+E: 0.116109 0000 0000 0000
+E: 0.125263 0003 0035 0865
+E: 0.125263 0003 0036 1311
+E: 0.125263 0003 0034 2096
+E: 0.125263 0000 0000 0000
+E: 0.132741 0003 0035 0820
+E: 0.132741 0003 0036 1261
+E: 0.132741 0003 0034 2083
+E: 0.132741 0000 0000 0000
+E: 0.141876 0003 0035 0755
+E: 0.141876 0003 0036 1193
+E: 0.141876 0003 003a 0216
+E: 0.141876 0003 0034 2266
+E: 0.141876 0000 0000 0000
+E: 0.149376 0003 0035 0691
+E: 0.149376 0003 0036 1124
+E: 0.149376 0003 0034 2448
+E: 0.149376 0000 0000 0000
+E: 0.158510 0003 0035 0609
+E: 0.158510 0003 0036 1033
+E: 0.158510 0003 0034 2631
+E: 0.158510 0000 0000 0000
+E: 0.166011 0003 0035 0543
+E: 0.166011 0003 0036 0957
+E: 0.166011 0003 0034 2813
+E: 0.166011 0000 0000 0000
+E: 0.175182 0003 0035 0471
+E: 0.175182 0003 0036 0864
+E: 0.175182 0003 0031 0076
+E: 0.175182 0003 0034 2996
+E: 0.175182 0000 0000 0000
+E: 0.182683 0003 0035 0417
+E: 0.182683 0003 0036 0792
+E: 0.182683 0003 003a 0214
+E: 0.182683 0003 0034 3178
+E: 0.182683 0000 0000 0000
+E: 0.191777 0003 0035 0361
+E: 0.191777 0003 0036 0719
+E: 0.191777 0003 0031 0075
+E: 0.191777 0003 003a 0213
+E: 0.191777 0003 0034 2996
+E: 0.191777 0000 0000 0000
+E: 0.199431 0003 0035 0271
+E: 0.199431 0003 0036 0603
+E: 0.199431 0003 0030 0060
+E: 0.199431 0003 0031 0029
+E: 0.199431 0003 003a 0060
+E: 0.199431 0003 0034 2813
+E: 0.199431 0000 0000 0000
+E: 0.207943 0003 003a 0000
+E: 0.207943 0003 0039 -001
+E: 0.207943 0001 014a 0000
+E: 0.207943 0000 0000 0000
diff --git a/tests/Input/res/raw/google_pixel_tablet_touchscreen_events.json b/tests/Input/res/raw/google_pixel_tablet_touchscreen_events.json
new file mode 100644
index 0000000..df4f9fb
--- /dev/null
+++ b/tests/Input/res/raw/google_pixel_tablet_touchscreen_events.json
@@ -0,0 +1,34 @@
+[
+ {
+ "name": "One finger swipe",
+ "source": "TOUCHSCREEN",
+ "events": [
+ {"action":"DOWN","axes":{"AXIS_X":810,"AXIS_Y":1650,"AXIS_PRESSURE":0.83984375,"AXIS_SIZE":0.03106682375073433,"AXIS_TOUCH_MAJOR":82,"AXIS_TOUCH_MINOR":77,"AXIS_TOOL_MAJOR":82,"AXIS_TOOL_MINOR":77,"AXIS_ORIENTATION":1.234087586402893},"buttonState":[]},
+ {"action":"MOVE","axes":{"AXIS_X":825,"AXIS_Y":1645,"AXIS_PRESSURE":0.83984375,"AXIS_SIZE":0.03106682375073433,"AXIS_TOUCH_MAJOR":82,"AXIS_TOUCH_MINOR":77,"AXIS_TOOL_MAJOR":82,"AXIS_TOOL_MINOR":77,"AXIS_ORIENTATION":1.2337040901184082},"buttonState":[]},
+ {"action":"MOVE","axes":{"AXIS_X":841,"AXIS_Y":1639,"AXIS_PRESSURE":0.83984375,"AXIS_SIZE":0.03106682375073433,"AXIS_TOUCH_MAJOR":82,"AXIS_TOUCH_MINOR":77,"AXIS_TOOL_MAJOR":82,"AXIS_TOOL_MINOR":77,"AXIS_ORIENTATION":1.1896021366119385},"buttonState":[]},
+ {"action":"MOVE","axes":{"AXIS_X":862,"AXIS_Y":1630,"AXIS_PRESSURE":0.83984375,"AXIS_SIZE":0.03106682375073433,"AXIS_TOUCH_MAJOR":82,"AXIS_TOUCH_MINOR":77,"AXIS_TOOL_MAJOR":82,"AXIS_TOOL_MINOR":77,"AXIS_ORIENTATION":1.1857671737670898},"buttonState":[]},
+ {"action":"MOVE","axes":{"AXIS_X":883,"AXIS_Y":1619,"AXIS_PRESSURE":0.83984375,"AXIS_SIZE":0.03106682375073433,"AXIS_TOUCH_MAJOR":82,"AXIS_TOUCH_MINOR":77,"AXIS_TOOL_MAJOR":82,"AXIS_TOOL_MINOR":77,"AXIS_ORIENTATION":1.1619905233383179},"buttonState":[]},
+ {"action":"MOVE","axes":{"AXIS_X":905,"AXIS_Y":1604,"AXIS_PRESSURE":0.83984375,"AXIS_SIZE":0.03106682375073433,"AXIS_TOUCH_MAJOR":82,"AXIS_TOUCH_MINOR":77,"AXIS_TOOL_MAJOR":82,"AXIS_TOOL_MINOR":77,"AXIS_ORIENTATION":1.0921943187713623},"buttonState":[]},
+ {"action":"MOVE","axes":{"AXIS_X":924,"AXIS_Y":1591,"AXIS_PRESSURE":0.83984375,"AXIS_SIZE":0.03106682375073433,"AXIS_TOUCH_MAJOR":82,"AXIS_TOUCH_MINOR":77,"AXIS_TOOL_MAJOR":82,"AXIS_TOOL_MINOR":77,"AXIS_ORIENTATION":1.0852913856506348},"buttonState":[]},
+ {"action":"MOVE","axes":{"AXIS_X":942,"AXIS_Y":1573,"AXIS_PRESSURE":0.83984375,"AXIS_SIZE":0.03106682375073433,"AXIS_TOUCH_MAJOR":82,"AXIS_TOUCH_MINOR":77,"AXIS_TOOL_MAJOR":82,"AXIS_TOOL_MINOR":77,"AXIS_ORIENTATION":1.0852913856506348},"buttonState":[]},
+ {"action":"MOVE","axes":{"AXIS_X":954,"AXIS_Y":1557,"AXIS_PRESSURE":0.83984375,"AXIS_SIZE":0.03106682375073433,"AXIS_TOUCH_MAJOR":82,"AXIS_TOUCH_MINOR":77,"AXIS_TOOL_MAJOR":82,"AXIS_TOOL_MINOR":77,"AXIS_ORIENTATION":1.0699516534805298},"buttonState":[]},
+ {"action":"MOVE","axes":{"AXIS_X":966,"AXIS_Y":1535,"AXIS_PRESSURE":0.83984375,"AXIS_SIZE":0.03106682375073433,"AXIS_TOUCH_MAJOR":82,"AXIS_TOUCH_MINOR":77,"AXIS_TOOL_MAJOR":82,"AXIS_TOOL_MINOR":77,"AXIS_ORIENTATION":1.0699516534805298},"buttonState":[]},
+ {"action":"MOVE","axes":{"AXIS_X":973,"AXIS_Y":1511,"AXIS_PRESSURE":0.83984375,"AXIS_SIZE":0.03106682375073433,"AXIS_TOUCH_MAJOR":82,"AXIS_TOUCH_MINOR":77,"AXIS_TOOL_MAJOR":82,"AXIS_TOOL_MINOR":77,"AXIS_ORIENTATION":1.06918466091156},"buttonState":[]},
+ {"action":"MOVE","axes":{"AXIS_X":971,"AXIS_Y":1480,"AXIS_PRESSURE":0.83984375,"AXIS_SIZE":0.03106682375073433,"AXIS_TOUCH_MAJOR":82,"AXIS_TOUCH_MINOR":77,"AXIS_TOOL_MAJOR":82,"AXIS_TOOL_MINOR":77,"AXIS_ORIENTATION":1.0622817277908325},"buttonState":[]},
+ {"action":"MOVE","axes":{"AXIS_X":961,"AXIS_Y":1445,"AXIS_PRESSURE":0.83984375,"AXIS_SIZE":0.03106682375073433,"AXIS_TOUCH_MAJOR":82,"AXIS_TOUCH_MINOR":77,"AXIS_TOOL_MAJOR":82,"AXIS_TOOL_MINOR":77,"AXIS_ORIENTATION":1.0139613151550293},"buttonState":[]},
+ {"action":"MOVE","axes":{"AXIS_X":937,"AXIS_Y":1400,"AXIS_PRESSURE":0.83984375,"AXIS_SIZE":0.03126221150159836,"AXIS_TOUCH_MAJOR":83,"AXIS_TOUCH_MINOR":77,"AXIS_TOOL_MAJOR":83,"AXIS_TOOL_MINOR":77,"AXIS_ORIENTATION":0.9437817335128784},"buttonState":[]},
+ {"action":"MOVE","axes":{"AXIS_X":909,"AXIS_Y":1361,"AXIS_PRESSURE":0.83984375,"AXIS_SIZE":0.03126221150159836,"AXIS_TOUCH_MAJOR":83,"AXIS_TOUCH_MINOR":77,"AXIS_TOOL_MAJOR":83,"AXIS_TOOL_MINOR":77,"AXIS_ORIENTATION":0.8736020922660828},"buttonState":[]},
+ {"action":"MOVE","axes":{"AXIS_X":865,"AXIS_Y":1311,"AXIS_PRESSURE":0.83984375,"AXIS_SIZE":0.03126221150159836,"AXIS_TOUCH_MAJOR":83,"AXIS_TOUCH_MINOR":77,"AXIS_TOOL_MAJOR":83,"AXIS_TOOL_MINOR":77,"AXIS_ORIENTATION":0.803805947303772},"buttonState":[]},
+ {"action":"MOVE","axes":{"AXIS_X":820,"AXIS_Y":1261,"AXIS_PRESSURE":0.83984375,"AXIS_SIZE":0.03126221150159836,"AXIS_TOUCH_MAJOR":83,"AXIS_TOUCH_MINOR":77,"AXIS_TOOL_MAJOR":83,"AXIS_TOOL_MINOR":77,"AXIS_ORIENTATION":0.7988204956054688},"buttonState":[]},
+ {"action":"MOVE","axes":{"AXIS_X":755,"AXIS_Y":1193,"AXIS_PRESSURE":0.84375,"AXIS_SIZE":0.03126221150159836,"AXIS_TOUCH_MAJOR":83,"AXIS_TOUCH_MINOR":77,"AXIS_TOOL_MAJOR":83,"AXIS_TOOL_MINOR":77,"AXIS_ORIENTATION":0.8690001368522644},"buttonState":[]},
+ {"action":"MOVE","axes":{"AXIS_X":691,"AXIS_Y":1124,"AXIS_PRESSURE":0.84375,"AXIS_SIZE":0.03126221150159836,"AXIS_TOUCH_MAJOR":83,"AXIS_TOUCH_MINOR":77,"AXIS_TOOL_MAJOR":83,"AXIS_TOOL_MINOR":77,"AXIS_ORIENTATION":0.9387962818145752},"buttonState":[]},
+ {"action":"MOVE","axes":{"AXIS_X":609,"AXIS_Y":1033,"AXIS_PRESSURE":0.84375,"AXIS_SIZE":0.03126221150159836,"AXIS_TOUCH_MAJOR":83,"AXIS_TOUCH_MINOR":77,"AXIS_TOOL_MAJOR":83,"AXIS_TOOL_MINOR":77,"AXIS_ORIENTATION":1.008975863456726},"buttonState":[]},
+ {"action":"MOVE","axes":{"AXIS_X":543,"AXIS_Y":957,"AXIS_PRESSURE":0.84375,"AXIS_SIZE":0.03126221150159836,"AXIS_TOUCH_MAJOR":83,"AXIS_TOUCH_MINOR":77,"AXIS_TOOL_MAJOR":83,"AXIS_TOOL_MINOR":77,"AXIS_ORIENTATION":1.0787720680236816},"buttonState":[]},
+ {"action":"MOVE","axes":{"AXIS_X":471,"AXIS_Y":864,"AXIS_PRESSURE":0.84375,"AXIS_SIZE":0.03106682375073433,"AXIS_TOUCH_MAJOR":83,"AXIS_TOUCH_MINOR":76,"AXIS_TOOL_MAJOR":83,"AXIS_TOOL_MINOR":76,"AXIS_ORIENTATION":1.1489516496658325},"buttonState":[]},
+ {"action":"MOVE","axes":{"AXIS_X":417,"AXIS_Y":792,"AXIS_PRESSURE":0.8359375,"AXIS_SIZE":0.03106682375073433,"AXIS_TOUCH_MAJOR":83,"AXIS_TOUCH_MINOR":76,"AXIS_TOOL_MAJOR":83,"AXIS_TOOL_MINOR":76,"AXIS_ORIENTATION":1.2187477350234985},"buttonState":[]},
+ {"action":"MOVE","axes":{"AXIS_X":361,"AXIS_Y":719,"AXIS_PRESSURE":0.83203125,"AXIS_SIZE":0.03087143413722515,"AXIS_TOUCH_MAJOR":83,"AXIS_TOUCH_MINOR":75,"AXIS_TOOL_MAJOR":83,"AXIS_TOOL_MINOR":75,"AXIS_ORIENTATION":1.1489516496658325},"buttonState":[]},
+ {"action":"MOVE","axes":{"AXIS_X":271,"AXIS_Y":603,"AXIS_PRESSURE":0.234375,"AXIS_SIZE":0.017389604821801186,"AXIS_TOUCH_MAJOR":60,"AXIS_TOUCH_MINOR":29,"AXIS_TOOL_MAJOR":60,"AXIS_TOOL_MINOR":29,"AXIS_ORIENTATION":1.0787720680236816},"buttonState":[]},
+ {"action":"UP","axes":{"AXIS_X":271,"AXIS_Y":603,"AXIS_PRESSURE":0.234375,"AXIS_SIZE":0.017389604821801186,"AXIS_TOUCH_MAJOR":60,"AXIS_TOUCH_MINOR":29,"AXIS_TOOL_MAJOR":60,"AXIS_TOOL_MINOR":29,"AXIS_ORIENTATION":1.0787720680236816},"buttonState":[]}
+ ]
+ }
+]
diff --git a/tests/Input/src/com/android/test/input/CaptureEventActivity.kt b/tests/Input/src/com/android/test/input/CaptureEventActivity.kt
new file mode 100644
index 0000000..d54e3470
--- /dev/null
+++ b/tests/Input/src/com/android/test/input/CaptureEventActivity.kt
@@ -0,0 +1,85 @@
+/*
+ * 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.test.input
+
+import android.app.Activity
+import android.os.Bundle
+import android.view.InputEvent
+import android.view.KeyEvent
+import android.view.MotionEvent
+import java.util.concurrent.LinkedBlockingQueue
+import java.util.concurrent.TimeUnit
+import org.junit.Assert.assertNull
+
+class CaptureEventActivity : Activity() {
+ private val events = LinkedBlockingQueue<InputEvent>()
+ var shouldHandleKeyEvents = true
+
+ override fun onCreate(savedInstanceState: Bundle?) {
+ super.onCreate(savedInstanceState)
+
+ // Set the fixed orientation if requested
+ if (intent.hasExtra(EXTRA_FIXED_ORIENTATION)) {
+ val orientation = intent.getIntExtra(EXTRA_FIXED_ORIENTATION, 0)
+ setRequestedOrientation(orientation)
+ }
+
+ // Set the flag if requested
+ if (intent.hasExtra(EXTRA_WINDOW_FLAGS)) {
+ val flags = intent.getIntExtra(EXTRA_WINDOW_FLAGS, 0)
+ window.addFlags(flags)
+ }
+ }
+
+ override fun dispatchGenericMotionEvent(ev: MotionEvent?): Boolean {
+ events.add(MotionEvent.obtain(ev))
+ return true
+ }
+
+ override fun dispatchTouchEvent(ev: MotionEvent?): Boolean {
+ events.add(MotionEvent.obtain(ev))
+ return true
+ }
+
+ override fun dispatchKeyEvent(event: KeyEvent?): Boolean {
+ events.add(KeyEvent(event))
+ return shouldHandleKeyEvents
+ }
+
+ override fun dispatchTrackballEvent(ev: MotionEvent?): Boolean {
+ events.add(MotionEvent.obtain(ev))
+ return true
+ }
+
+ fun getInputEvent(): InputEvent? {
+ return events.poll(5, TimeUnit.SECONDS)
+ }
+
+ fun hasReceivedEvents(): Boolean {
+ return !events.isEmpty()
+ }
+
+ fun assertNoEvents() {
+ val event = events.poll(100, TimeUnit.MILLISECONDS)
+ assertNull("Expected no events, but received $event", event)
+ }
+
+ companion object {
+ const val EXTRA_FIXED_ORIENTATION = "fixed_orientation"
+ const val EXTRA_WINDOW_FLAGS = "window_flags"
+ }
+}
diff --git a/tests/Input/src/com/android/test/input/UinputRecordingIntegrationTests.kt b/tests/Input/src/com/android/test/input/UinputRecordingIntegrationTests.kt
new file mode 100644
index 0000000..aa73c39
--- /dev/null
+++ b/tests/Input/src/com/android/test/input/UinputRecordingIntegrationTests.kt
@@ -0,0 +1,197 @@
+/*
+ * 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.test.input
+
+import android.Manifest.permission.ASSOCIATE_INPUT_DEVICE_TO_DISPLAY
+import android.app.Instrumentation
+import android.cts.input.EventVerifier
+import android.graphics.PointF
+import android.hardware.input.InputManager
+import android.os.ParcelFileDescriptor
+import android.util.Log
+import android.util.Size
+import android.view.InputEvent
+import android.view.MotionEvent
+import androidx.test.platform.app.InstrumentationRegistry
+import com.android.cts.input.BatchedEventSplitter
+import com.android.cts.input.InputJsonParser
+import com.android.cts.input.VirtualDisplayActivityScenario
+import com.android.cts.input.inputeventmatchers.isResampled
+import com.android.cts.input.inputeventmatchers.withButtonState
+import com.android.cts.input.inputeventmatchers.withHistorySize
+import com.android.cts.input.inputeventmatchers.withMotionAction
+import com.android.cts.input.inputeventmatchers.withPressure
+import com.android.cts.input.inputeventmatchers.withRawCoords
+import com.android.cts.input.inputeventmatchers.withSource
+import java.io.InputStream
+import junit.framework.Assert.fail
+import org.hamcrest.Matchers.allOf
+import org.junit.Before
+import org.junit.Rule
+import org.junit.Test
+import org.junit.rules.TestName
+import org.junit.runner.RunWith
+import org.junit.runners.Parameterized
+
+/**
+ * Integration tests for the input pipeline that replays recording taken from physical input devices
+ * at the evdev interface level, and makes assertions on the events that are received by a test app.
+ *
+ * These tests associate the playback input device with a virtual display to make these tests
+ * agnostic to the device form factor.
+ *
+ * New recordings can be taken using the `evemu-record` shell command.
+ */
+@RunWith(Parameterized::class)
+class UinputRecordingIntegrationTests {
+
+ companion object {
+ /**
+ * Add new test cases by adding a new [TestData] to the following list.
+ */
+ @JvmStatic
+ @Parameterized.Parameters(name = "{0}")
+ fun data(): Iterable<Any> =
+ listOf(
+ TestData(
+ "GooglePixelTabletTouchscreen", R.raw.google_pixel_tablet_touchscreen,
+ R.raw.google_pixel_tablet_touchscreen_events, Size(1600, 2560),
+ vendorId = 0x0603, productId = 0x7806
+ ),
+ )
+
+ /**
+ * Use the debug mode to see the JSON-encoded received events in logcat.
+ */
+ const val DEBUG_RECEIVED_EVENTS = false
+
+ const val INPUT_DEVICE_SOURCE_ALL = -1
+ val TAG = UinputRecordingIntegrationTests::class.java.simpleName
+ }
+
+ class TestData(
+ val name: String,
+ val uinputRecordingResource: Int,
+ val expectedEventsResource: Int,
+ val displaySize: Size,
+ val vendorId: Int,
+ val productId: Int,
+ ) {
+ override fun toString(): String = name
+ }
+
+ private lateinit var instrumentation: Instrumentation
+ private lateinit var parser: InputJsonParser
+
+ @get:Rule
+ val testName = TestName()
+
+ @Parameterized.Parameter(0)
+ lateinit var testData: TestData
+
+ @Before
+ fun setUp() {
+ instrumentation = InstrumentationRegistry.getInstrumentation()
+ parser = InputJsonParser(instrumentation.context)
+ }
+
+ @Test
+ fun testEvemuRecording() {
+ VirtualDisplayActivityScenario.AutoClose<CaptureEventActivity>(
+ testName,
+ size = testData.displaySize
+ ).use { scenario ->
+ scenario.activity.window.decorView.requestUnbufferedDispatch(INPUT_DEVICE_SOURCE_ALL)
+
+ try {
+ instrumentation.uiAutomation.adoptShellPermissionIdentity(
+ ASSOCIATE_INPUT_DEVICE_TO_DISPLAY,
+ )
+
+ val inputPort = "uinput:1:${testData.vendorId}:${testData.productId}"
+ val inputManager =
+ instrumentation.context.getSystemService(InputManager::class.java)!!
+ try {
+ inputManager.addUniqueIdAssociationByPort(
+ inputPort,
+ scenario.virtualDisplay.display.uniqueId!!,
+ )
+
+ injectUinputEvents()
+
+ if (DEBUG_RECEIVED_EVENTS) {
+ printReceivedEventsToLogcat(scenario.activity)
+ fail("Test cannot pass in debug mode!")
+ }
+
+ val verifier =
+ EventVerifier(BatchedEventSplitter { scenario.activity.getInputEvent() })
+ verifyEvents(verifier)
+ scenario.activity.assertNoEvents()
+ } finally {
+ inputManager.removeUniqueIdAssociationByPort(inputPort)
+ }
+ } finally {
+ instrumentation.uiAutomation.dropShellPermissionIdentity()
+ }
+ }
+ }
+
+ private fun printReceivedEventsToLogcat(activity: CaptureEventActivity) {
+ val getNextEvent = BatchedEventSplitter { activity.getInputEvent() }
+ var receivedEvent: InputEvent? = getNextEvent()
+ while (receivedEvent != null) {
+ Log.d(TAG,
+ parser.encodeEvent(receivedEvent)?.toString()
+ ?: "(Failed to encode received event)"
+ )
+ receivedEvent = getNextEvent()
+ }
+ }
+
+ private fun injectUinputEvents() {
+ val fds = instrumentation.uiAutomation!!.executeShellCommandRw("uinput -")
+
+ ParcelFileDescriptor.AutoCloseOutputStream(fds[1]).use { stdIn ->
+ val inputStream: InputStream = instrumentation.context.resources.openRawResource(
+ testData.uinputRecordingResource,
+ )
+ stdIn.write(inputStream.readBytes())
+ }
+ }
+
+ private fun verifyEvents(verifier: EventVerifier) {
+ val uinputTestData = parser.getUinputTestData(testData.expectedEventsResource)
+ for (test in uinputTestData) {
+ for ((index, expectedEvent) in test.events.withIndex()) {
+ if (expectedEvent is MotionEvent) {
+ verifier.assertReceivedMotion(
+ allOf(
+ withMotionAction(expectedEvent.action),
+ withSource(expectedEvent.source),
+ withButtonState(expectedEvent.buttonState),
+ withRawCoords(PointF(expectedEvent.rawX, expectedEvent.rawY)),
+ withPressure(expectedEvent.pressure),
+ isResampled(false),
+ withHistorySize(0),
+ ),
+ "${test.name}: Expected event at index $index",
+ )
+ }
+ }
+ }
+ }
+}
diff --git a/tests/TrustTests/TEST_MAPPING b/tests/TrustTests/TEST_MAPPING
index 23923ee..b0dd551 100644
--- a/tests/TrustTests/TEST_MAPPING
+++ b/tests/TrustTests/TEST_MAPPING
@@ -1,28 +1,12 @@
{
"presubmit": [
{
- "name": "TrustTests",
- "options": [
- {
- "include-filter": "android.trust.test"
- },
- {
- "exclude-annotation": "androidx.test.filters.FlakyTest"
- }
- ]
+ "name": "TrustTests_trust_test"
}
],
"trust-tablet": [
{
- "name": "TrustTests",
- "options": [
- {
- "include-filter": "android.trust.test"
- },
- {
- "exclude-annotation": "androidx.test.filters.FlakyTest"
- }
- ]
+ "name": "TrustTests_trust_test"
}
]
}
\ No newline at end of file
diff --git a/tests/UsbManagerTests/Android.bp b/tests/UsbManagerTests/Android.bp
index 2909e66..331a21a 100644
--- a/tests/UsbManagerTests/Android.bp
+++ b/tests/UsbManagerTests/Android.bp
@@ -44,7 +44,7 @@
"libstaticjvmtiagent",
],
libs: [
- "android.test.mock",
+ "android.test.mock.stubs.system",
],
certificate: "platform",
platform_apis: true,
diff --git a/tests/utils/testutils/TEST_MAPPING b/tests/utils/testutils/TEST_MAPPING
index 52fd5a8..71e9ad3 100644
--- a/tests/utils/testutils/TEST_MAPPING
+++ b/tests/utils/testutils/TEST_MAPPING
@@ -1,18 +1,7 @@
{
"presubmit": [
{
- "name": "frameworks-base-testutils-tests",
- "options": [
- {
- "exclude-annotation": "androidx.test.filters.LargeTest"
- },
- {
- "exclude-annotation": "androidx.test.filters.FlakyTest"
- },
- {
- "exclude-annotation": "org.junit.Ignore"
- }
- ]
+ "name": "frameworks-base-testutils-tests"
}
],
"postsubmit": [
diff --git a/tools/systemfeatures/Android.bp b/tools/systemfeatures/Android.bp
index aca25eb..a9e6328 100644
--- a/tools/systemfeatures/Android.bp
+++ b/tools/systemfeatures/Android.bp
@@ -5,6 +5,7 @@
// to get the below license kinds:
// SPDX-license-identifier-Apache-2.0
default_applicable_licenses: ["frameworks_base_license"],
+ default_team: "trendy_team_system_performance",
}
java_library_host {
@@ -25,8 +26,6 @@
static_libs: ["systemfeatures-gen-lib"],
}
-// TODO(b/203143243): Add golden diff test for generated sources.
-// Functional runtime behavior is covered in systemfeatures-gen-tests.
genrule {
name: "systemfeatures-gen-tests-srcs",
cmd: "$(location systemfeatures-gen-tool) com.android.systemfeatures.RwNoFeatures --readonly=false > $(location RwNoFeatures.java) && " +
@@ -42,11 +41,12 @@
tools: ["systemfeatures-gen-tool"],
}
+// Functional runtime behavior testing.
java_test_host {
name: "systemfeatures-gen-tests",
test_suites: ["general-tests"],
srcs: [
- "tests/**/*.java",
+ "tests/src/**/*.java",
":systemfeatures-gen-tests-srcs",
],
test_options: {
@@ -61,3 +61,33 @@
"truth",
],
}
+
+// Rename the goldens as they may be copied into the source tree, and we don't
+// need or want the usual `.java` linting (e.g., copyright checks).
+genrule {
+ name: "systemfeatures-gen-tests-golden-srcs",
+ cmd: "for f in $(in); do cp $$f $(genDir)/tests/gen/$$(basename $$f).gen; done",
+ srcs: [":systemfeatures-gen-tests-srcs"],
+ out: [
+ "tests/gen/RwNoFeatures.java.gen",
+ "tests/gen/RoNoFeatures.java.gen",
+ "tests/gen/RwFeatures.java.gen",
+ "tests/gen/RoFeatures.java.gen",
+ ],
+}
+
+// Golden output testing. Golden sources can be updated via:
+// $ANDROID_BUILD_TOP/frameworks/base/tools/systemfeatures/tests/golden_test.sh --update
+sh_test_host {
+ name: "systemfeatures-gen-golden-tests",
+ src: "tests/golden_test.sh",
+ filename: "systemfeatures-gen-golden-tests.sh",
+ test_config: "tests/systemfeatures-gen-golden-tests.xml",
+ data: [
+ "tests/golden/**/*.java*",
+ ":systemfeatures-gen-tests-golden-srcs",
+ ],
+ test_options: {
+ unit_test: true,
+ },
+}
diff --git a/tools/systemfeatures/src/com/android/systemfeatures/SystemFeaturesGenerator.kt b/tools/systemfeatures/src/com/android/systemfeatures/SystemFeaturesGenerator.kt
index e537ffc..5df453d 100644
--- a/tools/systemfeatures/src/com/android/systemfeatures/SystemFeaturesGenerator.kt
+++ b/tools/systemfeatures/src/com/android/systemfeatures/SystemFeaturesGenerator.kt
@@ -142,6 +142,10 @@
// TODO(b/203143243): Add validation of build vs runtime values to ensure consistency.
JavaFile.builder(outputClassName.packageName(), classBuilder.build())
+ .indent(" ")
+ .skipJavaLangImports(true)
+ .addFileComment("This file is auto-generated. DO NOT MODIFY.\n")
+ .addFileComment("Args: ${args.joinToString(" \\\n ")}")
.build()
.writeTo(System.out)
}
@@ -178,6 +182,7 @@
val methodBuilder =
MethodSpec.methodBuilder(methodName)
.addModifiers(Modifier.PUBLIC, Modifier.STATIC)
+ .addJavadoc("Check for ${feature.name}.\n\n@hide")
.returns(Boolean::class.java)
.addParameter(CONTEXT_CLASS, "context")
@@ -228,6 +233,7 @@
MethodSpec.methodBuilder("maybeHasFeature")
.addModifiers(Modifier.PUBLIC, Modifier.STATIC)
.addAnnotation(ClassName.get("android.annotation", "Nullable"))
+ .addJavadoc("@hide")
.returns(Boolean::class.javaObjectType) // Use object type for nullability
.addParameter(String::class.java, "featureName")
.addParameter(Int::class.java, "version")
diff --git a/tools/systemfeatures/tests/golden/RoFeatures.java.gen b/tools/systemfeatures/tests/golden/RoFeatures.java.gen
new file mode 100644
index 0000000..724639b
--- /dev/null
+++ b/tools/systemfeatures/tests/golden/RoFeatures.java.gen
@@ -0,0 +1,88 @@
+// This file is auto-generated. DO NOT MODIFY.
+// Args: com.android.systemfeatures.RoFeatures \
+// --readonly=true \
+// --feature=WATCH:1 \
+// --feature=WIFI:0 \
+// --feature=VULKAN:-1 \
+// --feature=AUTO: \
+// --feature-apis=WATCH,PC
+package com.android.systemfeatures;
+
+import android.annotation.Nullable;
+import android.content.Context;
+import android.content.pm.PackageManager;
+import com.android.aconfig.annotations.AssumeFalseForR8;
+import com.android.aconfig.annotations.AssumeTrueForR8;
+
+/**
+ * @hide
+ */
+public final class RoFeatures {
+ /**
+ * Check for FEATURE_WATCH.
+ *
+ * @hide
+ */
+ @AssumeTrueForR8
+ public static boolean hasFeatureWatch(Context context) {
+ return true;
+ }
+
+ /**
+ * Check for FEATURE_PC.
+ *
+ * @hide
+ */
+ public static boolean hasFeaturePc(Context context) {
+ return hasFeatureFallback(context, PackageManager.FEATURE_PC);
+ }
+
+ /**
+ * Check for FEATURE_WIFI.
+ *
+ * @hide
+ */
+ @AssumeTrueForR8
+ public static boolean hasFeatureWifi(Context context) {
+ return true;
+ }
+
+ /**
+ * Check for FEATURE_VULKAN.
+ *
+ * @hide
+ */
+ @AssumeFalseForR8
+ public static boolean hasFeatureVulkan(Context context) {
+ return false;
+ }
+
+ /**
+ * Check for FEATURE_AUTO.
+ *
+ * @hide
+ */
+ @AssumeFalseForR8
+ public static boolean hasFeatureAuto(Context context) {
+ return false;
+ }
+
+ private static boolean hasFeatureFallback(Context context, String featureName) {
+ return context.getPackageManager().hasSystemFeature(featureName, 0);
+ }
+
+ /**
+ * @hide
+ */
+ @Nullable
+ public static Boolean maybeHasFeature(String featureName, int version) {
+ switch (featureName) {
+ case PackageManager.FEATURE_WATCH: return 1 >= version;
+ case PackageManager.FEATURE_WIFI: return 0 >= version;
+ case PackageManager.FEATURE_VULKAN: return -1 >= version;
+ case PackageManager.FEATURE_AUTO: return false;
+ default: break;
+ }
+ return null;
+ }
+}
diff --git a/tools/systemfeatures/tests/golden/RoNoFeatures.java.gen b/tools/systemfeatures/tests/golden/RoNoFeatures.java.gen
new file mode 100644
index 0000000..59c5b4e
--- /dev/null
+++ b/tools/systemfeatures/tests/golden/RoNoFeatures.java.gen
@@ -0,0 +1,35 @@
+// This file is auto-generated. DO NOT MODIFY.
+// Args: com.android.systemfeatures.RoNoFeatures \
+// --readonly=true \
+// --feature-apis=WATCH
+package com.android.systemfeatures;
+
+import android.annotation.Nullable;
+import android.content.Context;
+import android.content.pm.PackageManager;
+
+/**
+ * @hide
+ */
+public final class RoNoFeatures {
+ /**
+ * Check for FEATURE_WATCH.
+ *
+ * @hide
+ */
+ public static boolean hasFeatureWatch(Context context) {
+ return hasFeatureFallback(context, PackageManager.FEATURE_WATCH);
+ }
+
+ private static boolean hasFeatureFallback(Context context, String featureName) {
+ return context.getPackageManager().hasSystemFeature(featureName, 0);
+ }
+
+ /**
+ * @hide
+ */
+ @Nullable
+ public static Boolean maybeHasFeature(String featureName, int version) {
+ return null;
+ }
+}
diff --git a/tools/systemfeatures/tests/golden/RwFeatures.java.gen b/tools/systemfeatures/tests/golden/RwFeatures.java.gen
new file mode 100644
index 0000000..6f89759
--- /dev/null
+++ b/tools/systemfeatures/tests/golden/RwFeatures.java.gen
@@ -0,0 +1,65 @@
+// This file is auto-generated. DO NOT MODIFY.
+// Args: com.android.systemfeatures.RwFeatures \
+// --readonly=false \
+// --feature=WATCH:1 \
+// --feature=WIFI:0 \
+// --feature=VULKAN:-1 \
+// --feature=AUTO:
+package com.android.systemfeatures;
+
+import android.annotation.Nullable;
+import android.content.Context;
+import android.content.pm.PackageManager;
+
+/**
+ * @hide
+ */
+public final class RwFeatures {
+ /**
+ * Check for FEATURE_WATCH.
+ *
+ * @hide
+ */
+ public static boolean hasFeatureWatch(Context context) {
+ return hasFeatureFallback(context, PackageManager.FEATURE_WATCH);
+ }
+
+ /**
+ * Check for FEATURE_WIFI.
+ *
+ * @hide
+ */
+ public static boolean hasFeatureWifi(Context context) {
+ return hasFeatureFallback(context, PackageManager.FEATURE_WIFI);
+ }
+
+ /**
+ * Check for FEATURE_VULKAN.
+ *
+ * @hide
+ */
+ public static boolean hasFeatureVulkan(Context context) {
+ return hasFeatureFallback(context, PackageManager.FEATURE_VULKAN);
+ }
+
+ /**
+ * Check for FEATURE_AUTO.
+ *
+ * @hide
+ */
+ public static boolean hasFeatureAuto(Context context) {
+ return hasFeatureFallback(context, PackageManager.FEATURE_AUTO);
+ }
+
+ private static boolean hasFeatureFallback(Context context, String featureName) {
+ return context.getPackageManager().hasSystemFeature(featureName, 0);
+ }
+
+ /**
+ * @hide
+ */
+ @Nullable
+ public static Boolean maybeHasFeature(String featureName, int version) {
+ return null;
+ }
+}
diff --git a/tools/systemfeatures/tests/golden/RwNoFeatures.java.gen b/tools/systemfeatures/tests/golden/RwNoFeatures.java.gen
new file mode 100644
index 0000000..2111d56
--- /dev/null
+++ b/tools/systemfeatures/tests/golden/RwNoFeatures.java.gen
@@ -0,0 +1,24 @@
+// This file is auto-generated. DO NOT MODIFY.
+// Args: com.android.systemfeatures.RwNoFeatures \
+// --readonly=false
+package com.android.systemfeatures;
+
+import android.annotation.Nullable;
+import android.content.Context;
+
+/**
+ * @hide
+ */
+public final class RwNoFeatures {
+ private static boolean hasFeatureFallback(Context context, String featureName) {
+ return context.getPackageManager().hasSystemFeature(featureName, 0);
+ }
+
+ /**
+ * @hide
+ */
+ @Nullable
+ public static Boolean maybeHasFeature(String featureName, int version) {
+ return null;
+ }
+}
diff --git a/tools/systemfeatures/tests/golden_test.sh b/tools/systemfeatures/tests/golden_test.sh
new file mode 100755
index 0000000..c249254
--- /dev/null
+++ b/tools/systemfeatures/tests/golden_test.sh
@@ -0,0 +1,52 @@
+#!/usr/bin/env bash
+
+# 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.
+
+set -e
+
+GEN_DIR="tests/gen"
+GOLDEN_DIR="tests/golden"
+
+if [[ $(basename $0) == "golden_test.sh" ]]; then
+ # We're running via command-line, so we need to:
+ # 1) manually update generated srcs
+ # 2) use absolute paths
+ if [ -z $ANDROID_BUILD_TOP ]; then
+ echo "You need to source and lunch before you can use this script directly."
+ exit 1
+ fi
+ GEN_DIR="$ANDROID_BUILD_TOP/out/soong/.intermediates/frameworks/base/tools/systemfeatures/systemfeatures-gen-tests-golden-srcs/gen/$GEN_DIR"
+ GOLDEN_DIR="$ANDROID_BUILD_TOP/frameworks/base/tools/systemfeatures/$GOLDEN_DIR"
+ rm -rf "$GEN_DIR"
+ "$ANDROID_BUILD_TOP"/build/soong/soong_ui.bash --make-mode systemfeatures-gen-tests-golden-srcs
+fi
+
+if [[ "$1" == "--update" ]]; then
+ rm -rf "$GOLDEN_DIR"
+ cp -R "$GEN_DIR" "$GOLDEN_DIR"
+ echo "Updated golden test files."
+else
+ echo "Running diff from test output against golden test files..."
+ if diff -ruN "$GOLDEN_DIR" "$GEN_DIR" ; then
+ echo "No changes."
+ else
+ echo
+ echo "----------------------------------------------------------------------------------------"
+ echo "If changes look OK, run:"
+ echo " \$ANDROID_BUILD_TOP/frameworks/base/tools/systemfeatures/tests/golden_test.sh --update"
+ echo "----------------------------------------------------------------------------------------"
+ exit 1
+ fi
+fi
diff --git a/tools/systemfeatures/tests/Context.java b/tools/systemfeatures/tests/src/Context.java
similarity index 100%
rename from tools/systemfeatures/tests/Context.java
rename to tools/systemfeatures/tests/src/Context.java
diff --git a/tools/systemfeatures/tests/PackageManager.java b/tools/systemfeatures/tests/src/PackageManager.java
similarity index 100%
rename from tools/systemfeatures/tests/PackageManager.java
rename to tools/systemfeatures/tests/src/PackageManager.java
diff --git a/tools/systemfeatures/tests/SystemFeaturesGeneratorTest.java b/tools/systemfeatures/tests/src/SystemFeaturesGeneratorTest.java
similarity index 100%
rename from tools/systemfeatures/tests/SystemFeaturesGeneratorTest.java
rename to tools/systemfeatures/tests/src/SystemFeaturesGeneratorTest.java
diff --git a/tools/systemfeatures/tests/systemfeatures-gen-golden-tests.xml b/tools/systemfeatures/tests/systemfeatures-gen-golden-tests.xml
new file mode 100644
index 0000000..e3a5841
--- /dev/null
+++ b/tools/systemfeatures/tests/systemfeatures-gen-golden-tests.xml
@@ -0,0 +1,20 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- 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.
+-->
+<configuration description="Runs systemfeatures-gen golden diff test">
+ <test class="com.android.tradefed.testtype.binary.ExecutableHostTest" >
+ <option name="binary" value="systemfeatures-gen-golden-tests.sh"/>
+ </test>
+</configuration>