Merge "Fix warnings in DesktopTasksController" into main
diff --git a/Android.bp b/Android.bp
index bfe749a..26d0d65 100644
--- a/Android.bp
+++ b/Android.bp
@@ -144,9 +144,6 @@
// For the generated R.java and Manifest.java
":framework-res{.aapt.srcjar}",
- // Java/AIDL sources to be moved out to CrashRecovery module
- ":framework-crashrecovery-sources",
-
// etc.
":framework-javastream-protos",
":statslog-framework-java-gen", // FrameworkStatsLog.java
@@ -432,7 +429,12 @@
name: "framework-non-updatable-unbundled-impl-libs",
static_libs: [
"framework-location.impl",
- ],
+ ] + select(soong_config_variable("ANDROID", "release_crashrecovery_module"), {
+ "true": [],
+ default: [
+ "framework-platformcrashrecovery.impl",
+ ],
+ }),
sdk_version: "core_platform",
installable: false,
}
@@ -565,7 +567,12 @@
"documents-ui-compat-config",
"calendar-provider-compat-config",
"contacts-provider-platform-compat-config",
- ],
+ ] + select(soong_config_variable("ANDROID", "release_crashrecovery_module"), {
+ "true": [],
+ default: [
+ "framework-platformcrashrecovery-compat-config",
+ ],
+ }),
}
platform_compat_config {
diff --git a/api/Android.bp b/api/Android.bp
index 3c92cb2..ff674c7 100644
--- a/api/Android.bp
+++ b/api/Android.bp
@@ -101,7 +101,9 @@
"true": [
"framework-crashrecovery",
],
- default: [],
+ default: [
+ "framework-platformcrashrecovery",
+ ],
}) + select(release_flag("RELEASE_RANGING_STACK"), {
true: [
"framework-ranging",
@@ -436,6 +438,7 @@
impl_library_visibility: ["//frameworks/base"],
defaults_visibility: [
"//frameworks/base/location",
+ "//frameworks/base/packages/CrashRecovery/framework",
"//frameworks/base/nfc",
],
plugins: ["error_prone_android_framework"],
diff --git a/api/api.go b/api/api.go
index 29083df..f32bdc3 100644
--- a/api/api.go
+++ b/api/api.go
@@ -28,6 +28,7 @@
const i18n = "i18n.module.public.api"
const virtualization = "framework-virtualization"
const location = "framework-location"
+const platformCrashrecovery = "framework-platformcrashrecovery"
var core_libraries_modules = []string{art, conscrypt, i18n}
@@ -39,7 +40,7 @@
// APIs.
// In addition, the modules in this list are allowed to contribute to test APIs
// stubs.
-var non_updatable_modules = []string{virtualization, location}
+var non_updatable_modules = []string{virtualization, location, platformCrashrecovery}
// The intention behind this soong plugin is to generate a number of "merged"
// API-related modules that would otherwise require a large amount of very
diff --git a/api/api_test.go b/api/api_test.go
index 166f053..28109b5e 100644
--- a/api/api_test.go
+++ b/api/api_test.go
@@ -78,10 +78,7 @@
"stub-annotations",
}
- extraSdkLibraryModules := []string{
- "framework-virtualization",
- "framework-location",
- }
+ extraSdkLibraryModules := non_updatable_modules
extraSystemModules := []string{
"core-public-stubs-system-modules",
@@ -184,10 +181,10 @@
func TestCombinedApisDefaults(t *testing.T) {
+ testNonUpdatableModules := append(non_updatable_modules, "framework-foo", "framework-bar")
result := android.GroupFixturePreparers(
prepareForTestWithCombinedApis,
- java.FixtureWithLastReleaseApis(
- "framework-location", "framework-virtualization", "framework-foo", "framework-bar"),
+ java.FixtureWithLastReleaseApis(testNonUpdatableModules...),
android.FixtureModifyProductVariables(func(variables android.FixtureProductVariables) {
variables.VendorVars = map[string]map[string]string{
"boolean_var": {
diff --git a/core/api/system-current.txt b/core/api/system-current.txt
index d1a9e67..491bca2 100644
--- a/core/api/system-current.txt
+++ b/core/api/system-current.txt
@@ -14086,31 +14086,6 @@
}
-package android.service.watchdog {
-
- public abstract class ExplicitHealthCheckService extends android.app.Service {
- ctor public ExplicitHealthCheckService();
- method public final void notifyHealthCheckPassed(@NonNull String);
- method @NonNull public final android.os.IBinder onBind(@NonNull android.content.Intent);
- method public abstract void onCancelHealthCheck(@NonNull String);
- method @NonNull public abstract java.util.List<java.lang.String> onGetRequestedPackages();
- method @NonNull public abstract java.util.List<android.service.watchdog.ExplicitHealthCheckService.PackageConfig> onGetSupportedPackages();
- method public abstract void onRequestHealthCheck(@NonNull String);
- field public static final String BIND_PERMISSION = "android.permission.BIND_EXPLICIT_HEALTH_CHECK_SERVICE";
- field public static final String SERVICE_INTERFACE = "android.service.watchdog.ExplicitHealthCheckService";
- }
-
- public static final class ExplicitHealthCheckService.PackageConfig implements android.os.Parcelable {
- ctor public ExplicitHealthCheckService.PackageConfig(@NonNull String, long);
- method public int describeContents();
- method public long getHealthCheckTimeoutMillis();
- method @NonNull public String getPackageName();
- method public void writeToParcel(android.os.Parcel, int);
- field @NonNull public static final android.os.Parcelable.Creator<android.service.watchdog.ExplicitHealthCheckService.PackageConfig> CREATOR;
- }
-
-}
-
package android.service.wearable {
@FlaggedApi("android.app.wearable.enable_data_request_observer_api") public interface WearableSensingDataRequester {
diff --git a/core/api/test-current.txt b/core/api/test-current.txt
index 58ab073..a0c4fdb 100644
--- a/core/api/test-current.txt
+++ b/core/api/test-current.txt
@@ -3301,14 +3301,6 @@
}
-package android.service.watchdog {
-
- public abstract class ExplicitHealthCheckService extends android.app.Service {
- method public void setCallback(@Nullable android.os.RemoteCallback);
- }
-
-}
-
package android.speech {
public abstract class RecognitionService extends android.app.Service {
diff --git a/core/java/android/window/flags/lse_desktop_experience.aconfig b/core/java/android/window/flags/lse_desktop_experience.aconfig
index c4a9e57..3f3d3d8 100644
--- a/core/java/android/window/flags/lse_desktop_experience.aconfig
+++ b/core/java/android/window/flags/lse_desktop_experience.aconfig
@@ -336,6 +336,13 @@
}
flag {
+ name: "enable_desktop_app_launch_transitions"
+ namespace: "lse_desktop_experience"
+ description: "Enables custom transitions for app launches in Desktop Mode."
+ bug: "375992828"
+}
+
+flag {
name: "enable_move_to_next_display_shortcut"
namespace: "lse_desktop_experience"
description: "Add new keyboard shortcut of moving a task into next display"
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/dagger/WMShellModule.java b/libs/WindowManager/Shell/src/com/android/wm/shell/dagger/WMShellModule.java
index 0942e05..8d25a9a 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/dagger/WMShellModule.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/dagger/WMShellModule.java
@@ -18,6 +18,7 @@
import static android.window.DesktopModeFlags.ENABLE_DESKTOP_WINDOWING_ENTER_TRANSITIONS;
import static android.window.DesktopModeFlags.ENABLE_DESKTOP_WINDOWING_TASK_LIMIT;
+import static android.window.DesktopModeFlags.ENABLE_WINDOWING_TRANSITION_HANDLERS_OBSERVERS;
import android.annotation.Nullable;
import android.app.KeyguardManager;
@@ -153,12 +154,7 @@
* <p>This module only defines Shell dependencies for handheld SystemUI implementation. Common
* dependencies should go into {@link WMShellBaseModule}.
*/
-@Module(
- includes = {
- WMShellBaseModule.class,
- PipModule.class,
- ShellBackAnimationModule.class
- })
+@Module(includes = {WMShellBaseModule.class, PipModule.class, ShellBackAnimationModule.class})
public abstract class WMShellModule {
//
@@ -173,8 +169,7 @@
@WMSingleton
@Provides
- static BubblePositioner provideBubblePositioner(Context context,
- WindowManager windowManager) {
+ static BubblePositioner provideBubblePositioner(Context context, WindowManager windowManager) {
return new BubblePositioner(context, windowManager);
}
@@ -186,20 +181,22 @@
@WMSingleton
@Provides
- static BubbleData provideBubbleData(Context context,
+ static BubbleData provideBubbleData(
+ Context context,
BubbleLogger logger,
BubblePositioner positioner,
BubbleEducationController educationController,
@ShellMainThread ShellExecutor mainExecutor,
@ShellBackgroundThread ShellExecutor bgExecutor) {
- return new BubbleData(context, logger, positioner, educationController, mainExecutor,
- bgExecutor);
+ return new BubbleData(
+ context, logger, positioner, educationController, mainExecutor, bgExecutor);
}
// Note: Handler needed for LauncherApps.register
@WMSingleton
@Provides
- static BubbleController provideBubbleController(Context context,
+ static BubbleController provideBubbleController(
+ Context context,
ShellInit shellInit,
ShellCommandHandler shellCommandHandler,
ShellController shellController,
@@ -224,14 +221,38 @@
Transitions transitions,
SyncTransactionQueue syncQueue,
IWindowManager wmService) {
- return new BubbleController(context, shellInit, shellCommandHandler, shellController, data,
- null /* synchronizer */, floatingContentCoordinator,
- new BubbleDataRepository(launcherApps, mainExecutor, bgExecutor,
+ return new BubbleController(
+ context,
+ shellInit,
+ shellCommandHandler,
+ shellController,
+ data,
+ null /* synchronizer */,
+ floatingContentCoordinator,
+ new BubbleDataRepository(
+ launcherApps,
+ mainExecutor,
+ bgExecutor,
new BubblePersistentRepository(context)),
- statusBarService, windowManager, windowManagerShellWrapper, userManager,
- launcherApps, logger, taskStackListener, organizer, positioner, displayController,
- oneHandedOptional, dragAndDropController, mainExecutor, mainHandler, bgExecutor,
- taskViewTransitions, transitions, syncQueue, wmService,
+ statusBarService,
+ windowManager,
+ windowManagerShellWrapper,
+ userManager,
+ launcherApps,
+ logger,
+ taskStackListener,
+ organizer,
+ positioner,
+ displayController,
+ oneHandedOptional,
+ dragAndDropController,
+ mainExecutor,
+ mainHandler,
+ bgExecutor,
+ taskViewTransitions,
+ transitions,
+ syncQueue,
+ wmService,
ProdBubbleProperties.INSTANCE);
}
@@ -318,9 +339,7 @@
@WMSingleton
@Provides
static AppToWebGenericLinksParser provideGenericLinksParser(
- Context context,
- @ShellMainThread ShellExecutor mainExecutor
- ) {
+ Context context, @ShellMainThread ShellExecutor mainExecutor) {
return new AppToWebGenericLinksParser(context, mainExecutor);
}
@@ -328,8 +347,7 @@
static AssistContentRequester provideAssistContentRequester(
Context context,
@ShellMainThread ShellExecutor shellExecutor,
- @ShellBackgroundThread ShellExecutor bgExecutor
- ) {
+ @ShellBackgroundThread ShellExecutor bgExecutor) {
return new AssistContentRequester(context, shellExecutor, bgExecutor);
}
@@ -366,15 +384,20 @@
Optional<DesktopRepository> desktopRepository,
Optional<DesktopTasksController> desktopTasksController,
LaunchAdjacentController launchAdjacentController,
- WindowDecorViewModel windowDecorViewModel) {
+ WindowDecorViewModel windowDecorViewModel,
+ Optional<TaskChangeListener> taskChangeListener) {
// TODO(b/238217847): Temporarily add this check here until we can remove the dynamic
// override for this controller from the base module
- ShellInit init = FreeformComponents.isFreeformEnabled(context)
- ? shellInit
- : null;
- return new FreeformTaskListener(context, init, shellTaskOrganizer,
- desktopRepository, desktopTasksController, launchAdjacentController,
- windowDecorViewModel);
+ ShellInit init = FreeformComponents.isFreeformEnabled(context) ? shellInit : null;
+ return new FreeformTaskListener(
+ context,
+ init,
+ shellTaskOrganizer,
+ desktopRepository,
+ desktopTasksController,
+ launchAdjacentController,
+ windowDecorViewModel,
+ taskChangeListener);
}
@WMSingleton
@@ -385,10 +408,7 @@
@ShellMainThread ShellExecutor mainExecutor,
@ShellAnimationThread ShellExecutor animExecutor) {
return new FreeformTaskTransitionHandler(
- transitions,
- displayController,
- mainExecutor,
- animExecutor);
+ transitions, displayController, mainExecutor, animExecutor);
}
@WMSingleton
@@ -402,8 +422,13 @@
Optional<TaskChangeListener> taskChangeListener,
FocusTransitionObserver focusTransitionObserver) {
return new FreeformTaskTransitionObserver(
- context, shellInit, transitions, desktopImmersiveController,
- windowDecorViewModel, taskChangeListener, focusTransitionObserver);
+ context,
+ shellInit,
+ transitions,
+ desktopImmersiveController,
+ windowDecorViewModel,
+ taskChangeListener,
+ focusTransitionObserver);
}
@WMSingleton
@@ -419,8 +444,8 @@
} else {
transitionStarter = freeformTaskTransitionHandler;
}
- return new FreeformTaskTransitionStarterInitializer(shellInit, windowDecorViewModel,
- transitionStarter);
+ return new FreeformTaskTransitionStarterInitializer(
+ shellInit, windowDecorViewModel, transitionStarter);
}
//
@@ -431,7 +456,8 @@
@WMSingleton
@Provides
@DynamicOverride
- static OneHandedController provideOneHandedController(Context context,
+ static OneHandedController provideOneHandedController(
+ Context context,
ShellInit shellInit,
ShellCommandHandler shellCommandHandler,
ShellController shellController,
@@ -443,9 +469,19 @@
InteractionJankMonitor jankMonitor,
@ShellMainThread ShellExecutor mainExecutor,
@ShellMainThread Handler mainHandler) {
- return OneHandedController.create(context, shellInit, shellCommandHandler, shellController,
- windowManager, displayController, displayLayout, taskStackListener, jankMonitor,
- uiEventLogger, mainExecutor, mainHandler);
+ return OneHandedController.create(
+ context,
+ shellInit,
+ shellCommandHandler,
+ shellController,
+ windowManager,
+ displayController,
+ displayLayout,
+ taskStackListener,
+ jankMonitor,
+ uiEventLogger,
+ mainExecutor,
+ mainHandler);
}
//
@@ -477,12 +513,29 @@
MultiInstanceHelper multiInstanceHelper,
@ShellMainThread ShellExecutor mainExecutor,
@ShellMainThread Handler mainHandler) {
- return new SplitScreenController(context, shellInit, shellCommandHandler, shellController,
- shellTaskOrganizer, syncQueue, rootTaskDisplayAreaOrganizer, displayController,
- displayImeController, displayInsetsController, dragAndDropController, transitions,
- transactionPool, iconProvider, recentTasks, launchAdjacentController,
- windowDecorViewModel, desktopTasksController, null /* stageCoordinator */,
- multiInstanceHelper, mainExecutor, mainHandler);
+ return new SplitScreenController(
+ context,
+ shellInit,
+ shellCommandHandler,
+ shellController,
+ shellTaskOrganizer,
+ syncQueue,
+ rootTaskDisplayAreaOrganizer,
+ displayController,
+ displayImeController,
+ displayInsetsController,
+ dragAndDropController,
+ transitions,
+ transactionPool,
+ iconProvider,
+ recentTasks,
+ launchAdjacentController,
+ windowDecorViewModel,
+ desktopTasksController,
+ null /* stageCoordinator */,
+ multiInstanceHelper,
+ mainExecutor,
+ mainHandler);
}
//
@@ -502,10 +555,16 @@
Optional<UnfoldTransitionHandler> unfoldHandler,
Optional<ActivityEmbeddingController> activityEmbeddingController,
Transitions transitions) {
- return new DefaultMixedHandler(shellInit, transitions, splitScreenOptional,
- pipTransitionController, recentsTransitionHandler,
- keyguardTransitionHandler, desktopTasksController,
- unfoldHandler, activityEmbeddingController);
+ return new DefaultMixedHandler(
+ shellInit,
+ transitions,
+ splitScreenOptional,
+ pipTransitionController,
+ recentsTransitionHandler,
+ keyguardTransitionHandler,
+ desktopTasksController,
+ unfoldHandler,
+ activityEmbeddingController);
}
@WMSingleton
@@ -516,8 +575,12 @@
Transitions transitions,
Optional<RecentTasksController> recentTasksController,
HomeTransitionObserver homeTransitionObserver) {
- return new RecentsTransitionHandler(shellInit, shellTaskOrganizer, transitions,
- recentTasksController.orElse(null), homeTransitionObserver);
+ return new RecentsTransitionHandler(
+ shellInit,
+ shellTaskOrganizer,
+ transitions,
+ recentTasksController.orElse(null),
+ homeTransitionObserver);
}
//
@@ -534,8 +597,7 @@
FullscreenUnfoldTaskAnimator fullscreenAnimator,
Lazy<Optional<UnfoldTransitionHandler>> unfoldTransitionHandler,
ShellInit shellInit,
- @ShellMainThread ShellExecutor mainExecutor
- ) {
+ @ShellMainThread ShellExecutor mainExecutor) {
final List<UnfoldTaskAnimator> animators = new ArrayList<>();
animators.add(splitAnimator);
animators.add(fullscreenAnimator);
@@ -546,8 +608,7 @@
progressProvider.get(),
animators,
unfoldTransitionHandler,
- mainExecutor
- );
+ mainExecutor);
}
@Provides
@@ -555,10 +616,9 @@
Context context,
UnfoldBackgroundController unfoldBackgroundController,
ShellController shellController,
- DisplayInsetsController displayInsetsController
- ) {
- return new FullscreenUnfoldTaskAnimator(context, unfoldBackgroundController,
- shellController, displayInsetsController);
+ DisplayInsetsController displayInsetsController) {
+ return new FullscreenUnfoldTaskAnimator(
+ context, unfoldBackgroundController, shellController, displayInsetsController);
}
@Provides
@@ -568,14 +628,18 @@
ShellController shellController,
@ShellMainThread ShellExecutor executor,
Lazy<Optional<SplitScreenController>> splitScreenOptional,
- DisplayInsetsController displayInsetsController
- ) {
+ DisplayInsetsController displayInsetsController) {
// TODO(b/238217847): The lazy reference here causes some dependency issues since it
// immediately registers a listener on that controller on init. We should reference the
// controller directly once we refactor ShellTaskOrganizer to not depend on the unfold
// animation controller directly.
- return new SplitTaskUnfoldAnimator(context, executor, splitScreenOptional,
- shellController, backgroundController, displayInsetsController);
+ return new SplitTaskUnfoldAnimator(
+ context,
+ executor,
+ splitScreenOptional,
+ shellController,
+ backgroundController,
+ displayInsetsController);
}
@WMSingleton
@@ -602,8 +666,15 @@
@ShellMainThread ShellExecutor executor,
@ShellMainThread Handler handler,
ShellInit shellInit) {
- return new UnfoldTransitionHandler(shellInit, progressProvider.get(), animator,
- unfoldAnimator, transactionPool, executor, handler, transitions);
+ return new UnfoldTransitionHandler(
+ shellInit,
+ progressProvider.get(),
+ animator,
+ unfoldAnimator,
+ transactionPool,
+ executor,
+ handler,
+ transitions);
}
@WMSingleton
@@ -652,18 +723,38 @@
FocusTransitionObserver focusTransitionObserver,
DesktopModeEventLogger desktopModeEventLogger,
DesktopTilingDecorViewModel desktopTilingDecorViewModel) {
- return new DesktopTasksController(context, shellInit, shellCommandHandler, shellController,
- displayController, shellTaskOrganizer, syncQueue, rootTaskDisplayAreaOrganizer,
- dragAndDropController, transitions, keyguardManager,
- returnToDragStartAnimator, enterDesktopTransitionHandler,
- exitDesktopTransitionHandler, desktopModeDragAndDropTransitionHandler,
+ return new DesktopTasksController(
+ context,
+ shellInit,
+ shellCommandHandler,
+ shellController,
+ displayController,
+ shellTaskOrganizer,
+ syncQueue,
+ rootTaskDisplayAreaOrganizer,
+ dragAndDropController,
+ transitions,
+ keyguardManager,
+ returnToDragStartAnimator,
+ enterDesktopTransitionHandler,
+ exitDesktopTransitionHandler,
+ desktopModeDragAndDropTransitionHandler,
toggleResizeDesktopTaskTransitionHandler,
- dragToDesktopTransitionHandler, desktopImmersiveController.get(),
+ dragToDesktopTransitionHandler,
+ desktopImmersiveController.get(),
desktopRepository,
- desktopModeLoggerTransitionObserver, launchAdjacentController,
- recentsTransitionHandler, multiInstanceHelper, mainExecutor, desktopTasksLimiter,
- recentTasksController.orElse(null), interactionJankMonitor, mainHandler,
- inputManager, focusTransitionObserver, desktopModeEventLogger,
+ desktopModeLoggerTransitionObserver,
+ launchAdjacentController,
+ recentsTransitionHandler,
+ multiInstanceHelper,
+ mainExecutor,
+ desktopTasksLimiter,
+ recentTasksController.orElse(null),
+ interactionJankMonitor,
+ mainHandler,
+ inputManager,
+ focusTransitionObserver,
+ desktopModeEventLogger,
desktopTilingDecorViewModel);
}
@@ -693,10 +784,11 @@
@WMSingleton
@Provides
- static Optional<TaskChangeListener> provideDesktopTaskChangeListener(Context context) {
- if (Flags.enableWindowingTransitionHandlersObservers() &&
- DesktopModeStatus.canEnterDesktopMode(context)) {
- return Optional.of(new DesktopTaskChangeListener());
+ static Optional<TaskChangeListener> provideDesktopTaskChangeListener(
+ Context context, @DynamicOverride DesktopRepository desktopRepository) {
+ if (ENABLE_WINDOWING_TRANSITION_HANDLERS_OBSERVERS.isTrue()
+ && DesktopModeStatus.canEnterDesktopMode(context)) {
+ return Optional.of(new DesktopTaskChangeListener(desktopRepository));
}
return Optional.empty();
}
@@ -724,8 +816,7 @@
maxTaskLimit,
interactionJankMonitor,
context,
- handler)
- );
+ handler));
}
@WMSingleton
@@ -739,10 +830,7 @@
if (DesktopModeStatus.canEnterDesktopMode(context)) {
return Optional.of(
new DesktopImmersiveController(
- transitions,
- desktopRepository,
- displayController,
- shellTaskOrganizer));
+ transitions, desktopRepository, displayController, shellTaskOrganizer));
}
return Optional.empty();
}
@@ -754,7 +842,6 @@
return new ReturnToDragStartAnimator(context, interactionJankMonitor);
}
-
@WMSingleton
@Provides
static DragToDesktopTransitionHandler provideDragToDesktopTransitionHandler(
@@ -762,12 +849,12 @@
Transitions transitions,
RootTaskDisplayAreaOrganizer rootTaskDisplayAreaOrganizer,
InteractionJankMonitor interactionJankMonitor) {
- return (Flags.enableDesktopWindowingTransitions() ||
- ENABLE_DESKTOP_WINDOWING_ENTER_TRANSITIONS.isTrue())
- ? new SpringDragToDesktopTransitionHandler(context, transitions,
- rootTaskDisplayAreaOrganizer, interactionJankMonitor)
- : new DefaultDragToDesktopTransitionHandler(context, transitions,
- rootTaskDisplayAreaOrganizer, interactionJankMonitor);
+ return (Flags.enableDesktopWindowingTransitions()
+ || ENABLE_DESKTOP_WINDOWING_ENTER_TRANSITIONS.isTrue())
+ ? new SpringDragToDesktopTransitionHandler(
+ context, transitions, rootTaskDisplayAreaOrganizer, interactionJankMonitor)
+ : new DefaultDragToDesktopTransitionHandler(
+ context, transitions, rootTaskDisplayAreaOrganizer, interactionJankMonitor);
}
@WMSingleton
@@ -802,31 +889,26 @@
static CloseDesktopTaskTransitionHandler provideCloseDesktopTaskTransitionHandler(
Context context,
@ShellMainThread ShellExecutor mainExecutor,
- @ShellAnimationThread ShellExecutor animExecutor
- ) {
+ @ShellAnimationThread ShellExecutor animExecutor) {
return new CloseDesktopTaskTransitionHandler(context, mainExecutor, animExecutor);
}
@WMSingleton
@Provides
static DesktopModeDragAndDropTransitionHandler provideDesktopModeDragAndDropTransitionHandler(
- Transitions transitions
- ) {
+ Transitions transitions) {
return new DesktopModeDragAndDropTransitionHandler(transitions);
}
@WMSingleton
@Provides
@DynamicOverride
-
static DesktopRepository provideDesktopRepository(
Context context,
ShellInit shellInit,
DesktopPersistentRepository desktopPersistentRepository,
- @ShellMainThread CoroutineScope mainScope
- ) {
- return new DesktopRepository(context, shellInit, desktopPersistentRepository,
- mainScope);
+ @ShellMainThread CoroutineScope mainScope) {
+ return new DesktopRepository(context, shellInit, desktopPersistentRepository, mainScope);
}
@WMSingleton
@@ -837,12 +919,16 @@
ShellTaskOrganizer shellTaskOrganizer,
TaskStackListenerImpl taskStackListener,
ToggleResizeDesktopTaskTransitionHandler toggleResizeDesktopTaskTransitionHandler,
- @DynamicOverride DesktopRepository desktopRepository
- ) {
+ @DynamicOverride DesktopRepository desktopRepository) {
if (DesktopModeStatus.canEnterDesktopMode(context)) {
- return Optional.of(new DesktopActivityOrientationChangeHandler(
- context, shellInit, shellTaskOrganizer, taskStackListener,
- toggleResizeDesktopTaskTransitionHandler, desktopRepository));
+ return Optional.of(
+ new DesktopActivityOrientationChangeHandler(
+ context,
+ shellInit,
+ shellTaskOrganizer,
+ taskStackListener,
+ toggleResizeDesktopTaskTransitionHandler,
+ desktopRepository));
}
return Optional.empty();
}
@@ -854,12 +940,16 @@
Optional<DesktopRepository> desktopRepository,
Transitions transitions,
ShellTaskOrganizer shellTaskOrganizer,
- ShellInit shellInit
- ) {
- return desktopRepository.flatMap(repository ->
- Optional.of(new DesktopTasksTransitionObserver(
- context, repository, transitions, shellTaskOrganizer, shellInit))
- );
+ ShellInit shellInit) {
+ return desktopRepository.flatMap(
+ repository ->
+ Optional.of(
+ new DesktopTasksTransitionObserver(
+ context,
+ repository,
+ transitions,
+ shellTaskOrganizer,
+ shellInit)));
}
@WMSingleton
@@ -871,8 +961,7 @@
FreeformTaskTransitionHandler freeformTaskTransitionHandler,
CloseDesktopTaskTransitionHandler closeDesktopTaskTransitionHandler,
InteractionJankMonitor interactionJankMonitor,
- @ShellMainThread Handler handler
- ) {
+ @ShellMainThread Handler handler) {
if (!DesktopModeStatus.canEnterDesktopMode(context)) {
return Optional.empty();
}
@@ -929,12 +1018,11 @@
@Provides
static DesktopWindowingEducationTooltipController
provideDesktopWindowingEducationTooltipController(
- Context context,
- AdditionalSystemViewContainer.Factory additionalSystemViewContainerFactory,
- DisplayController displayController
- ) {
- return new DesktopWindowingEducationTooltipController(context,
- additionalSystemViewContainerFactory, displayController);
+ Context context,
+ AdditionalSystemViewContainer.Factory additionalSystemViewContainerFactory,
+ DisplayController displayController) {
+ return new DesktopWindowingEducationTooltipController(
+ context, additionalSystemViewContainerFactory, displayController);
}
@OptIn(markerClass = ExperimentalCoroutinesApi.class)
@@ -946,19 +1034,22 @@
AppHandleEducationDatastoreRepository appHandleEducationDatastoreRepository,
WindowDecorCaptionHandleRepository windowDecorCaptionHandleRepository,
DesktopWindowingEducationTooltipController desktopWindowingEducationTooltipController,
- @ShellMainThread CoroutineScope applicationScope, @ShellBackgroundThread
- MainCoroutineDispatcher backgroundDispatcher) {
- return new AppHandleEducationController(context, appHandleEducationFilter,
- appHandleEducationDatastoreRepository, windowDecorCaptionHandleRepository,
- desktopWindowingEducationTooltipController, applicationScope,
+ @ShellMainThread CoroutineScope applicationScope,
+ @ShellBackgroundThread MainCoroutineDispatcher backgroundDispatcher) {
+ return new AppHandleEducationController(
+ context,
+ appHandleEducationFilter,
+ appHandleEducationDatastoreRepository,
+ windowDecorCaptionHandleRepository,
+ desktopWindowingEducationTooltipController,
+ applicationScope,
backgroundDispatcher);
}
@WMSingleton
@Provides
static DesktopPersistentRepository provideDesktopPersistentRepository(
- Context context,
- @ShellBackgroundThread CoroutineScope bgScope) {
+ Context context, @ShellBackgroundThread CoroutineScope bgScope) {
return new DesktopPersistentRepository(context, bgScope);
}
@@ -969,14 +1060,14 @@
@WMSingleton
@Provides
static GlobalDragListener provideGlobalDragListener(
- IWindowManager wmService,
- @ShellMainThread ShellExecutor mainExecutor) {
+ IWindowManager wmService, @ShellMainThread ShellExecutor mainExecutor) {
return new GlobalDragListener(wmService, mainExecutor);
}
@WMSingleton
@Provides
- static DragAndDropController provideDragAndDropController(Context context,
+ static DragAndDropController provideDragAndDropController(
+ Context context,
ShellInit shellInit,
ShellController shellController,
ShellCommandHandler shellCommandHandler,
@@ -987,9 +1078,18 @@
GlobalDragListener globalDragListener,
Transitions transitions,
@ShellMainThread ShellExecutor mainExecutor) {
- return new DragAndDropController(context, shellInit, shellController, shellCommandHandler,
- shellTaskOrganizer, displayController, uiEventLogger, iconProvider,
- globalDragListener, transitions, mainExecutor);
+ return new DragAndDropController(
+ context,
+ shellInit,
+ shellController,
+ shellCommandHandler,
+ shellTaskOrganizer,
+ displayController,
+ uiEventLogger,
+ iconProvider,
+ globalDragListener,
+ transitions,
+ mainExecutor);
}
//
@@ -1003,8 +1103,7 @@
@Provides
static Object provideIndependentShellComponentsToCreate(
DragAndDropController dragAndDropController,
- Optional<DesktopTasksTransitionObserver> desktopTasksTransitionObserverOptional
- ) {
+ Optional<DesktopTasksTransitionObserver> desktopTasksTransitionObserverOptional) {
return new Object();
}
}
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopTaskChangeListener.kt b/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopTaskChangeListener.kt
index 1ee2de9..237a465 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopTaskChangeListener.kt
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopTaskChangeListener.kt
@@ -17,21 +17,60 @@
package com.android.wm.shell.desktopmode
import android.app.ActivityManager.RunningTaskInfo
+import android.app.WindowConfiguration.WINDOWING_MODE_FREEFORM
+import android.window.DesktopModeFlags
import com.android.wm.shell.freeform.TaskChangeListener
/** Manages tasks handling specific to Android Desktop Mode. */
-class DesktopTaskChangeListener: TaskChangeListener {
+class DesktopTaskChangeListener(
+ private val desktopRepository: DesktopRepository,
+) : TaskChangeListener {
override fun onTaskOpening(taskInfo: RunningTaskInfo) {
- // TODO: b/367268953 - Connect this with DesktopRepository.
+ if (!isFreeformTask(taskInfo) && desktopRepository.isActiveTask(taskInfo.taskId)) {
+ desktopRepository.removeFreeformTask(taskInfo.displayId, taskInfo.taskId)
+ return
+ }
+ if (isFreeformTask(taskInfo)) {
+ desktopRepository.addOrMoveFreeformTaskToTop(taskInfo.displayId, taskInfo.taskId)
+ if (taskInfo.isVisible) {
+ desktopRepository.addActiveTask(taskInfo.displayId, taskInfo.taskId)
+ desktopRepository.updateTaskVisibility(taskInfo.displayId, taskInfo.taskId, visible = true)
+ }
+ }
}
override fun onTaskChanging(taskInfo: RunningTaskInfo) {
- // TODO: b/367268953 - Connect this with DesktopRepository.
+ if (!desktopRepository.isActiveTask(taskInfo.taskId)) return
+
+ // Case 1: Freeform task is changed in Desktop Mode.
+ if (isFreeformTask(taskInfo)) {
+ if (taskInfo.isVisible) {
+ desktopRepository.addActiveTask(taskInfo.displayId, taskInfo.taskId)
+ }
+ desktopRepository.updateTaskVisibility(
+ taskInfo.displayId, taskInfo.taskId, taskInfo.isVisible)
+ } else {
+ // Case 2: Freeform task is changed outside Desktop Mode.
+ desktopRepository.removeFreeformTask(taskInfo.displayId, taskInfo.taskId)
+ }
+ }
+
+ // This method should only be used for scenarios where the task info changes are not propagated to
+ // [DesktopTaskChangeListener#onTaskChanging] via [TransitionsObserver].
+ // Any changes to [DesktopRepository] from this method should be made carefully to minimize risk
+ // of race conditions and possible duplications with [onTaskChanging].
+ override fun onNonTransitionTaskChanging(taskInfo: RunningTaskInfo) {
+ // TODO: b/367268953 - Propapagate usages from FreeformTaskListener to this method.
}
override fun onTaskMovingToFront(taskInfo: RunningTaskInfo) {
- // TODO: b/367268953 - Connect this with DesktopRepository.
+ if (!desktopRepository.isActiveTask(taskInfo.taskId)) return
+ if (!isFreeformTask(taskInfo)) {
+ desktopRepository.removeFreeformTask(taskInfo.displayId, taskInfo.taskId)
+ }
+ // TODO: b/367268953 - Connect this with DesktopRepository for handling
+ // task moving to front for tasks in windowing mode.
}
override fun onTaskMovingToBack(taskInfo: RunningTaskInfo) {
@@ -39,6 +78,20 @@
}
override fun onTaskClosing(taskInfo: RunningTaskInfo) {
- // TODO: b/367268953 - Connect this with DesktopRepository.
+ if (!desktopRepository.isActiveTask(taskInfo.taskId)) return
+ // TODO: b/370038902 - Handle Activity#finishAndRemoveTask.
+ if (!DesktopModeFlags.ENABLE_DESKTOP_WINDOWING_BACK_NAVIGATION.isTrue() ||
+ desktopRepository.isClosingTask(taskInfo.taskId)) {
+ // A task that's vanishing should be removed:
+ // - If it's closed by the X button which means it's marked as a closing task.
+ desktopRepository.removeClosingTask(taskInfo.taskId)
+ desktopRepository.removeFreeformTask(taskInfo.displayId, taskInfo.taskId)
+ } else {
+ desktopRepository.updateTaskVisibility(taskInfo.displayId, taskInfo.taskId, visible = false)
+ desktopRepository.minimizeTask(taskInfo.displayId, taskInfo.taskId)
+ }
}
+
+ private fun isFreeformTask(taskInfo: RunningTaskInfo): Boolean =
+ taskInfo.windowingMode == WINDOWING_MODE_FREEFORM
}
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/freeform/FreeformTaskListener.java b/libs/WindowManager/Shell/src/com/android/wm/shell/freeform/FreeformTaskListener.java
index a16446ff..af87ab7 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/freeform/FreeformTaskListener.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/freeform/FreeformTaskListener.java
@@ -17,7 +17,6 @@
package com.android.wm.shell.freeform;
import static android.app.WindowConfiguration.WINDOWING_MODE_FREEFORM;
-
import static com.android.wm.shell.ShellTaskOrganizer.TASK_LISTENER_TYPE_FREEFORM;
import android.app.ActivityManager.RunningTaskInfo;
@@ -54,6 +53,7 @@
private final Optional<DesktopTasksController> mDesktopTasksController;
private final WindowDecorViewModel mWindowDecorationViewModel;
private final LaunchAdjacentController mLaunchAdjacentController;
+ private final Optional<TaskChangeListener> mTaskChangeListener;
private final SparseArray<State> mTasks = new SparseArray<>();
@@ -69,13 +69,15 @@
Optional<DesktopRepository> desktopRepository,
Optional<DesktopTasksController> desktopTasksController,
LaunchAdjacentController launchAdjacentController,
- WindowDecorViewModel windowDecorationViewModel) {
+ WindowDecorViewModel windowDecorationViewModel,
+ Optional<TaskChangeListener> taskChangeListener) {
mContext = context;
mShellTaskOrganizer = shellTaskOrganizer;
mWindowDecorationViewModel = windowDecorationViewModel;
mDesktopRepository = desktopRepository;
mDesktopTasksController = desktopTasksController;
mLaunchAdjacentController = launchAdjacentController;
+ mTaskChangeListener = taskChangeListener;
if (shellInit != null) {
shellInit.addInitCallback(this::onInit, this);
}
@@ -100,7 +102,8 @@
state.mLeash = leash;
mTasks.put(taskInfo.taskId, state);
- if (DesktopModeStatus.canEnterDesktopMode(mContext)) {
+ if (!DesktopModeFlags.ENABLE_WINDOWING_TRANSITION_HANDLERS_OBSERVERS.isTrue() &&
+ DesktopModeStatus.canEnterDesktopMode(mContext)) {
mDesktopRepository.ifPresent(repository -> {
repository.addOrMoveFreeformTaskToTop(taskInfo.displayId, taskInfo.taskId);
if (taskInfo.isVisible) {
@@ -119,7 +122,8 @@
taskInfo.taskId);
mTasks.remove(taskInfo.taskId);
- if (DesktopModeStatus.canEnterDesktopMode(mContext)) {
+ if (!DesktopModeFlags.ENABLE_WINDOWING_TRANSITION_HANDLERS_OBSERVERS.isTrue() &&
+ DesktopModeStatus.canEnterDesktopMode(mContext)) {
mDesktopRepository.ifPresent(repository -> {
// TODO: b/370038902 - Handle Activity#finishAndRemoveTask.
if (!DesktopModeFlags.ENABLE_DESKTOP_WINDOWING_BACK_NAVIGATION.isTrue()
@@ -148,13 +152,20 @@
mWindowDecorationViewModel.onTaskInfoChanged(taskInfo);
state.mTaskInfo = taskInfo;
if (DesktopModeStatus.canEnterDesktopMode(mContext)) {
- mDesktopRepository.ifPresent(repository -> {
- if (taskInfo.isVisible) {
- repository.addActiveTask(taskInfo.displayId, taskInfo.taskId);
- }
- repository.updateTaskVisibility(taskInfo.displayId, taskInfo.taskId,
+ if (DesktopModeFlags.ENABLE_WINDOWING_TRANSITION_HANDLERS_OBSERVERS.isTrue()) {
+ // Pass task info changes to the [TaskChangeListener] since [TransitionsObserver]
+ // does not propagate all task info changes.
+ mTaskChangeListener.ifPresent(listener ->
+ listener.onNonTransitionTaskChanging(taskInfo));
+ } else {
+ mDesktopRepository.ifPresent(repository -> {
+ if (taskInfo.isVisible) {
+ repository.addActiveTask(taskInfo.displayId, taskInfo.taskId);
+ }
+ repository.updateTaskVisibility(taskInfo.displayId, taskInfo.taskId,
taskInfo.isVisible);
- });
+ });
+ }
}
updateLaunchAdjacentController();
}
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/freeform/FreeformTaskTransitionObserver.java b/libs/WindowManager/Shell/src/com/android/wm/shell/freeform/FreeformTaskTransitionObserver.java
index 7631ece..18f9cc7 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/freeform/FreeformTaskTransitionObserver.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/freeform/FreeformTaskTransitionObserver.java
@@ -42,9 +42,9 @@
import java.util.Optional;
/**
- * The {@link Transitions.TransitionHandler} that handles freeform task launches, closes,
- * maximizing and restoring transitions. It also reports transitions so that window decorations can
- * be a part of transitions.
+ * The {@link Transitions.TransitionHandler} that handles freeform task launches, closes, maximizing
+ * and restoring transitions. It also reports transitions so that window decorations can be a part
+ * of transitions.
*/
public class FreeformTaskTransitionObserver implements Transitions.TransitionObserver {
private final Transitions mTransitions;
@@ -89,8 +89,8 @@
// TODO(b/367268953): Remove when DesktopTaskListener is introduced and the repository
// is updated from there **before** the |mWindowDecorViewModel| methods are invoked.
// Otherwise window decoration relayout won't run with the immersive state up to date.
- mDesktopImmersiveController.ifPresent(h ->
- h.onTransitionReady(transition, info, startT, finishT));
+ mDesktopImmersiveController.ifPresent(
+ h -> h.onTransitionReady(transition, info, startT, finishT));
}
// Update focus state first to ensure the correct state can be queried from listeners.
// TODO(371503964): Remove this once the unified task repository is ready.
@@ -147,33 +147,28 @@
TransitionInfo.Change change,
SurfaceControl.Transaction startT,
SurfaceControl.Transaction finishT) {
- mTaskChangeListener.ifPresent(
- listener -> listener.onTaskOpening(change.getTaskInfo()));
+ mTaskChangeListener.ifPresent(listener -> listener.onTaskOpening(change.getTaskInfo()));
mWindowDecorViewModel.onTaskOpening(
- change.getTaskInfo(), change.getLeash(), startT, finishT);
+ change.getTaskInfo(), change.getLeash(), startT, finishT);
}
private void onCloseTransitionReady(
TransitionInfo.Change change,
SurfaceControl.Transaction startT,
SurfaceControl.Transaction finishT) {
- mTaskChangeListener.ifPresent(
- listener -> listener.onTaskClosing(change.getTaskInfo()));
+ mTaskChangeListener.ifPresent(listener -> listener.onTaskClosing(change.getTaskInfo()));
mWindowDecorViewModel.onTaskClosing(change.getTaskInfo(), startT, finishT);
-
}
private void onChangeTransitionReady(
TransitionInfo.Change change,
SurfaceControl.Transaction startT,
SurfaceControl.Transaction finishT) {
- mTaskChangeListener.ifPresent(listener ->
- listener.onTaskChanging(change.getTaskInfo()));
+ mTaskChangeListener.ifPresent(listener -> listener.onTaskChanging(change.getTaskInfo()));
mWindowDecorViewModel.onTaskChanging(
change.getTaskInfo(), change.getLeash(), startT, finishT);
}
-
private void onToFrontTransitionReady(
TransitionInfo.Change change,
SurfaceControl.Transaction startT,
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/freeform/TaskChangeListener.kt b/libs/WindowManager/Shell/src/com/android/wm/shell/freeform/TaskChangeListener.kt
index f07c069..fb86a9f 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/freeform/TaskChangeListener.kt
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/freeform/TaskChangeListener.kt
@@ -16,7 +16,7 @@
package com.android.wm.shell.freeform
-import android.app.ActivityManager.RunningTaskInfo;
+import android.app.ActivityManager.RunningTaskInfo
/**
* Interface used by [FreeformTaskTransitionObserver] to manage freeform tasks.
@@ -24,18 +24,27 @@
* The implementations are responsible for handle all the task management.
*/
interface TaskChangeListener {
- /** Notifies a task opening in freeform mode. */
- fun onTaskOpening(taskInfo: RunningTaskInfo)
+ /** Notifies a task opening in freeform mode. */
+ fun onTaskOpening(taskInfo: RunningTaskInfo)
- /** Notifies a task info update on the given task. */
- fun onTaskChanging(taskInfo: RunningTaskInfo)
+ /** Notifies a task info update on the given task from Shell Transitions framework. */
+ fun onTaskChanging(taskInfo: RunningTaskInfo)
- /** Notifies a task moving to the front. */
- fun onTaskMovingToFront(taskInfo: RunningTaskInfo)
+ /**
+ * Notifies a task info update on the given task from [FreeformTaskListener].
+ *
+ * This is used to propagate task info changes since not all task changes are propagated from
+ * [TransitionObserver] in [onTaskChanging]. It is recommended to use [onTaskChanging] instead of
+ * this method where possible.
+ */
+ fun onNonTransitionTaskChanging(taskInfo: RunningTaskInfo)
- /** Notifies a task moving to the back. */
- fun onTaskMovingToBack(taskInfo: RunningTaskInfo)
+ /** Notifies a task moving to the front. */
+ fun onTaskMovingToFront(taskInfo: RunningTaskInfo)
- /** Notifies a task is closing. */
- fun onTaskClosing(taskInfo: RunningTaskInfo)
-}
\ No newline at end of file
+ /** Notifies a task moving to the back. */
+ fun onTaskMovingToBack(taskInfo: RunningTaskInfo)
+
+ /** Notifies a task is closing. */
+ fun onTaskClosing(taskInfo: RunningTaskInfo)
+}
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/desktopmode/DesktopTaskChangeListenerTest.kt b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/desktopmode/DesktopTaskChangeListenerTest.kt
new file mode 100644
index 0000000..8ae8b0f
--- /dev/null
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/desktopmode/DesktopTaskChangeListenerTest.kt
@@ -0,0 +1,180 @@
+/*
+ * 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.desktopmode
+
+import android.platform.test.annotations.DisableFlags
+import android.platform.test.annotations.EnableFlags
+import android.platform.test.flag.junit.SetFlagsRule
+import android.testing.AndroidTestingRunner
+import androidx.test.filters.SmallTest
+import com.android.window.flags.Flags.FLAG_ENABLE_DESKTOP_WINDOWING_BACK_NAVIGATION
+import com.android.wm.shell.ShellTestCase
+import com.android.wm.shell.desktopmode.DesktopTestHelpers.Companion.createFreeformTask
+import com.android.wm.shell.desktopmode.DesktopTestHelpers.Companion.createFullscreenTask
+import org.junit.Before
+import org.junit.Rule
+import org.junit.Test
+import org.junit.runner.RunWith
+import org.mockito.kotlin.mock
+import org.mockito.kotlin.never
+import org.mockito.kotlin.verify
+import org.mockito.kotlin.whenever
+
+/**
+ * Tests for {@link DesktopTaskChangeListener}
+ *
+ * Build/Install/Run: atest WMShellUnitTests:DesktopTaskChangeListenerTest
+ */
+@SmallTest
+@RunWith(AndroidTestingRunner::class)
+class DesktopTaskChangeListenerTest : ShellTestCase() {
+
+ @JvmField @Rule val setFlagsRule = SetFlagsRule()
+
+ private lateinit var desktopTaskChangeListener: DesktopTaskChangeListener
+
+ private val desktopRepository = mock<DesktopRepository>()
+
+ @Before
+ fun setUp() {
+ desktopTaskChangeListener = DesktopTaskChangeListener(desktopRepository)
+ }
+
+ @Test
+ fun onTaskOpening_fullscreenTask_notActiveDesktopTask_noop() {
+ val task = createFullscreenTask().apply { isVisible = true }
+ whenever(desktopRepository.isActiveTask(task.taskId)).thenReturn(false)
+
+ desktopTaskChangeListener.onTaskOpening(task)
+
+ verify(desktopRepository, never()).addOrMoveFreeformTaskToTop(task.displayId, task.taskId)
+ verify(desktopRepository, never()).removeFreeformTask(task.displayId, task.taskId)
+ }
+
+ @Test
+ fun onTaskOpening_freeformTask_activeDesktopTask_removesTaskFromRepo() {
+ val task = createFullscreenTask().apply { isVisible = true }
+ whenever(desktopRepository.isActiveTask(task.taskId)).thenReturn(true)
+
+ desktopTaskChangeListener.onTaskOpening(task)
+
+ verify(desktopRepository).removeFreeformTask(task.displayId, task.taskId)
+ }
+
+ @Test
+ fun onTaskOpening_freeformTask_visibleDesktopTask_addsTaskToRepository() {
+ val task = createFreeformTask().apply { isVisible = true }
+ whenever(desktopRepository.isActiveTask(task.taskId)).thenReturn(false)
+
+ desktopTaskChangeListener.onTaskOpening(task)
+
+ verify(desktopRepository).addOrMoveFreeformTaskToTop(task.displayId, task.taskId)
+ verify(desktopRepository).addActiveTask(task.displayId, task.taskId)
+ verify(desktopRepository).updateTaskVisibility(task.displayId, task.taskId, visible = true)
+ }
+
+ @Test
+ fun onTaskOpening_freeformTask_nonVisibleDesktopTask_addsTaskToRepository() {
+ val task = createFreeformTask().apply { isVisible = false }
+ whenever(desktopRepository.isActiveTask(task.taskId)).thenReturn(true)
+
+ desktopTaskChangeListener.onTaskOpening(task)
+
+ verify(desktopRepository).addOrMoveFreeformTaskToTop(task.displayId, task.taskId)
+ }
+
+ @Test
+ fun onTaskChanging_freeformTaskOutsideDesktop_removesTaskFromRepo() {
+ val task = createFullscreenTask().apply { isVisible = true }
+ whenever(desktopRepository.isActiveTask(task.taskId)).thenReturn(true)
+
+ desktopTaskChangeListener.onTaskChanging(task)
+
+ verify(desktopRepository).removeFreeformTask(task.displayId, task.taskId)
+ }
+
+ @Test
+ fun onTaskChanging_visibleTaskInDesktop_updatesTaskVisibility() {
+ val task = createFreeformTask().apply { isVisible = true }
+ whenever(desktopRepository.isActiveTask(task.taskId)).thenReturn(true)
+
+ desktopTaskChangeListener.onTaskChanging(task)
+
+ verify(desktopRepository).addActiveTask(task.displayId, task.taskId)
+ verify(desktopRepository).updateTaskVisibility(task.displayId, task.taskId, task.isVisible)
+ }
+
+ @Test
+ fun onTaskChanging_nonVisibleTask_updatesTaskVisibility() {
+ val task = createFreeformTask().apply { isVisible = false }
+ whenever(desktopRepository.isActiveTask(task.taskId)).thenReturn(true)
+
+ desktopTaskChangeListener.onTaskChanging(task)
+
+ verify(desktopRepository).updateTaskVisibility(task.displayId, task.taskId, task.isVisible)
+ }
+
+ @Test
+ fun onTaskMovingToFront_freeformTaskOutsideDesktop_removesTaskFromRepo() {
+ val task = createFullscreenTask().apply { isVisible = true }
+ whenever(desktopRepository.isActiveTask(task.taskId)).thenReturn(true)
+
+ desktopTaskChangeListener.onTaskMovingToFront(task)
+
+ verify(desktopRepository).removeFreeformTask(task.displayId, task.taskId)
+ }
+
+ @Test
+ @EnableFlags(FLAG_ENABLE_DESKTOP_WINDOWING_BACK_NAVIGATION)
+ fun onTaskClosing_backNavEnabled_nonClosingTask_minimizesTaskInRepo() {
+ val task = createFreeformTask().apply { isVisible = true }
+ whenever(desktopRepository.isActiveTask(task.taskId)).thenReturn(true)
+ whenever(desktopRepository.isClosingTask(task.taskId)).thenReturn(false)
+
+ desktopTaskChangeListener.onTaskClosing(task)
+
+ verify(desktopRepository).updateTaskVisibility(task.displayId, task.taskId, visible = false)
+ verify(desktopRepository).minimizeTask(task.displayId, task.taskId)
+ }
+
+ @Test
+ @DisableFlags(FLAG_ENABLE_DESKTOP_WINDOWING_BACK_NAVIGATION)
+ fun onTaskClosing_backNavDisabled_closingTask_removesTaskInRepo() {
+ val task = createFreeformTask().apply { isVisible = true }
+ whenever(desktopRepository.isActiveTask(task.taskId)).thenReturn(true)
+ whenever(desktopRepository.isClosingTask(task.taskId)).thenReturn(true)
+
+ desktopTaskChangeListener.onTaskClosing(task)
+
+ verify(desktopRepository, never()).minimizeTask(task.displayId, task.taskId)
+ verify(desktopRepository).removeClosingTask(task.taskId)
+ verify(desktopRepository).removeFreeformTask(task.displayId, task.taskId)
+ }
+
+ @Test
+ @EnableFlags(FLAG_ENABLE_DESKTOP_WINDOWING_BACK_NAVIGATION)
+ fun onTaskClosing_backNavEnabled_closingTask_removesTaskFromRepo() {
+ val task = createFreeformTask().apply { isVisible = true }
+ whenever(desktopRepository.isActiveTask(task.taskId)).thenReturn(true)
+ whenever(desktopRepository.isClosingTask(task.taskId)).thenReturn(true)
+
+ desktopTaskChangeListener.onTaskClosing(task)
+
+ verify(desktopRepository).removeClosingTask(task.taskId)
+ verify(desktopRepository).removeFreeformTask(task.displayId, task.taskId)
+ }
+}
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/freeform/FreeformTaskListenerTests.java b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/freeform/FreeformTaskListenerTests.java
index 8dd1545..0a5397a 100644
--- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/freeform/FreeformTaskListenerTests.java
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/freeform/FreeformTaskListenerTests.java
@@ -23,13 +23,17 @@
import static com.android.dx.mockito.inline.extended.ExtendedMockito.doReturn;
import static com.android.dx.mockito.inline.extended.ExtendedMockito.mockitoSession;
import static com.android.window.flags.Flags.FLAG_ENABLE_DESKTOP_WINDOWING_BACK_NAVIGATION;
+import static com.android.window.flags.Flags.FLAG_ENABLE_WINDOWING_TRANSITION_HANDLERS_OBSERVERS;
+import static com.android.window.flags.Flags.FLAG_SHOW_DESKTOP_WINDOWING_DEV_OPTION;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.Mockito.never;
+import static org.mockito.Mockito.times;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
import android.app.ActivityManager;
+import android.platform.test.annotations.DisableFlags;
import android.platform.test.annotations.EnableFlags;
import android.platform.test.flag.junit.SetFlagsRule;
import android.view.SurfaceControl;
@@ -59,9 +63,8 @@
import java.util.Optional;
/**
- * Tests for {@link FreeformTaskListener}
- * Build/Install/Run:
- * atest WMShellUnitTests:FreeformTaskListenerTests
+ * Tests for {@link FreeformTaskListener} Build/Install/Run: atest
+ * WMShellUnitTests:FreeformTaskListenerTests
*/
@SmallTest
@RunWith(AndroidJUnit4.class)
@@ -84,41 +87,96 @@
private DesktopTasksController mDesktopTasksController;
@Mock
private LaunchAdjacentController mLaunchAdjacentController;
+ @Mock
+ private TaskChangeListener mTaskChangeListener;
+
private FreeformTaskListener mFreeformTaskListener;
private StaticMockitoSession mMockitoSession;
@Before
public void setup() {
- mMockitoSession = mockitoSession().initMocks(this)
- .strictness(Strictness.LENIENT).mockStatic(DesktopModeStatus.class).startMocking();
+ mMockitoSession =
+ mockitoSession()
+ .initMocks(this)
+ .strictness(Strictness.LENIENT)
+ .mockStatic(DesktopModeStatus.class)
+ .startMocking();
doReturn(true).when(() -> DesktopModeStatus.canEnterDesktopMode(any()));
- mFreeformTaskListener = new FreeformTaskListener(
- mContext,
- mShellInit,
- mTaskOrganizer,
- Optional.of(mDesktopRepository),
- Optional.of(mDesktopTasksController),
- mLaunchAdjacentController,
- mWindowDecorViewModel);
+ mFreeformTaskListener =
+ new FreeformTaskListener(
+ mContext,
+ mShellInit,
+ mTaskOrganizer,
+ Optional.of(mDesktopRepository),
+ Optional.of(mDesktopTasksController),
+ mLaunchAdjacentController,
+ mWindowDecorViewModel,
+ Optional.of(mTaskChangeListener));
}
@Test
- public void testFocusTaskChanged_freeformTaskIsAddedToRepo() {
- ActivityManager.RunningTaskInfo task = new TestRunningTaskInfoBuilder()
- .setWindowingMode(WINDOWING_MODE_FREEFORM).build();
+ @DisableFlags(FLAG_ENABLE_WINDOWING_TRANSITION_HANDLERS_OBSERVERS)
+ public void onTaskAppeared_noTransitionObservers_visibleTask_addsTaskToRepo() {
+ ActivityManager.RunningTaskInfo task =
+ new TestRunningTaskInfoBuilder().setWindowingMode(WINDOWING_MODE_FREEFORM).build();
+ task.isVisible = true;
+
+ mFreeformTaskListener.onTaskAppeared(task, mMockSurfaceControl);
+
+ verify(mDesktopRepository).addOrMoveFreeformTaskToTop(task.displayId, task.taskId);
+ verify(mDesktopRepository).addActiveTask(task.displayId, task.taskId);
+ verify(mDesktopRepository)
+ .updateTaskVisibility(task.displayId, task.taskId, task.isVisible);
+ }
+
+ @Test
+ @DisableFlags(FLAG_ENABLE_WINDOWING_TRANSITION_HANDLERS_OBSERVERS)
+ public void onTaskAppeared_noTransitionObservers_nonVisibleTask_addsTaskToRepo() {
+ ActivityManager.RunningTaskInfo task =
+ new TestRunningTaskInfoBuilder().setWindowingMode(WINDOWING_MODE_FREEFORM).build();
+ task.isVisible = false;
+
+ mFreeformTaskListener.onTaskAppeared(task, mMockSurfaceControl);
+
+ verify(mDesktopRepository).addOrMoveFreeformTaskToTop(task.displayId, task.taskId);
+ verify(mDesktopRepository, never()).addActiveTask(task.displayId, task.taskId);
+ verify(mDesktopRepository, never())
+ .updateTaskVisibility(task.displayId, task.taskId, task.isVisible);
+ }
+
+ @Test
+ @EnableFlags(FLAG_ENABLE_WINDOWING_TRANSITION_HANDLERS_OBSERVERS)
+ public void onTaskAppeared_useTransitionObserver_noopInRepository() {
+ ActivityManager.RunningTaskInfo task =
+ new TestRunningTaskInfoBuilder().setWindowingMode(WINDOWING_MODE_FREEFORM).build();
+ task.isVisible = true;
+
+ mFreeformTaskListener.onTaskAppeared(task, mMockSurfaceControl);
+
+ verify(mDesktopRepository, never()).addOrMoveFreeformTaskToTop(task.displayId, task.taskId);
+ verify(mDesktopRepository, never()).addActiveTask(task.displayId, task.taskId);
+ verify(mDesktopRepository, never())
+ .updateTaskVisibility(task.displayId, task.taskId, task.isVisible);
+ }
+
+ @Test
+ public void focusTaskChanged_addsFreeformTaskToRepo() {
+ ActivityManager.RunningTaskInfo task =
+ new TestRunningTaskInfoBuilder().setWindowingMode(WINDOWING_MODE_FREEFORM).build();
task.isFocused = true;
mFreeformTaskListener.onFocusTaskChanged(task);
- verify(mDesktopRepository)
- .addOrMoveFreeformTaskToTop(task.displayId, task.taskId);
+ verify(mDesktopRepository).addOrMoveFreeformTaskToTop(task.displayId, task.taskId);
}
@Test
- public void testFocusTaskChanged_fullscreenTaskIsNotAddedToRepo() {
- ActivityManager.RunningTaskInfo fullscreenTask = new TestRunningTaskInfoBuilder()
- .setWindowingMode(WINDOWING_MODE_FULLSCREEN).build();
+ public void focusTaskChanged_fullscreenTaskNotAddedToRepo() {
+ ActivityManager.RunningTaskInfo fullscreenTask =
+ new TestRunningTaskInfoBuilder()
+ .setWindowingMode(WINDOWING_MODE_FULLSCREEN)
+ .build();
fullscreenTask.isFocused = true;
mFreeformTaskListener.onFocusTaskChanged(fullscreenTask);
@@ -128,9 +186,9 @@
}
@Test
- public void testVisibilityTaskChanged_visible_setLaunchAdjacentDisabled() {
- ActivityManager.RunningTaskInfo task = new TestRunningTaskInfoBuilder()
- .setWindowingMode(WINDOWING_MODE_FREEFORM).build();
+ public void visibilityTaskChanged_visible_setLaunchAdjacentDisabled() {
+ ActivityManager.RunningTaskInfo task =
+ new TestRunningTaskInfoBuilder().setWindowingMode(WINDOWING_MODE_FREEFORM).build();
task.isVisible = true;
mFreeformTaskListener.onTaskAppeared(task, mMockSurfaceControl);
@@ -139,9 +197,9 @@
}
@Test
- public void testVisibilityTaskChanged_NotVisible_setLaunchAdjacentEnabled() {
- ActivityManager.RunningTaskInfo task = new TestRunningTaskInfoBuilder()
- .setWindowingMode(WINDOWING_MODE_FREEFORM).build();
+ public void visibilityTaskChanged_notVisible_setLaunchAdjacentEnabled() {
+ ActivityManager.RunningTaskInfo task =
+ new TestRunningTaskInfoBuilder().setWindowingMode(WINDOWING_MODE_FREEFORM).build();
task.isVisible = true;
mFreeformTaskListener.onTaskAppeared(task, mMockSurfaceControl);
@@ -154,9 +212,10 @@
@Test
@EnableFlags(FLAG_ENABLE_DESKTOP_WINDOWING_BACK_NAVIGATION)
- public void onTaskVanished_nonClosingTask_isMinimized() {
- ActivityManager.RunningTaskInfo task = new TestRunningTaskInfoBuilder()
- .setWindowingMode(WINDOWING_MODE_FREEFORM).build();
+ @DisableFlags(FLAG_ENABLE_WINDOWING_TRANSITION_HANDLERS_OBSERVERS)
+ public void onTaskVanished_nonClosingTask_noTransitionObservers_isMinimized() {
+ ActivityManager.RunningTaskInfo task =
+ new TestRunningTaskInfoBuilder().setWindowingMode(WINDOWING_MODE_FREEFORM).build();
task.isVisible = true;
mFreeformTaskListener.onTaskAppeared(task, mMockSurfaceControl);
@@ -169,10 +228,11 @@
}
@Test
+ @DisableFlags(FLAG_ENABLE_WINDOWING_TRANSITION_HANDLERS_OBSERVERS)
@EnableFlags(FLAG_ENABLE_DESKTOP_WINDOWING_BACK_NAVIGATION)
- public void onTaskVanished_closingTask_isNotMinimized() {
- ActivityManager.RunningTaskInfo task = new TestRunningTaskInfoBuilder()
- .setWindowingMode(WINDOWING_MODE_FREEFORM).build();
+ public void onTaskVanished_closingTask_noTransitionObservers_isNotMinimized() {
+ ActivityManager.RunningTaskInfo task =
+ new TestRunningTaskInfoBuilder().setWindowingMode(WINDOWING_MODE_FREEFORM).build();
task.isVisible = true;
mFreeformTaskListener.onTaskAppeared(task, mMockSurfaceControl);
@@ -188,9 +248,23 @@
}
@Test
+ @EnableFlags(FLAG_ENABLE_WINDOWING_TRANSITION_HANDLERS_OBSERVERS)
+ public void onTaskVanished_usesTransitionObservers_noopInRepo() {
+ ActivityManager.RunningTaskInfo task =
+ new TestRunningTaskInfoBuilder().setWindowingMode(WINDOWING_MODE_FREEFORM).build();
+ mFreeformTaskListener.onTaskAppeared(task, mMockSurfaceControl);
+
+ mFreeformTaskListener.onTaskVanished(task);
+
+ verify(mDesktopRepository, never()).minimizeTask(task.displayId, task.taskId);
+ verify(mDesktopRepository, never()).removeClosingTask(task.taskId);
+ verify(mDesktopRepository, never()).removeFreeformTask(task.displayId, task.taskId);
+ }
+
+ @Test
public void onTaskInfoChanged_withDesktopController_forwards() {
- ActivityManager.RunningTaskInfo task = new TestRunningTaskInfoBuilder()
- .setWindowingMode(WINDOWING_MODE_FREEFORM).build();
+ ActivityManager.RunningTaskInfo task =
+ new TestRunningTaskInfoBuilder().setWindowingMode(WINDOWING_MODE_FREEFORM).build();
task.isVisible = true;
mFreeformTaskListener.onTaskAppeared(task, mMockSurfaceControl);
@@ -199,6 +273,38 @@
verify(mDesktopTasksController).onTaskInfoChanged(task);
}
+ @Test
+ @DisableFlags(FLAG_ENABLE_WINDOWING_TRANSITION_HANDLERS_OBSERVERS)
+ public void onTaskInfoChanged_noTransitionObservers_updatesTaskVisibility() {
+ ActivityManager.RunningTaskInfo task =
+ new TestRunningTaskInfoBuilder().setWindowingMode(WINDOWING_MODE_FREEFORM).build();
+ task.isVisible = true;
+ mFreeformTaskListener.onTaskAppeared(task, mMockSurfaceControl);
+
+ mFreeformTaskListener.onTaskInfoChanged(task);
+
+ verify(mTaskChangeListener, never()).onTaskChanging(any());
+ verify(mDesktopRepository, times(2)).addActiveTask(task.displayId, task.taskId);
+ verify(mDesktopRepository, times(2))
+ .updateTaskVisibility(task.displayId, task.taskId, task.isVisible);
+ }
+
+ @Test
+ @EnableFlags(FLAG_ENABLE_WINDOWING_TRANSITION_HANDLERS_OBSERVERS)
+ @DisableFlags(FLAG_SHOW_DESKTOP_WINDOWING_DEV_OPTION)
+ public void onTaskInfoChanged_useTransitionObserver_noopInRepository() {
+ ActivityManager.RunningTaskInfo task =
+ new TestRunningTaskInfoBuilder().setWindowingMode(WINDOWING_MODE_FREEFORM).build();
+ task.isVisible = true;
+ mFreeformTaskListener.onTaskAppeared(task, mMockSurfaceControl);
+
+ mFreeformTaskListener.onTaskInfoChanged(task);
+
+ verify(mTaskChangeListener).onNonTransitionTaskChanging(any());
+ verify(mDesktopRepository, never())
+ .updateTaskVisibility(task.displayId, task.taskId, task.isVisible);
+ }
+
@After
public void tearDown() {
mMockitoSession.finishMocking();
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/freeform/FreeformTaskTransitionObserverTest.java b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/freeform/FreeformTaskTransitionObserverTest.java
index 90ab2b8..5aed461 100644
--- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/freeform/FreeformTaskTransitionObserverTest.java
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/freeform/FreeformTaskTransitionObserverTest.java
@@ -58,25 +58,17 @@
import java.util.Optional;
-/**
- * Tests for {@link FreeformTaskTransitionObserver}.
- */
+/** Tests for {@link FreeformTaskTransitionObserver}. */
@SmallTest
public class FreeformTaskTransitionObserverTest {
public final SetFlagsRule mSetFlagsRule = new SetFlagsRule();
- @Mock
- private ShellInit mShellInit;
- @Mock
- private Transitions mTransitions;
- @Mock
- private DesktopImmersiveController mDesktopImmersiveController;
- @Mock
- private WindowDecorViewModel mWindowDecorViewModel;
- @Mock
- private TaskChangeListener mTaskChangeListener;
- @Mock
- private FocusTransitionObserver mFocusTransitionObserver;
+ @Mock private ShellInit mShellInit;
+ @Mock private Transitions mTransitions;
+ @Mock private DesktopImmersiveController mDesktopImmersiveController;
+ @Mock private WindowDecorViewModel mWindowDecorViewModel;
+ @Mock private TaskChangeListener mTaskChangeListener;
+ @Mock private FocusTransitionObserver mFocusTransitionObserver;
private FreeformTaskTransitionObserver mTransitionObserver;
@@ -85,20 +77,22 @@
MockitoAnnotations.initMocks(this);
PackageManager pm = mock(PackageManager.class);
- doReturn(true).when(pm).hasSystemFeature(
- PackageManager.FEATURE_FREEFORM_WINDOW_MANAGEMENT);
+ doReturn(true).when(pm).hasSystemFeature(PackageManager.FEATURE_FREEFORM_WINDOW_MANAGEMENT);
final Context context = mock(Context.class);
doReturn(pm).when(context).getPackageManager();
- mTransitionObserver = new FreeformTaskTransitionObserver(
- context, mShellInit, mTransitions,
- Optional.of(mDesktopImmersiveController),
- mWindowDecorViewModel, Optional.of(mTaskChangeListener), mFocusTransitionObserver);
+ mTransitionObserver =
+ new FreeformTaskTransitionObserver(
+ context,
+ mShellInit,
+ mTransitions,
+ Optional.of(mDesktopImmersiveController),
+ mWindowDecorViewModel,
+ Optional.of(mTaskChangeListener),
+ mFocusTransitionObserver);
- final ArgumentCaptor<Runnable> initRunnableCaptor = ArgumentCaptor.forClass(
- Runnable.class);
- verify(mShellInit).addInitCallback(initRunnableCaptor.capture(),
- same(mTransitionObserver));
+ final ArgumentCaptor<Runnable> initRunnableCaptor = ArgumentCaptor.forClass(Runnable.class);
+ verify(mShellInit).addInitCallback(initRunnableCaptor.capture(), same(mTransitionObserver));
initRunnableCaptor.getValue().run();
}
@@ -109,10 +103,9 @@
@Test
public void openTransition_createsWindowDecor() {
- final TransitionInfo.Change change =
- createChange(TRANSIT_OPEN, 1, WINDOWING_MODE_FREEFORM);
- final TransitionInfo info = new TransitionInfoBuilder(TRANSIT_OPEN, 0)
- .addChange(change).build();
+ final TransitionInfo.Change change = createChange(TRANSIT_OPEN, 1, WINDOWING_MODE_FREEFORM);
+ final TransitionInfo info =
+ new TransitionInfoBuilder(TRANSIT_OPEN, 0).addChange(change).build();
final IBinder transition = mock(IBinder.class);
final SurfaceControl.Transaction startT = mock(SurfaceControl.Transaction.class);
@@ -120,16 +113,15 @@
mTransitionObserver.onTransitionReady(transition, info, startT, finishT);
mTransitionObserver.onTransitionStarting(transition);
- verify(mWindowDecorViewModel).onTaskOpening(
- change.getTaskInfo(), change.getLeash(), startT, finishT);
+ verify(mWindowDecorViewModel)
+ .onTaskOpening(change.getTaskInfo(), change.getLeash(), startT, finishT);
}
@Test
public void openTransition_notifiesOnTaskOpening() {
- final TransitionInfo.Change change =
- createChange(TRANSIT_OPEN, 1, WINDOWING_MODE_FREEFORM);
- final TransitionInfo info = new TransitionInfoBuilder(TRANSIT_OPEN, 0)
- .addChange(change).build();
+ final TransitionInfo.Change change = createChange(TRANSIT_OPEN, 1, WINDOWING_MODE_FREEFORM);
+ final TransitionInfo info =
+ new TransitionInfoBuilder(TRANSIT_OPEN, 0).addChange(change).build();
final IBinder transition = mock(IBinder.class);
final SurfaceControl.Transaction startT = mock(SurfaceControl.Transaction.class);
@@ -144,8 +136,10 @@
public void toFrontTransition_notifiesOnTaskMovingToFront() {
final TransitionInfo.Change change =
createChange(TRANSIT_TO_FRONT, /* taskId= */ 1, WINDOWING_MODE_FREEFORM);
- final TransitionInfo info = new TransitionInfoBuilder(TRANSIT_TO_FRONT, /* flags= */ 0)
- .addChange(change).build();
+ final TransitionInfo info =
+ new TransitionInfoBuilder(TRANSIT_TO_FRONT, /* flags= */ 0)
+ .addChange(change)
+ .build();
final IBinder transition = mock(IBinder.class);
final SurfaceControl.Transaction startT = mock(SurfaceControl.Transaction.class);
@@ -160,8 +154,10 @@
public void toBackTransition_notifiesOnTaskMovingToBack() {
final TransitionInfo.Change change =
createChange(TRANSIT_TO_BACK, /* taskId= */ 1, WINDOWING_MODE_FREEFORM);
- final TransitionInfo info = new TransitionInfoBuilder(TRANSIT_TO_BACK, /* flags= */ 0)
- .addChange(change).build();
+ final TransitionInfo info =
+ new TransitionInfoBuilder(TRANSIT_TO_BACK, /* flags= */ 0)
+ .addChange(change)
+ .build();
final IBinder transition = mock(IBinder.class);
final SurfaceControl.Transaction startT = mock(SurfaceControl.Transaction.class);
@@ -173,11 +169,11 @@
}
@Test
- public void changeTransition_notifiesOnTaskChanging() {
+ public void changeTransition_notifiesOnTaskChange() {
final TransitionInfo.Change change =
createChange(TRANSIT_CHANGE, /* taskId= */ 1, WINDOWING_MODE_FREEFORM);
- final TransitionInfo info = new TransitionInfoBuilder(TRANSIT_CHANGE, /* flags= */ 0)
- .addChange(change).build();
+ final TransitionInfo info =
+ new TransitionInfoBuilder(TRANSIT_CHANGE, /* flags= */ 0).addChange(change).build();
final IBinder transition = mock(IBinder.class);
final SurfaceControl.Transaction startT = mock(SurfaceControl.Transaction.class);
@@ -192,8 +188,8 @@
public void closeTransition_preparesWindowDecor() {
final TransitionInfo.Change change =
createChange(TRANSIT_CLOSE, 1, WINDOWING_MODE_FREEFORM);
- final TransitionInfo info = new TransitionInfoBuilder(TRANSIT_CLOSE, 0)
- .addChange(change).build();
+ final TransitionInfo info =
+ new TransitionInfoBuilder(TRANSIT_CLOSE, 0).addChange(change).build();
final IBinder transition = mock(IBinder.class);
final SurfaceControl.Transaction startT = mock(SurfaceControl.Transaction.class);
@@ -201,16 +197,15 @@
mTransitionObserver.onTransitionReady(transition, info, startT, finishT);
mTransitionObserver.onTransitionStarting(transition);
- verify(mWindowDecorViewModel).onTaskClosing(
- change.getTaskInfo(), startT, finishT);
+ verify(mWindowDecorViewModel).onTaskClosing(change.getTaskInfo(), startT, finishT);
}
@Test
public void closeTransition_notifiesOnTaskClosing() {
final TransitionInfo.Change change =
createChange(TRANSIT_CLOSE, 1, WINDOWING_MODE_FREEFORM);
- final TransitionInfo info = new TransitionInfoBuilder(TRANSIT_CLOSE, 0)
- .addChange(change).build();
+ final TransitionInfo info =
+ new TransitionInfoBuilder(TRANSIT_CLOSE, 0).addChange(change).build();
final IBinder transition = mock(IBinder.class);
final SurfaceControl.Transaction startT = mock(SurfaceControl.Transaction.class);
@@ -225,8 +220,8 @@
public void closeTransition_doesntCloseWindowDecorDuringTransition() throws Exception {
final TransitionInfo.Change change =
createChange(TRANSIT_CLOSE, 1, WINDOWING_MODE_FREEFORM);
- final TransitionInfo info = new TransitionInfoBuilder(TRANSIT_CLOSE, 0)
- .addChange(change).build();
+ final TransitionInfo info =
+ new TransitionInfoBuilder(TRANSIT_CLOSE, 0).addChange(change).build();
final IBinder transition = mock(IBinder.class);
final SurfaceControl.Transaction startT = mock(SurfaceControl.Transaction.class);
@@ -241,8 +236,8 @@
public void closeTransition_closesWindowDecorAfterTransition() throws Exception {
final TransitionInfo.Change change =
createChange(TRANSIT_CLOSE, 1, WINDOWING_MODE_FREEFORM);
- final TransitionInfo info = new TransitionInfoBuilder(TRANSIT_CLOSE, 0)
- .addChange(change).build();
+ final TransitionInfo info =
+ new TransitionInfoBuilder(TRANSIT_CLOSE, 0).addChange(change).build();
final AutoCloseable windowDecor = mock(AutoCloseable.class);
@@ -261,8 +256,8 @@
// The playing transition
final TransitionInfo.Change change1 =
createChange(TRANSIT_OPEN, 1, WINDOWING_MODE_FREEFORM);
- final TransitionInfo info1 = new TransitionInfoBuilder(TRANSIT_OPEN, 0)
- .addChange(change1).build();
+ final TransitionInfo info1 =
+ new TransitionInfoBuilder(TRANSIT_OPEN, 0).addChange(change1).build();
final IBinder transition1 = mock(IBinder.class);
final SurfaceControl.Transaction startT1 = mock(SurfaceControl.Transaction.class);
@@ -273,8 +268,8 @@
// The merged transition
final TransitionInfo.Change change2 =
createChange(TRANSIT_CLOSE, 2, WINDOWING_MODE_FREEFORM);
- final TransitionInfo info2 = new TransitionInfoBuilder(TRANSIT_CLOSE, 0)
- .addChange(change2).build();
+ final TransitionInfo info2 =
+ new TransitionInfoBuilder(TRANSIT_CLOSE, 0).addChange(change2).build();
final IBinder transition2 = mock(IBinder.class);
final SurfaceControl.Transaction startT2 = mock(SurfaceControl.Transaction.class);
@@ -292,8 +287,8 @@
// The playing transition
final TransitionInfo.Change change1 =
createChange(TRANSIT_CLOSE, 1, WINDOWING_MODE_FREEFORM);
- final TransitionInfo info1 = new TransitionInfoBuilder(TRANSIT_CLOSE, 0)
- .addChange(change1).build();
+ final TransitionInfo info1 =
+ new TransitionInfoBuilder(TRANSIT_CLOSE, 0).addChange(change1).build();
final IBinder transition1 = mock(IBinder.class);
final SurfaceControl.Transaction startT1 = mock(SurfaceControl.Transaction.class);
@@ -304,8 +299,8 @@
// The merged transition
final TransitionInfo.Change change2 =
createChange(TRANSIT_CLOSE, 2, WINDOWING_MODE_FREEFORM);
- final TransitionInfo info2 = new TransitionInfoBuilder(TRANSIT_CLOSE, 0)
- .addChange(change2).build();
+ final TransitionInfo info2 =
+ new TransitionInfoBuilder(TRANSIT_CLOSE, 0).addChange(change2).build();
final IBinder transition2 = mock(IBinder.class);
final SurfaceControl.Transaction startT2 = mock(SurfaceControl.Transaction.class);
@@ -368,9 +363,10 @@
taskInfo.taskId = taskId;
taskInfo.configuration.windowConfiguration.setWindowingMode(windowingMode);
- final TransitionInfo.Change change = new TransitionInfo.Change(
- new WindowContainerToken(mock(IWindowContainerToken.class)),
- mock(SurfaceControl.class));
+ final TransitionInfo.Change change =
+ new TransitionInfo.Change(
+ new WindowContainerToken(mock(IWindowContainerToken.class)),
+ mock(SurfaceControl.class));
change.setMode(mode);
change.setTaskInfo(taskInfo);
return change;
diff --git a/packages/CrashRecovery/framework/Android.bp b/packages/CrashRecovery/framework/Android.bp
index 1be776d..2beffda 100644
--- a/packages/CrashRecovery/framework/Android.bp
+++ b/packages/CrashRecovery/framework/Android.bp
@@ -6,7 +6,25 @@
],
path: "java",
visibility: [
- "//frameworks/base:__subpackages__",
"//packages/modules/CrashRecovery/framework",
],
}
+
+java_sdk_library {
+ name: "framework-platformcrashrecovery",
+ srcs: [":framework-crashrecovery-sources"],
+ defaults: ["framework-non-updatable-unbundled-defaults"],
+ aidl: {
+ include_dirs: [
+ "frameworks/base/core/java",
+ ],
+ },
+ impl_library_visibility: [
+ "//frameworks/base:__subpackages__",
+ ],
+}
+
+platform_compat_config {
+ name: "framework-platformcrashrecovery-compat-config",
+ src: ":framework-platformcrashrecovery",
+}
diff --git a/packages/CrashRecovery/framework/api/current.txt b/packages/CrashRecovery/framework/api/current.txt
new file mode 100644
index 0000000..d802177
--- /dev/null
+++ b/packages/CrashRecovery/framework/api/current.txt
@@ -0,0 +1 @@
+// Signature format: 2.0
diff --git a/packages/CrashRecovery/framework/api/module-lib-current.txt b/packages/CrashRecovery/framework/api/module-lib-current.txt
new file mode 100644
index 0000000..d802177
--- /dev/null
+++ b/packages/CrashRecovery/framework/api/module-lib-current.txt
@@ -0,0 +1 @@
+// Signature format: 2.0
diff --git a/packages/CrashRecovery/framework/api/module-lib-removed.txt b/packages/CrashRecovery/framework/api/module-lib-removed.txt
new file mode 100644
index 0000000..d802177
--- /dev/null
+++ b/packages/CrashRecovery/framework/api/module-lib-removed.txt
@@ -0,0 +1 @@
+// Signature format: 2.0
diff --git a/packages/CrashRecovery/framework/api/removed.txt b/packages/CrashRecovery/framework/api/removed.txt
new file mode 100644
index 0000000..d802177
--- /dev/null
+++ b/packages/CrashRecovery/framework/api/removed.txt
@@ -0,0 +1 @@
+// Signature format: 2.0
diff --git a/packages/CrashRecovery/framework/api/system-current.txt b/packages/CrashRecovery/framework/api/system-current.txt
new file mode 100644
index 0000000..3a48a4a
--- /dev/null
+++ b/packages/CrashRecovery/framework/api/system-current.txt
@@ -0,0 +1,26 @@
+// Signature format: 2.0
+package android.service.watchdog {
+
+ public abstract class ExplicitHealthCheckService extends android.app.Service {
+ ctor public ExplicitHealthCheckService();
+ method public final void notifyHealthCheckPassed(@NonNull String);
+ method @NonNull public final android.os.IBinder onBind(@NonNull android.content.Intent);
+ method public abstract void onCancelHealthCheck(@NonNull String);
+ method @NonNull public abstract java.util.List<java.lang.String> onGetRequestedPackages();
+ method @NonNull public abstract java.util.List<android.service.watchdog.ExplicitHealthCheckService.PackageConfig> onGetSupportedPackages();
+ method public abstract void onRequestHealthCheck(@NonNull String);
+ field public static final String BIND_PERMISSION = "android.permission.BIND_EXPLICIT_HEALTH_CHECK_SERVICE";
+ field public static final String SERVICE_INTERFACE = "android.service.watchdog.ExplicitHealthCheckService";
+ }
+
+ public static final class ExplicitHealthCheckService.PackageConfig implements android.os.Parcelable {
+ ctor public ExplicitHealthCheckService.PackageConfig(@NonNull String, long);
+ method public int describeContents();
+ method public long getHealthCheckTimeoutMillis();
+ method @NonNull public String getPackageName();
+ method public void writeToParcel(android.os.Parcel, int);
+ field @NonNull public static final android.os.Parcelable.Creator<android.service.watchdog.ExplicitHealthCheckService.PackageConfig> CREATOR;
+ }
+
+}
+
diff --git a/packages/CrashRecovery/framework/api/system-lint-baseline.txt b/packages/CrashRecovery/framework/api/system-lint-baseline.txt
new file mode 100644
index 0000000..f52be7c
--- /dev/null
+++ b/packages/CrashRecovery/framework/api/system-lint-baseline.txt
@@ -0,0 +1,47 @@
+// Baseline format: 1.0
+InvalidNullabilityOverride: android.service.watchdog.ExplicitHealthCheckService#onBind(android.content.Intent):
+ Invalid nullability on type android.content.Intent in parameter `intent` in method `onBind`. Parameter in method override cannot use a non-null type when the corresponding type from the super method is platform-nullness.
+InvalidNullabilityOverride: android.service.watchdog.ExplicitHealthCheckService#onBind(android.content.Intent) parameter #0:
+ Invalid nullability on type android.content.Intent in parameter `intent` in method `onBind`. Parameter in method override cannot use a non-null type when the corresponding type from the super method is platform-nullness.
+
+
+MissingNullability: android.service.watchdog.ExplicitHealthCheckService.PackageConfig#writeToParcel(android.os.Parcel,int):
+ Missing nullability on parameter `parcel` in method `writeToParcel`
+
+
+UnflaggedApi: android.service.watchdog.ExplicitHealthCheckService:
+ New API must be flagged with @FlaggedApi: class android.service.watchdog.ExplicitHealthCheckService
+UnflaggedApi: android.service.watchdog.ExplicitHealthCheckService#BIND_PERMISSION:
+ New API must be flagged with @FlaggedApi: field android.service.watchdog.ExplicitHealthCheckService.BIND_PERMISSION
+UnflaggedApi: android.service.watchdog.ExplicitHealthCheckService#SERVICE_INTERFACE:
+ New API must be flagged with @FlaggedApi: field android.service.watchdog.ExplicitHealthCheckService.SERVICE_INTERFACE
+UnflaggedApi: android.service.watchdog.ExplicitHealthCheckService#notifyHealthCheckPassed(String):
+ New API must be flagged with @FlaggedApi: method android.service.watchdog.ExplicitHealthCheckService.notifyHealthCheckPassed(String)
+UnflaggedApi: android.service.watchdog.ExplicitHealthCheckService#onBind(android.content.Intent):
+ New API must be flagged with @FlaggedApi: method android.service.watchdog.ExplicitHealthCheckService.onBind(android.content.Intent)
+UnflaggedApi: android.service.watchdog.ExplicitHealthCheckService#onCancelHealthCheck(String):
+ New API must be flagged with @FlaggedApi: method android.service.watchdog.ExplicitHealthCheckService.onCancelHealthCheck(String)
+UnflaggedApi: android.service.watchdog.ExplicitHealthCheckService#onGetRequestedPackages():
+ New API must be flagged with @FlaggedApi: method android.service.watchdog.ExplicitHealthCheckService.onGetRequestedPackages()
+UnflaggedApi: android.service.watchdog.ExplicitHealthCheckService#onGetSupportedPackages():
+ New API must be flagged with @FlaggedApi: method android.service.watchdog.ExplicitHealthCheckService.onGetSupportedPackages()
+UnflaggedApi: android.service.watchdog.ExplicitHealthCheckService#onRequestHealthCheck(String):
+ New API must be flagged with @FlaggedApi: method android.service.watchdog.ExplicitHealthCheckService.onRequestHealthCheck(String)
+UnflaggedApi: android.service.watchdog.ExplicitHealthCheckService.PackageConfig:
+ New API must be flagged with @FlaggedApi: class android.service.watchdog.ExplicitHealthCheckService.PackageConfig
+UnflaggedApi: android.service.watchdog.ExplicitHealthCheckService.PackageConfig#CREATOR:
+ New API must be flagged with @FlaggedApi: field android.service.watchdog.ExplicitHealthCheckService.PackageConfig.CREATOR
+UnflaggedApi: android.service.watchdog.ExplicitHealthCheckService.PackageConfig#PackageConfig(String, long):
+ New API must be flagged with @FlaggedApi: constructor android.service.watchdog.ExplicitHealthCheckService.PackageConfig(String,long)
+UnflaggedApi: android.service.watchdog.ExplicitHealthCheckService.PackageConfig#PackageConfig(String,long):
+ New API must be flagged with @FlaggedApi: constructor android.service.watchdog.ExplicitHealthCheckService.PackageConfig(String,long)
+UnflaggedApi: android.service.watchdog.ExplicitHealthCheckService.PackageConfig#describeContents():
+ New API must be flagged with @FlaggedApi: method android.service.watchdog.ExplicitHealthCheckService.PackageConfig.describeContents()
+UnflaggedApi: android.service.watchdog.ExplicitHealthCheckService.PackageConfig#getHealthCheckTimeoutMillis():
+ New API must be flagged with @FlaggedApi: method android.service.watchdog.ExplicitHealthCheckService.PackageConfig.getHealthCheckTimeoutMillis()
+UnflaggedApi: android.service.watchdog.ExplicitHealthCheckService.PackageConfig#getPackageName():
+ New API must be flagged with @FlaggedApi: method android.service.watchdog.ExplicitHealthCheckService.PackageConfig.getPackageName()
+UnflaggedApi: android.service.watchdog.ExplicitHealthCheckService.PackageConfig#writeToParcel(android.os.Parcel, int):
+ New API must be flagged with @FlaggedApi: method android.service.watchdog.ExplicitHealthCheckService.PackageConfig.writeToParcel(android.os.Parcel,int)
+UnflaggedApi: android.service.watchdog.ExplicitHealthCheckService.PackageConfig#writeToParcel(android.os.Parcel,int):
+ New API must be flagged with @FlaggedApi: method android.service.watchdog.ExplicitHealthCheckService.PackageConfig.writeToParcel(android.os.Parcel,int)
\ No newline at end of file
diff --git a/packages/CrashRecovery/framework/api/system-removed.txt b/packages/CrashRecovery/framework/api/system-removed.txt
new file mode 100644
index 0000000..d802177
--- /dev/null
+++ b/packages/CrashRecovery/framework/api/system-removed.txt
@@ -0,0 +1 @@
+// Signature format: 2.0
diff --git a/packages/CrashRecovery/framework/api/test-current.txt b/packages/CrashRecovery/framework/api/test-current.txt
new file mode 100644
index 0000000..54f501f
--- /dev/null
+++ b/packages/CrashRecovery/framework/api/test-current.txt
@@ -0,0 +1,9 @@
+// Signature format: 2.0
+package android.service.watchdog {
+
+ public abstract class ExplicitHealthCheckService extends android.app.Service {
+ method public void setCallback(@Nullable android.os.RemoteCallback);
+ }
+
+}
+
diff --git a/packages/CrashRecovery/framework/api/test-removed.txt b/packages/CrashRecovery/framework/api/test-removed.txt
new file mode 100644
index 0000000..d802177
--- /dev/null
+++ b/packages/CrashRecovery/framework/api/test-removed.txt
@@ -0,0 +1 @@
+// Signature format: 2.0
diff --git a/packages/CrashRecovery/services/module/java/com/android/server/PackageWatchdog.java b/packages/CrashRecovery/services/module/java/com/android/server/PackageWatchdog.java
index 8e5ae20..fbf51fd 100644
--- a/packages/CrashRecovery/services/module/java/com/android/server/PackageWatchdog.java
+++ b/packages/CrashRecovery/services/module/java/com/android/server/PackageWatchdog.java
@@ -19,6 +19,7 @@
import static android.content.Intent.ACTION_REBOOT;
import static android.content.Intent.ACTION_SHUTDOWN;
import static android.service.watchdog.ExplicitHealthCheckService.PackageConfig;
+import static android.util.Xml.Encoding.UTF_8;
import static com.android.server.crashrecovery.CrashRecoveryUtils.dumpCrashRecoveryEvents;
@@ -58,13 +59,14 @@
import com.android.internal.annotations.GuardedBy;
import com.android.internal.annotations.VisibleForTesting;
+import com.android.internal.util.FastXmlSerializer;
import com.android.modules.utils.BackgroundThread;
-import com.android.modules.utils.TypedXmlPullParser;
-import com.android.modules.utils.TypedXmlSerializer;
import libcore.io.IoUtils;
+import org.xmlpull.v1.XmlPullParser;
import org.xmlpull.v1.XmlPullParserException;
+import org.xmlpull.v1.XmlSerializer;
import java.io.BufferedReader;
import java.io.BufferedWriter;
@@ -1152,7 +1154,8 @@
mAllObservers.clear();
try {
infile = mPolicyFile.openRead();
- final TypedXmlPullParser parser = Xml.resolvePullParser(infile);
+ final XmlPullParser parser = Xml.newPullParser();
+ parser.setInput(infile, UTF_8.name());
XmlUtils.beginDocument(parser, TAG_PACKAGE_WATCHDOG);
int outerDepth = parser.getDepth();
while (XmlUtils.nextElementWithin(parser, outerDepth)) {
@@ -1163,7 +1166,7 @@
}
} catch (FileNotFoundException e) {
// Nothing to monitor
- } catch (IOException | NumberFormatException | XmlPullParserException e) {
+ } catch (Exception e) {
Slog.wtf(TAG, "Unable to read monitored packages, deleting file", e);
mPolicyFile.delete();
} finally {
@@ -1237,10 +1240,11 @@
}
try {
- TypedXmlSerializer out = Xml.resolveSerializer(stream);
+ XmlSerializer out = new FastXmlSerializer();
+ out.setOutput(stream, UTF_8.name());
out.startDocument(null, true);
out.startTag(null, TAG_PACKAGE_WATCHDOG);
- out.attributeInt(null, ATTR_VERSION, DB_VERSION);
+ out.attribute(null, ATTR_VERSION, Integer.toString(DB_VERSION));
for (int oIndex = 0; oIndex < mAllObservers.size(); oIndex++) {
mAllObservers.valueAt(oIndex).writeLocked(out);
}
@@ -1356,12 +1360,12 @@
* Does not persist any package failure thresholds.
*/
@GuardedBy("mLock")
- public boolean writeLocked(TypedXmlSerializer out) {
+ public boolean writeLocked(XmlSerializer out) {
try {
out.startTag(null, TAG_OBSERVER);
out.attribute(null, ATTR_NAME, name);
if (Flags.recoverabilityDetection()) {
- out.attributeInt(null, ATTR_MITIGATION_COUNT, mMitigationCount);
+ out.attribute(null, ATTR_MITIGATION_COUNT, Integer.toString(mMitigationCount));
}
for (int i = 0; i < mPackages.size(); i++) {
MonitoredPackage p = mPackages.valueAt(i);
@@ -1486,7 +1490,7 @@
* #loadFromFile which in turn is only called on construction of the
* singleton PackageWatchdog.
**/
- public static ObserverInternal read(TypedXmlPullParser parser, PackageWatchdog watchdog) {
+ public static ObserverInternal read(XmlPullParser parser, PackageWatchdog watchdog) {
String observerName = null;
int observerMitigationCount = 0;
if (TAG_OBSERVER.equals(parser.getName())) {
@@ -1501,9 +1505,9 @@
try {
if (Flags.recoverabilityDetection()) {
try {
- observerMitigationCount =
- parser.getAttributeInt(null, ATTR_MITIGATION_COUNT);
- } catch (XmlPullParserException e) {
+ observerMitigationCount = Integer.parseInt(
+ parser.getAttributeValue(null, ATTR_MITIGATION_COUNT));
+ } catch (Exception e) {
Slog.i(
TAG,
"ObserverInternal mitigation count was not present.");
@@ -1579,13 +1583,14 @@
hasPassedHealthCheck, mitigationCalls);
}
- MonitoredPackage parseMonitoredPackage(TypedXmlPullParser parser)
+ MonitoredPackage parseMonitoredPackage(XmlPullParser parser)
throws XmlPullParserException {
String packageName = parser.getAttributeValue(null, ATTR_NAME);
- long duration = parser.getAttributeLong(null, ATTR_DURATION);
- long healthCheckDuration = parser.getAttributeLong(null,
- ATTR_EXPLICIT_HEALTH_CHECK_DURATION);
- boolean hasPassedHealthCheck = parser.getAttributeBoolean(null, ATTR_PASSED_HEALTH_CHECK);
+ long duration = Long.parseLong(parser.getAttributeValue(null, ATTR_DURATION));
+ long healthCheckDuration = Long.parseLong(parser.getAttributeValue(null,
+ ATTR_EXPLICIT_HEALTH_CHECK_DURATION));
+ boolean hasPassedHealthCheck = Boolean.parseBoolean(parser.getAttributeValue(null,
+ ATTR_PASSED_HEALTH_CHECK));
LongArrayQueue mitigationCalls = parseLongArrayQueue(
parser.getAttributeValue(null, ATTR_MITIGATION_CALLS));
return newMonitoredPackage(packageName,
@@ -1643,12 +1648,13 @@
* @hide
*/
@GuardedBy("mLock")
- public void writeLocked(TypedXmlSerializer out) throws IOException {
+ public void writeLocked(XmlSerializer out) throws IOException {
out.startTag(null, TAG_PACKAGE);
out.attribute(null, ATTR_NAME, getName());
- out.attributeLong(null, ATTR_DURATION, mDurationMs);
- out.attributeLong(null, ATTR_EXPLICIT_HEALTH_CHECK_DURATION, mHealthCheckDurationMs);
- out.attributeBoolean(null, ATTR_PASSED_HEALTH_CHECK, mHasPassedHealthCheck);
+ out.attribute(null, ATTR_DURATION, Long.toString(mDurationMs));
+ out.attribute(null, ATTR_EXPLICIT_HEALTH_CHECK_DURATION,
+ Long.toString(mHealthCheckDurationMs));
+ out.attribute(null, ATTR_PASSED_HEALTH_CHECK, Boolean.toString(mHasPassedHealthCheck));
LongArrayQueue normalizedCalls = normalizeMitigationCalls();
out.attribute(null, ATTR_MITIGATION_CALLS, longArrayQueueToString(normalizedCalls));
out.endTag(null, TAG_PACKAGE);
diff --git a/packages/SettingsLib/DataStore/src/com/android/settingslib/datastore/HandlerExecutor.kt b/packages/SettingsLib/DataStore/src/com/android/settingslib/datastore/HandlerExecutor.kt
new file mode 100644
index 0000000..be08606
--- /dev/null
+++ b/packages/SettingsLib/DataStore/src/com/android/settingslib/datastore/HandlerExecutor.kt
@@ -0,0 +1,45 @@
+/*
+ * 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.settingslib.datastore
+
+import android.os.Handler
+import android.os.Looper
+import java.util.concurrent.Executor
+
+/**
+ * Adapter of [Handler] and [Executor], where the task is executed on handler with given looper.
+ *
+ * When current looper is same with the given looper, task passed to [Executor.execute] will be
+ * executed immediately to improve better performance.
+ *
+ * @param looper Looper of the handler.
+ */
+open class HandlerExecutor(looper: Looper) : Handler(looper), Executor {
+
+ override fun execute(command: Runnable) {
+ if (looper == Looper.myLooper()) {
+ command.run()
+ } else {
+ post(command)
+ }
+ }
+
+ companion object {
+ /** The main thread [HandlerExecutor]. */
+ val main = HandlerExecutor(Looper.getMainLooper())
+ }
+}
diff --git a/packages/SettingsLib/DataStore/src/com/android/settingslib/datastore/SettingsStore.kt b/packages/SettingsLib/DataStore/src/com/android/settingslib/datastore/SettingsStore.kt
index 62d3fc3..04d4bfe 100644
--- a/packages/SettingsLib/DataStore/src/com/android/settingslib/datastore/SettingsStore.kt
+++ b/packages/SettingsLib/DataStore/src/com/android/settingslib/datastore/SettingsStore.kt
@@ -19,8 +19,6 @@
import android.content.ContentResolver
import android.database.ContentObserver
import android.net.Uri
-import android.os.Handler
-import android.os.Looper
import android.util.Log
import java.util.concurrent.Executor
import java.util.concurrent.atomic.AtomicInteger
@@ -39,7 +37,7 @@
private val counter = AtomicInteger()
private val contentObserver =
- object : ContentObserver(Handler(Looper.getMainLooper())) {
+ object : ContentObserver(HandlerExecutor.main) {
override fun onChange(selfChange: Boolean) {
super.onChange(selfChange, null)
}
diff --git a/packages/SettingsLib/Preference/src/com/android/settingslib/preference/PreferenceScreenBindingHelper.kt b/packages/SettingsLib/Preference/src/com/android/settingslib/preference/PreferenceScreenBindingHelper.kt
index d99d470..ad4cc33 100644
--- a/packages/SettingsLib/Preference/src/com/android/settingslib/preference/PreferenceScreenBindingHelper.kt
+++ b/packages/SettingsLib/Preference/src/com/android/settingslib/preference/PreferenceScreenBindingHelper.kt
@@ -19,12 +19,11 @@
import android.content.Context
import android.content.Intent
import android.os.Bundle
-import android.os.Handler
-import android.os.Looper
import androidx.preference.Preference
import androidx.preference.PreferenceDataStore
import androidx.preference.PreferenceGroup
import androidx.preference.PreferenceScreen
+import com.android.settingslib.datastore.HandlerExecutor
import com.android.settingslib.datastore.KeyValueStore
import com.android.settingslib.datastore.KeyedDataObservable
import com.android.settingslib.datastore.KeyedObservable
@@ -37,7 +36,6 @@
import com.android.settingslib.metadata.PreferenceScreenRegistry
import com.google.common.collect.ImmutableMap
import com.google.common.collect.ImmutableMultimap
-import java.util.concurrent.Executor
/**
* Helper to bind preferences on given [preferenceScreen].
@@ -54,13 +52,7 @@
private val preferenceHierarchy: PreferenceHierarchy,
) : KeyedDataObservable<String>() {
- private val handler = Handler(Looper.getMainLooper())
- private val executor =
- object : Executor {
- override fun execute(command: Runnable) {
- handler.post(command)
- }
- }
+ private val mainExecutor = HandlerExecutor.main
private val preferenceLifecycleContext =
object : PreferenceLifecycleContext(context) {
@@ -121,8 +113,8 @@
this.lifecycleAwarePreferences = lifecycleAwarePreferences.toTypedArray()
preferenceObserver = KeyedObserver { key, reason -> onPreferenceChange(key, reason) }
- addObserver(preferenceObserver, executor)
- for (storage in storages) storage.addObserver(storageObserver, executor)
+ addObserver(preferenceObserver, mainExecutor)
+ for (storage in storages) storage.addObserver(storageObserver, mainExecutor)
}
private fun onPreferenceChange(key: String?, reason: Int) {
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/haptics/slider/SeekbarHapticPluginTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/haptics/slider/HapticSliderPluginTest.kt
similarity index 92%
rename from packages/SystemUI/multivalentTests/src/com/android/systemui/haptics/slider/SeekbarHapticPluginTest.kt
rename to packages/SystemUI/multivalentTests/src/com/android/systemui/haptics/slider/HapticSliderPluginTest.kt
index 587d3d9..0881010 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/haptics/slider/SeekbarHapticPluginTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/haptics/slider/HapticSliderPluginTest.kt
@@ -45,14 +45,14 @@
@SmallTest
@RunWith(AndroidJUnit4::class)
@OptIn(ExperimentalCoroutinesApi::class)
-class SeekbarHapticPluginTest : SysuiTestCase() {
+class HapticSliderPluginTest : SysuiTestCase() {
private val kosmos = Kosmos()
@Rule @JvmField val mMockitoRule: MockitoRule = MockitoJUnit.rule()
@Mock private lateinit var vibratorHelper: VibratorHelper
private val seekBar = SeekBar(mContext)
- private lateinit var plugin: SeekbarHapticPlugin
+ private lateinit var plugin: HapticSliderPlugin
@Before
fun setup() {
@@ -95,7 +95,7 @@
// GIVEN an onKeyDown that starts the wait and a program progress change that advances the
// slider state to ARROW_HANDLE_MOVED_ONCE
plugin.onKeyDown()
- plugin.onProgressChanged(seekBar, 50, false)
+ plugin.onProgressChanged(50, false)
testScheduler.runCurrent()
assertThat(plugin.trackerState).isEqualTo(SliderState.ARROW_HANDLE_MOVED_ONCE)
@@ -112,7 +112,7 @@
// GIVEN an onKeyDown that starts the wait and a program progress change that advances the
// slider state to ARROW_HANDLE_MOVED_ONCE
plugin.onKeyDown()
- plugin.onProgressChanged(seekBar, 50, false)
+ plugin.onProgressChanged(50, false)
testScheduler.runCurrent()
assertThat(plugin.trackerState).isEqualTo(SliderState.ARROW_HANDLE_MOVED_ONCE)
@@ -142,7 +142,13 @@
}
private fun createPlugin() {
- plugin = SeekbarHapticPlugin(vibratorHelper, kosmos.msdlPlayer, kosmos.fakeSystemClock)
+ plugin =
+ HapticSliderPlugin(
+ vibratorHelper,
+ kosmos.msdlPlayer,
+ kosmos.fakeSystemClock,
+ HapticSlider.SeekBar(seekBar),
+ )
}
companion object {
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/settings/brightness/BrightnessSliderControllerTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/settings/brightness/BrightnessSliderControllerTest.kt
index 080f46f..119abd1 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/settings/brightness/BrightnessSliderControllerTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/settings/brightness/BrightnessSliderControllerTest.kt
@@ -24,7 +24,8 @@
import com.android.settingslib.RestrictedLockUtils
import com.android.systemui.SysuiTestCase
import com.android.systemui.classifier.FalsingManagerFake
-import com.android.systemui.haptics.slider.SeekbarHapticPlugin
+import com.android.systemui.haptics.slider.HapticSlider
+import com.android.systemui.haptics.slider.HapticSliderPlugin
import com.android.systemui.plugins.ActivityStarter
import com.android.systemui.statusbar.VibratorHelper
import com.android.systemui.statusbar.policy.BrightnessMirrorController
@@ -86,7 +87,12 @@
brightnessSliderView,
mFalsingManager,
uiEventLogger,
- SeekbarHapticPlugin(vibratorHelper, msdlPlayer, systemClock),
+ HapticSliderPlugin(
+ vibratorHelper,
+ msdlPlayer,
+ systemClock,
+ HapticSlider.SeekBar(seekBar),
+ ),
activityStarter,
)
mController.init()
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/footer/ui/viewmodel/FooterViewModelTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/footer/ui/viewmodel/FooterViewModelTest.kt
index 46f3a6b..1adfc2b 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/footer/ui/viewmodel/FooterViewModelTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/footer/ui/viewmodel/FooterViewModelTest.kt
@@ -18,6 +18,7 @@
package com.android.systemui.statusbar.notification.footer.ui.viewmodel
+import android.platform.test.annotations.DisableFlags
import android.platform.test.annotations.EnableFlags
import android.platform.test.flag.junit.FlagsParameterization
import android.provider.Settings
@@ -40,6 +41,7 @@
import com.android.systemui.statusbar.notification.data.repository.activeNotificationListRepository
import com.android.systemui.statusbar.notification.emptyshade.shared.ModesEmptyShadeFix
import com.android.systemui.statusbar.notification.footer.shared.FooterViewRefactor
+import com.android.systemui.statusbar.notification.footer.shared.NotifRedesignFooter
import com.android.systemui.testKosmos
import com.android.systemui.util.ui.isAnimating
import com.android.systemui.util.ui.value
@@ -230,6 +232,7 @@
}
@Test
+ @DisableFlags(NotifRedesignFooter.FLAG_NAME)
fun manageButton_whenHistoryDisabled() =
testScope.runTest {
val buttonLabel by collectLastValue(underTest.manageOrHistoryButton.labelId)
@@ -243,6 +246,7 @@
}
@Test
+ @DisableFlags(NotifRedesignFooter.FLAG_NAME)
fun historyButton_whenHistoryEnabled() =
testScope.runTest {
val buttonLabel by collectLastValue(underTest.manageOrHistoryButton.labelId)
@@ -255,8 +259,9 @@
assertThat(buttonLabel).isEqualTo(R.string.manage_notifications_history_text)
}
- @EnableFlags(ModesEmptyShadeFix.FLAG_NAME)
@Test
+ @EnableFlags(ModesEmptyShadeFix.FLAG_NAME)
+ @DisableFlags(NotifRedesignFooter.FLAG_NAME)
fun manageButtonOnClick_whenHistoryDisabled() =
testScope.runTest {
val onClick by collectLastValue(underTest.manageOrHistoryButtonClick)
@@ -271,8 +276,9 @@
assertThat(onClick?.backStack).isEmpty()
}
- @EnableFlags(ModesEmptyShadeFix.FLAG_NAME)
@Test
+ @EnableFlags(ModesEmptyShadeFix.FLAG_NAME)
+ @DisableFlags(NotifRedesignFooter.FLAG_NAME)
fun historyButtonOnClick_whenHistoryEnabled() =
testScope.runTest {
val onClick by collectLastValue(underTest.manageOrHistoryButtonClick)
@@ -289,6 +295,7 @@
}
@Test
+ @DisableFlags(NotifRedesignFooter.FLAG_NAME)
fun manageButtonVisible_whenMessageVisible() =
testScope.runTest {
val visible by collectLastValue(underTest.manageOrHistoryButton.isVisible)
@@ -299,6 +306,7 @@
}
@Test
+ @DisableFlags(NotifRedesignFooter.FLAG_NAME)
fun manageButtonVisible_whenMessageNotVisible() =
testScope.runTest {
val visible by collectLastValue(underTest.manageOrHistoryButton.isVisible)
@@ -307,4 +315,30 @@
assertThat(visible?.value).isTrue()
}
+
+ @Test
+ @EnableFlags(NotifRedesignFooter.FLAG_NAME)
+ fun settingsAndHistoryButtonsNotVisible_whenMessageVisible() =
+ testScope.runTest {
+ val settingsVisible by collectLastValue(underTest.settingsButtonVisible)
+ val historyVisible by collectLastValue(underTest.historyButtonVisible)
+
+ activeNotificationListRepository.hasFilteredOutSeenNotifications.value = true
+
+ assertThat(settingsVisible).isFalse()
+ assertThat(historyVisible).isFalse()
+ }
+
+ @Test
+ @EnableFlags(NotifRedesignFooter.FLAG_NAME)
+ fun settingsAndHistoryButtonsNotVisible_whenMessageNotVisible() =
+ testScope.runTest {
+ val settingsVisible by collectLastValue(underTest.settingsButtonVisible)
+ val historyVisible by collectLastValue(underTest.historyButtonVisible)
+
+ activeNotificationListRepository.hasFilteredOutSeenNotifications.value = false
+
+ assertThat(settingsVisible).isTrue()
+ assertThat(historyVisible).isTrue()
+ }
}
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/phone/StatusBarRemoteInputCallbackTest.java b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/phone/StatusBarRemoteInputCallbackTest.java
index 81c40dc..8ec17da 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/phone/StatusBarRemoteInputCallbackTest.java
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/phone/StatusBarRemoteInputCallbackTest.java
@@ -261,6 +261,7 @@
when(enr.getPrivateLayout()).thenReturn(privateLayout);
when(enr.getEntry()).thenReturn(enrEntry);
when(enr.isChildInGroup()).thenReturn(false);
+ when(enr.isPinned()).thenReturn(false);
when(enr.isExpanded()).thenReturn(false);
// WHEN
@@ -287,6 +288,7 @@
when(enr.getPrivateLayout()).thenReturn(privateLayout);
when(enr.getEntry()).thenReturn(enrEntry);
when(enr.isChildInGroup()).thenReturn(false);
+ when(enr.isPinned()).thenReturn(false);
when(enr.isExpanded()).thenReturn(true);
// WHEN
@@ -299,4 +301,58 @@
verify(enr, never()).setUserExpanded(anyBoolean());
verify(mGroupExpansionManager, never()).toggleGroupExpansion(any());
}
+
+ @Test
+ @EnableFlags(ExpandHeadsUpOnInlineReply.FLAG_NAME)
+ public void onMakeExpandedVisibleForRemoteInput_notExpandedPinnedHUN_toggleExpansion() {
+ // GIVEN
+ final Runnable onExpandedVisibleRunner = mock(Runnable.class);
+
+ final ExpandableNotificationRow enr = mock(ExpandableNotificationRow.class);
+ final NotificationContentView privateLayout = mock(NotificationContentView.class);
+ final NotificationEntry enrEntry = mock(NotificationEntry.class);
+
+ when(enr.getPrivateLayout()).thenReturn(privateLayout);
+ when(enr.getEntry()).thenReturn(enrEntry);
+ when(enr.isChildInGroup()).thenReturn(false);
+ when(enr.isPinned()).thenReturn(true);
+ when(enr.isPinnedAndExpanded()).thenReturn(false);
+
+ // WHEN
+ mRemoteInputCallback.onMakeExpandedVisibleForRemoteInput(
+ enr, mock(View.class), false, onExpandedVisibleRunner);
+
+ // THEN
+ verify(enr).toggleExpansionState();
+ verify(privateLayout).setOnExpandedVisibleListener(onExpandedVisibleRunner);
+ verify(enr, never()).setUserExpanded(anyBoolean());
+ verify(mGroupExpansionManager, never()).toggleGroupExpansion(any());
+ }
+
+ @Test
+ @EnableFlags(ExpandHeadsUpOnInlineReply.FLAG_NAME)
+ public void onMakeExpandedVisibleForRemoteInput_expandedPinnedHUN_notToggleExpansion() {
+ // GIVEN
+ final Runnable onExpandedVisibleRunner = mock(Runnable.class);
+
+ final ExpandableNotificationRow enr = mock(ExpandableNotificationRow.class);
+ final NotificationContentView privateLayout = mock(NotificationContentView.class);
+ final NotificationEntry enrEntry = mock(NotificationEntry.class);
+
+ when(enr.getPrivateLayout()).thenReturn(privateLayout);
+ when(enr.getEntry()).thenReturn(enrEntry);
+ when(enr.isChildInGroup()).thenReturn(false);
+ when(enr.isPinned()).thenReturn(true);
+ when(enr.isPinnedAndExpanded()).thenReturn(true);
+
+ // WHEN
+ mRemoteInputCallback.onMakeExpandedVisibleForRemoteInput(
+ enr, mock(View.class), false, onExpandedVisibleRunner);
+
+ // THEN
+ verify(enr, never()).toggleExpansionState();
+ verify(privateLayout, never()).setOnExpandedVisibleListener(onExpandedVisibleRunner);
+ verify(enr, never()).setUserExpanded(anyBoolean());
+ verify(mGroupExpansionManager, never()).toggleGroupExpansion(any());
+ }
}
diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardSecurityContainerController.java b/packages/SystemUI/src/com/android/keyguard/KeyguardSecurityContainerController.java
index a408211..e564626 100644
--- a/packages/SystemUI/src/com/android/keyguard/KeyguardSecurityContainerController.java
+++ b/packages/SystemUI/src/com/android/keyguard/KeyguardSecurityContainerController.java
@@ -1102,8 +1102,11 @@
}
mView.initMode(mode, mGlobalSettings, mFalsingManager, mUserSwitcherController,
- () -> showMessage(getContext().getString(R.string.keyguard_unlock_to_continue),
- /* colorState= */ null, /* animated= */ true), mFalsingA11yDelegate);
+ () -> {
+ String msg = getContext().getString(R.string.keyguard_unlock_to_continue);
+ showMessage(msg, /* colorState= */ null, /* animated= */ true);
+ mBouncerMessageInteractor.setUnlockToContinueMessage(msg);
+ }, mFalsingA11yDelegate);
}
public void reportFailedUnlockAttempt(int userId, int timeoutMs) {
diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitor.java b/packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitor.java
index 8b2cf7a..8b59370 100644
--- a/packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitor.java
+++ b/packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitor.java
@@ -585,62 +585,68 @@
}
private void handleSimSubscriptionInfoChanged() {
- Assert.isMainThread();
mSimLogger.v("onSubscriptionInfoChanged()");
- List<SubscriptionInfo> subscriptionInfos = getSubscriptionInfo(true /* forceReload */);
- if (!subscriptionInfos.isEmpty()) {
- for (SubscriptionInfo subInfo : subscriptionInfos) {
- mSimLogger.logSubInfo(subInfo);
- }
- } else {
- mSimLogger.v("onSubscriptionInfoChanged: list is null");
- }
+ mBackgroundExecutor.execute(() -> {
+ final List<SubscriptionInfo> subscriptionInfos =
+ getSubscriptionInfo(true /* forceReload */);
+ mMainExecutor.execute(() -> {
+ if (!subscriptionInfos.isEmpty()) {
+ for (SubscriptionInfo subInfo : subscriptionInfos) {
+ mSimLogger.logSubInfo(subInfo);
+ }
+ } else {
+ mSimLogger.v("onSubscriptionInfoChanged: list is null");
+ }
- // Hack level over 9000: Because the subscription id is not yet valid when we see the
- // first update in handleSimStateChange, we need to force refresh all SIM states
- // so the subscription id for them is consistent.
- ArrayList<SubscriptionInfo> changedSubscriptions = new ArrayList<>();
- Set<Integer> activeSubIds = new HashSet<>();
- for (int i = 0; i < subscriptionInfos.size(); i++) {
- SubscriptionInfo info = subscriptionInfos.get(i);
- activeSubIds.add(info.getSubscriptionId());
- boolean changed = refreshSimState(info.getSubscriptionId(), info.getSimSlotIndex());
- if (changed) {
- changedSubscriptions.add(info);
- }
- }
+ // Hack level over 9000: Because the subscription id is not yet valid when we see
+ // the first update in handleSimStateChange, we need to force refresh all SIM states
+ // so the subscription id for them is consistent.
+ ArrayList<SubscriptionInfo> changedSubscriptions = new ArrayList<>();
+ Set<Integer> activeSubIds = new HashSet<>();
+ for (int i = 0; i < subscriptionInfos.size(); i++) {
+ SubscriptionInfo info = subscriptionInfos.get(i);
+ activeSubIds.add(info.getSubscriptionId());
+ boolean changed = refreshSimState(info.getSubscriptionId(),
+ info.getSimSlotIndex());
+ if (changed) {
+ changedSubscriptions.add(info);
+ }
+ }
- // It is possible for active subscriptions to become invalid (-1), and these will not be
- // present in the subscriptionInfo list
- synchronized (mSimDataLockObject) {
- Iterator<Map.Entry<Integer, SimData>> iter = mSimDatas.entrySet().iterator();
- while (iter.hasNext()) {
- Map.Entry<Integer, SimData> simData = iter.next();
- if (!activeSubIds.contains(simData.getKey())) {
- mSimLogger.logInvalidSubId(simData.getKey());
- iter.remove();
+ // It is possible for active subscriptions to become invalid (-1), and these will
+ // not be present in the subscriptionInfo list
+ synchronized (mSimDataLockObject) {
+ Iterator<Map.Entry<Integer, SimData>> iter = mSimDatas.entrySet().iterator();
+ while (iter.hasNext()) {
+ Map.Entry<Integer, SimData> simData = iter.next();
+ if (!activeSubIds.contains(simData.getKey())) {
+ mSimLogger.logInvalidSubId(simData.getKey());
+ iter.remove();
- SimData data = simData.getValue();
- for (int j = 0; j < mCallbacks.size(); j++) {
- KeyguardUpdateMonitorCallback cb = mCallbacks.get(j).get();
- if (cb != null) {
- cb.onSimStateChanged(data.subId, data.slotId, data.simState);
+ SimData data = simData.getValue();
+ for (int j = 0; j < mCallbacks.size(); j++) {
+ KeyguardUpdateMonitorCallback cb = mCallbacks.get(j).get();
+ if (cb != null) {
+ cb.onSimStateChanged(data.subId, data.slotId, data.simState);
+ }
+ }
}
}
- }
- }
- for (int i = 0; i < changedSubscriptions.size(); i++) {
- SimData data = mSimDatas.get(changedSubscriptions.get(i).getSubscriptionId());
- for (int j = 0; j < mCallbacks.size(); j++) {
- KeyguardUpdateMonitorCallback cb = mCallbacks.get(j).get();
- if (cb != null) {
- cb.onSimStateChanged(data.subId, data.slotId, data.simState);
+ for (int i = 0; i < changedSubscriptions.size(); i++) {
+ SimData data = mSimDatas.get(
+ changedSubscriptions.get(i).getSubscriptionId());
+ for (int j = 0; j < mCallbacks.size(); j++) {
+ KeyguardUpdateMonitorCallback cb = mCallbacks.get(j).get();
+ if (cb != null) {
+ cb.onSimStateChanged(data.subId, data.slotId, data.simState);
+ }
+ }
}
+ callbacksRefreshCarrierInfo();
}
- }
- callbacksRefreshCarrierInfo();
- }
+ });
+ });
}
private void handleAirplaneModeChanged() {
@@ -2523,6 +2529,11 @@
if (mUserTracker.isUserSwitching()) {
handleUserSwitching(mUserTracker.getUserId(), () -> {});
}
+
+ // Force the cache to be initialized
+ mBackgroundExecutor.execute(() -> {
+ getSubscriptionInfo(/* forceReload= */ true);
+ });
}
@VisibleForTesting
@@ -3851,11 +3862,14 @@
* @see #isSimPinSecure(int)
*/
public boolean isSimPinSecure() {
- // True if any SIM is pin secure
- for (SubscriptionInfo info : getSubscriptionInfo(false /* forceReload */)) {
- if (isSimPinSecure(getSimState(info.getSubscriptionId()))) return true;
+ synchronized (mSimDataLockObject) {
+ for (SimData data : mSimDatas.values()) {
+ if (isSimPinSecure(data.simState)) {
+ return true;
+ }
+ }
+ return false;
}
- return false;
}
public int getSimState(int subId) {
diff --git a/packages/SystemUI/src/com/android/systemui/bouncer/domain/interactor/BouncerMessageInteractor.kt b/packages/SystemUI/src/com/android/systemui/bouncer/domain/interactor/BouncerMessageInteractor.kt
index d125c36..e52ddb2 100644
--- a/packages/SystemUI/src/com/android/systemui/bouncer/domain/interactor/BouncerMessageInteractor.kt
+++ b/packages/SystemUI/src/com/android/systemui/bouncer/domain/interactor/BouncerMessageInteractor.kt
@@ -81,7 +81,7 @@
deviceEntryBiometricsAllowedInteractor.isFingerprintCurrentlyAllowedOnBouncer.stateIn(
applicationScope,
SharingStarted.Eagerly,
- false
+ false,
)
private val currentSecurityMode
@@ -114,13 +114,13 @@
BiometricSourceType.FACE ->
BouncerMessageStrings.incorrectFaceInput(
currentSecurityMode.toAuthModel(),
- isFingerprintAuthCurrentlyAllowedOnBouncer.value
+ isFingerprintAuthCurrentlyAllowedOnBouncer.value,
)
.toMessage()
else ->
BouncerMessageStrings.defaultMessage(
currentSecurityMode.toAuthModel(),
- isFingerprintAuthCurrentlyAllowedOnBouncer.value
+ isFingerprintAuthCurrentlyAllowedOnBouncer.value,
)
.toMessage()
},
@@ -130,7 +130,7 @@
override fun onBiometricAcquired(
biometricSourceType: BiometricSourceType?,
- acquireInfo: Int
+ acquireInfo: Int,
) {
if (
repository.getMessageSource() == BiometricSourceType.FACE &&
@@ -143,7 +143,7 @@
override fun onBiometricAuthenticated(
userId: Int,
biometricSourceType: BiometricSourceType?,
- isStrongBiometric: Boolean
+ isStrongBiometric: Boolean,
) {
repository.setMessage(defaultMessage, biometricSourceType)
}
@@ -169,7 +169,7 @@
deviceEntryBiometricsAllowedInteractor.isFingerprintLockedOut,
deviceEntryBiometricsAllowedInteractor.isFaceLockedOut,
isFingerprintAuthCurrentlyAllowedOnBouncer,
- ::Septuple
+ ::Septuple,
)
.map { (_, flags, _, biometricsEnrolledAndEnabled, fpLockedOut, faceLockedOut, _) ->
val isTrustUsuallyManaged = trustRepository.isCurrentUserTrustUsuallyManaged.value
@@ -220,14 +220,14 @@
} else {
BouncerMessageStrings.faceLockedOut(
currentSecurityMode.toAuthModel(),
- isFingerprintAuthCurrentlyAllowedOnBouncer.value
+ isFingerprintAuthCurrentlyAllowedOnBouncer.value,
)
.toMessage()
}
} else if (flags.isSomeAuthRequiredAfterAdaptiveAuthRequest) {
BouncerMessageStrings.authRequiredAfterAdaptiveAuthRequest(
currentSecurityMode.toAuthModel(),
- isFingerprintAuthCurrentlyAllowedOnBouncer.value
+ isFingerprintAuthCurrentlyAllowedOnBouncer.value,
)
.toMessage()
} else if (
@@ -236,19 +236,19 @@
) {
BouncerMessageStrings.nonStrongAuthTimeout(
currentSecurityMode.toAuthModel(),
- isFingerprintAuthCurrentlyAllowedOnBouncer.value
+ isFingerprintAuthCurrentlyAllowedOnBouncer.value,
)
.toMessage()
} else if (isTrustUsuallyManaged && flags.someAuthRequiredAfterUserRequest) {
BouncerMessageStrings.trustAgentDisabled(
currentSecurityMode.toAuthModel(),
- isFingerprintAuthCurrentlyAllowedOnBouncer.value
+ isFingerprintAuthCurrentlyAllowedOnBouncer.value,
)
.toMessage()
} else if (isTrustUsuallyManaged && flags.someAuthRequiredAfterTrustAgentExpired) {
BouncerMessageStrings.trustAgentDisabled(
currentSecurityMode.toAuthModel(),
- isFingerprintAuthCurrentlyAllowedOnBouncer.value
+ isFingerprintAuthCurrentlyAllowedOnBouncer.value,
)
.toMessage()
} else if (trustOrBiometricsAvailable && flags.isInUserLockdown) {
@@ -292,7 +292,7 @@
repository.setMessage(
BouncerMessageStrings.incorrectSecurityInput(
currentSecurityMode.toAuthModel(),
- isFingerprintAuthCurrentlyAllowedOnBouncer.value
+ isFingerprintAuthCurrentlyAllowedOnBouncer.value,
)
.toMessage()
)
@@ -304,19 +304,30 @@
defaultMessage(
currentSecurityMode,
value,
- isFingerprintAuthCurrentlyAllowedOnBouncer.value
+ isFingerprintAuthCurrentlyAllowedOnBouncer.value,
),
BiometricSourceType.FINGERPRINT,
)
}
+ fun setUnlockToContinueMessage(value: String) {
+ if (!Flags.revampedBouncerMessages()) return
+ repository.setMessage(
+ defaultMessage(
+ currentSecurityMode,
+ value,
+ isFingerprintAuthCurrentlyAllowedOnBouncer.value,
+ )
+ )
+ }
+
fun setFaceAcquisitionMessage(value: String?) {
if (!Flags.revampedBouncerMessages()) return
repository.setMessage(
defaultMessage(
currentSecurityMode,
value,
- isFingerprintAuthCurrentlyAllowedOnBouncer.value
+ isFingerprintAuthCurrentlyAllowedOnBouncer.value,
),
BiometricSourceType.FACE,
)
@@ -329,7 +340,7 @@
defaultMessage(
currentSecurityMode,
value,
- isFingerprintAuthCurrentlyAllowedOnBouncer.value
+ isFingerprintAuthCurrentlyAllowedOnBouncer.value,
)
)
}
@@ -338,7 +349,7 @@
get() =
BouncerMessageStrings.defaultMessage(
currentSecurityMode.toAuthModel(),
- isFingerprintAuthCurrentlyAllowedOnBouncer.value
+ isFingerprintAuthCurrentlyAllowedOnBouncer.value,
)
.toMessage()
@@ -400,7 +411,7 @@
private fun defaultMessage(
securityMode: SecurityMode,
secondaryMessage: String?,
- fpAuthIsAllowed: Boolean
+ fpAuthIsAllowed: Boolean,
): BouncerMessageModel {
return BouncerMessageModel(
message =
@@ -408,21 +419,21 @@
messageResId =
BouncerMessageStrings.defaultMessage(
securityMode.toAuthModel(),
- fpAuthIsAllowed
+ fpAuthIsAllowed,
)
.toMessage()
.message
?.messageResId,
- animate = false
+ animate = false,
),
- secondaryMessage = Message(message = secondaryMessage, animate = false)
+ secondaryMessage = Message(message = secondaryMessage, animate = false),
)
}
private fun Pair<Int, Int>.toMessage(): BouncerMessageModel {
return BouncerMessageModel(
message = Message(messageResId = this.first, animate = false),
- secondaryMessage = Message(messageResId = this.second, animate = false)
+ secondaryMessage = Message(messageResId = this.second, animate = false),
)
}
diff --git a/packages/SystemUI/src/com/android/systemui/complication/dagger/RegisteredComplicationsModule.java b/packages/SystemUI/src/com/android/systemui/complication/dagger/RegisteredComplicationsModule.java
index 6f1b098..9970c5d 100644
--- a/packages/SystemUI/src/com/android/systemui/complication/dagger/RegisteredComplicationsModule.java
+++ b/packages/SystemUI/src/com/android/systemui/complication/dagger/RegisteredComplicationsModule.java
@@ -20,7 +20,6 @@
import android.view.ViewGroup;
import com.android.systemui.complication.ComplicationLayoutParams;
-import com.android.systemui.dagger.SystemUIBinder;
import com.android.systemui.dagger.qualifiers.Main;
import com.android.systemui.flags.FeatureFlags;
import com.android.systemui.flags.Flags;
@@ -32,8 +31,7 @@
import javax.inject.Named;
/**
- * Module for all components with corresponding dream layer complications registered in
- * {@link SystemUIBinder}.
+ * Module for all components with corresponding dream layer complications.
*/
@Module(
subcomponents = {
diff --git a/packages/SystemUI/src/com/android/systemui/dagger/ReferenceSysUIComponent.java b/packages/SystemUI/src/com/android/systemui/dagger/ReferenceSysUIComponent.java
index b71af69..b34a240 100644
--- a/packages/SystemUI/src/com/android/systemui/dagger/ReferenceSysUIComponent.java
+++ b/packages/SystemUI/src/com/android/systemui/dagger/ReferenceSysUIComponent.java
@@ -32,7 +32,6 @@
DependencyProvider.class,
NotificationInsetsModule.class,
QsFrameTranslateModule.class,
- SystemUIBinder.class,
SystemUIModule.class,
SystemUICoreStartableModule.class,
SysUIUnfoldModule.class,
diff --git a/packages/SystemUI/src/com/android/systemui/dagger/ReferenceSystemUIModule.java b/packages/SystemUI/src/com/android/systemui/dagger/ReferenceSystemUIModule.java
index b966ad4..bf93469 100644
--- a/packages/SystemUI/src/com/android/systemui/dagger/ReferenceSystemUIModule.java
+++ b/packages/SystemUI/src/com/android/systemui/dagger/ReferenceSystemUIModule.java
@@ -38,6 +38,7 @@
import com.android.systemui.emergency.EmergencyGestureModule;
import com.android.systemui.inputdevice.tutorial.KeyboardTouchpadTutorialModule;
import com.android.systemui.keyboard.shortcut.ShortcutHelperModule;
+import com.android.systemui.keyguard.dagger.KeyguardModule;
import com.android.systemui.keyguard.ui.composable.blueprint.DefaultBlueprintModule;
import com.android.systemui.keyguard.ui.view.layout.blueprints.KeyguardBlueprintModule;
import com.android.systemui.keyguard.ui.view.layout.sections.KeyguardSectionsModule;
@@ -53,6 +54,7 @@
import com.android.systemui.reardisplay.RearDisplayModule;
import com.android.systemui.recents.Recents;
import com.android.systemui.recents.RecentsImplementation;
+import com.android.systemui.recents.RecentsModule;
import com.android.systemui.rotationlock.RotationLockModule;
import com.android.systemui.rotationlock.RotationLockNewModule;
import com.android.systemui.scene.SceneContainerFrameworkModule;
@@ -68,6 +70,7 @@
import com.android.systemui.statusbar.NotificationLockscreenUserManagerImpl;
import com.android.systemui.statusbar.NotificationShadeWindowController;
import com.android.systemui.statusbar.SysuiStatusBarStateController;
+import com.android.systemui.statusbar.dagger.CentralSurfacesModule;
import com.android.systemui.statusbar.dagger.StartCentralSurfacesModule;
import com.android.systemui.statusbar.phone.CentralSurfaces;
import com.android.systemui.statusbar.phone.DozeServiceHost;
@@ -120,6 +123,7 @@
AccessibilityRepositoryModule.class,
AospPolicyModule.class,
BatterySaverModule.class,
+ CentralSurfacesModule.class,
ClipboardOverlaySuppressionModule.class,
CollapsedStatusBarFragmentStartableModule.class,
ConnectingDisplayViewModel.StartableModule.class,
@@ -127,6 +131,7 @@
EmergencyGestureModule.class,
GestureModule.class,
HeadsUpModule.class,
+ KeyguardModule.class,
KeyboardShortcutsModule.class,
KeyguardBlueprintModule.class,
KeyguardSectionsModule.class,
@@ -139,6 +144,7 @@
PowerModule.class,
QSModule.class,
RearDisplayModule.class,
+ RecentsModule.class,
ReferenceScreenshotModule.class,
RotationLockModule.class,
RotationLockNewModule.class,
diff --git a/packages/SystemUI/src/com/android/systemui/dagger/SysUIComponent.java b/packages/SystemUI/src/com/android/systemui/dagger/SysUIComponent.java
index 17f1961..580896c 100644
--- a/packages/SystemUI/src/com/android/systemui/dagger/SysUIComponent.java
+++ b/packages/SystemUI/src/com/android/systemui/dagger/SysUIComponent.java
@@ -65,7 +65,6 @@
DependencyProvider.class,
NotificationInsetsModule.class,
QsFrameTranslateModule.class,
- SystemUIBinder.class,
SystemUIModule.class,
SystemUICoreStartableModule.class,
ReferenceSystemUIModule.class})
diff --git a/packages/SystemUI/src/com/android/systemui/dagger/SystemUIBinder.java b/packages/SystemUI/src/com/android/systemui/dagger/SystemUIBinder.java
deleted file mode 100644
index 2f041ac..0000000
--- a/packages/SystemUI/src/com/android/systemui/dagger/SystemUIBinder.java
+++ /dev/null
@@ -1,34 +0,0 @@
-/*
- * Copyright (C) 2019 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.dagger;
-
-import com.android.systemui.keyguard.dagger.KeyguardModule;
-import com.android.systemui.recents.RecentsModule;
-import com.android.systemui.statusbar.dagger.CentralSurfacesModule;
-
-import dagger.Module;
-
-/**
- * SystemUI objects that are injectable should go here.
- */
-@Module(includes = {
- RecentsModule.class,
- CentralSurfacesModule.class,
- KeyguardModule.class,
-})
-public abstract class SystemUIBinder {
-}
diff --git a/packages/SystemUI/src/com/android/systemui/haptics/slider/HapticSlider.kt b/packages/SystemUI/src/com/android/systemui/haptics/slider/HapticSlider.kt
new file mode 100644
index 0000000..1d226fd
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/haptics/slider/HapticSlider.kt
@@ -0,0 +1,41 @@
+/*
+ * 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.haptics.slider
+
+sealed interface HapticSlider {
+
+ val min: Float
+ val max: Float
+
+ class SeekBar(val seekBar: android.widget.SeekBar) : HapticSlider {
+
+ override val min: Float
+ get() = seekBar.min.toFloat()
+
+ override val max: Float
+ get() = seekBar.max.toFloat()
+ }
+
+ class Slider(val slider: com.google.android.material.slider.Slider) : HapticSlider {
+
+ override val min: Float
+ get() = slider.valueFrom
+
+ override val max: Float
+ get() = slider.valueTo
+ }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/haptics/slider/SeekbarHapticPlugin.kt b/packages/SystemUI/src/com/android/systemui/haptics/slider/HapticSliderPlugin.kt
similarity index 83%
rename from packages/SystemUI/src/com/android/systemui/haptics/slider/SeekbarHapticPlugin.kt
rename to packages/SystemUI/src/com/android/systemui/haptics/slider/HapticSliderPlugin.kt
index f6d7e15..16c53b1 100644
--- a/packages/SystemUI/src/com/android/systemui/haptics/slider/SeekbarHapticPlugin.kt
+++ b/packages/SystemUI/src/com/android/systemui/haptics/slider/HapticSliderPlugin.kt
@@ -18,30 +18,30 @@
import android.view.MotionEvent
import android.view.VelocityTracker
-import android.widget.SeekBar
import androidx.annotation.VisibleForTesting
+import com.android.app.tracing.coroutines.launchTraced as launch
import com.android.systemui.statusbar.VibratorHelper
import com.android.systemui.util.time.SystemClock
import com.google.android.msdl.domain.MSDLPlayer
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Job
import kotlinx.coroutines.delay
-import com.android.app.tracing.coroutines.launchTraced as launch
/**
- * A plugin added to a manager of a [android.widget.SeekBar] that adds dynamic haptic feedback.
+ * A plugin added to a manager of a [HapticSlider] that adds dynamic haptic feedback.
*
* A [SliderStateProducer] is used as the producer of slider events, a
* [SliderHapticFeedbackProvider] is used as the listener of slider states to play haptic feedback
* depending on the state, and a [SliderStateTracker] is used as the state machine handler that
* tracks and manipulates the slider state.
*/
-class SeekbarHapticPlugin
+class HapticSliderPlugin
@JvmOverloads
constructor(
vibratorHelper: VibratorHelper,
msdlPlayer: MSDLPlayer,
systemClock: SystemClock,
+ private val slider: HapticSlider,
sliderHapticFeedbackConfig: SliderHapticFeedbackConfig = SliderHapticFeedbackConfig(),
private val sliderTrackerConfig: SeekableSliderTrackerConfig = SeekableSliderTrackerConfig(),
) {
@@ -128,46 +128,42 @@
}
}
- /** onStartTrackingTouch event from the slider's [android.widget.SeekBar] */
- fun onStartTrackingTouch(seekBar: SeekBar) {
+ /** onStartTrackingTouch event from the slider. */
+ fun onStartTrackingTouch() {
if (isTracking) {
sliderEventProducer.onStartTracking(true)
}
}
- /** onProgressChanged event from the slider's [android.widget.SeekBar] */
- fun onProgressChanged(seekBar: SeekBar, progress: Int, fromUser: Boolean) {
+ /** onProgressChanged event from the slider's. */
+ fun onProgressChanged(progress: Int, fromUser: Boolean) {
if (isTracking) {
if (sliderTracker?.currentState == SliderState.IDLE && !fromUser) {
// This case translates to the slider starting to track program changes
- sliderEventProducer.resetWithProgress(normalizeProgress(seekBar, progress))
+ sliderEventProducer.resetWithProgress(normalizeProgress(slider, progress))
sliderEventProducer.onStartTracking(false)
} else {
- sliderEventProducer.onProgressChanged(
- fromUser,
- normalizeProgress(seekBar, progress),
- )
+ sliderEventProducer.onProgressChanged(fromUser, normalizeProgress(slider, progress))
}
}
}
/**
- * Normalize the integer progress of a SeekBar to the range from 0F to 1F.
+ * Normalize the integer progress of a HapticSlider to the range from 0F to 1F.
*
- * @param[seekBar] The SeekBar that reports a progress.
- * @param[progress] The integer progress of the SeekBar within its min and max values.
+ * @param[slider] The HapticSlider that reports a progress.
+ * @param[progress] The integer progress of the HapticSlider within its min and max values.
* @return The progress in the range from 0F to 1F.
*/
- private fun normalizeProgress(seekBar: SeekBar, progress: Int): Float {
- if (seekBar.max == seekBar.min) {
+ private fun normalizeProgress(slider: HapticSlider, progress: Int): Float {
+ if (slider.max == slider.min) {
return 1.0f
}
- val range = seekBar.max - seekBar.min
- return (progress - seekBar.min) / range.toFloat()
+ return (progress - slider.min) / (slider.max - slider.min)
}
- /** onStopTrackingTouch event from the slider's [android.widget.SeekBar] */
- fun onStopTrackingTouch(seekBar: SeekBar) {
+ /** onStopTrackingTouch event from the slider. */
+ fun onStopTrackingTouch() {
if (isTracking) {
sliderEventProducer.onStopTracking(true)
}
diff --git a/packages/SystemUI/src/com/android/systemui/haptics/slider/HapticSliderViewBinder.kt b/packages/SystemUI/src/com/android/systemui/haptics/slider/HapticSliderViewBinder.kt
index ca6c8da..f43682d 100644
--- a/packages/SystemUI/src/com/android/systemui/haptics/slider/HapticSliderViewBinder.kt
+++ b/packages/SystemUI/src/com/android/systemui/haptics/slider/HapticSliderViewBinder.kt
@@ -23,11 +23,11 @@
object HapticSliderViewBinder {
/**
- * Binds a [SeekbarHapticPlugin] to a [View]. The binded view should be a
+ * Binds a [HapticSliderPlugin] to a [View]. The binded view should be a
* [android.widget.SeekBar] or a container of a [android.widget.SeekBar]
*/
@JvmStatic
- fun bind(view: View?, plugin: SeekbarHapticPlugin) {
+ fun bind(view: View?, plugin: HapticSliderPlugin) {
view?.repeatWhenAttached {
plugin.startInScope(lifecycleScope)
try {
diff --git a/packages/SystemUI/src/com/android/systemui/settings/brightness/BrightnessSliderController.java b/packages/SystemUI/src/com/android/systemui/settings/brightness/BrightnessSliderController.java
index 8703f68..2f7df21 100644
--- a/packages/SystemUI/src/com/android/systemui/settings/brightness/BrightnessSliderController.java
+++ b/packages/SystemUI/src/com/android/systemui/settings/brightness/BrightnessSliderController.java
@@ -30,8 +30,9 @@
import com.android.settingslib.RestrictedLockUtils;
import com.android.systemui.Gefingerpoken;
import com.android.systemui.classifier.Classifier;
+import com.android.systemui.haptics.slider.HapticSlider;
+import com.android.systemui.haptics.slider.HapticSliderPlugin;
import com.android.systemui.haptics.slider.HapticSliderViewBinder;
-import com.android.systemui.haptics.slider.SeekbarHapticPlugin;
import com.android.systemui.plugins.ActivityStarter;
import com.android.systemui.plugins.FalsingManager;
import com.android.systemui.res.R;
@@ -39,7 +40,6 @@
import com.android.systemui.statusbar.policy.BrightnessMirrorController;
import com.android.systemui.util.ViewController;
import com.android.systemui.util.time.SystemClock;
-
import com.google.android.msdl.domain.MSDLPlayer;
import javax.inject.Inject;
@@ -65,7 +65,7 @@
private final FalsingManager mFalsingManager;
private final UiEventLogger mUiEventLogger;
- private final SeekbarHapticPlugin mBrightnessSliderHapticPlugin;
+ private final HapticSliderPlugin mBrightnessSliderHapticPlugin;
private final ActivityStarter mActivityStarter;
private final Gefingerpoken mOnInterceptListener = new Gefingerpoken() {
@@ -89,7 +89,7 @@
BrightnessSliderView brightnessSliderView,
FalsingManager falsingManager,
UiEventLogger uiEventLogger,
- SeekbarHapticPlugin brightnessSliderHapticPlugin,
+ HapticSliderPlugin brightnessSliderHapticPlugin,
ActivityStarter activityStarter) {
super(brightnessSliderView);
mFalsingManager = falsingManager;
@@ -240,7 +240,7 @@
if (mListener != null) {
mListener.onChanged(mTracking, progress, false);
if (fromUser) {
- mBrightnessSliderHapticPlugin.onProgressChanged(seekBar, progress, fromUser);
+ mBrightnessSliderHapticPlugin.onProgressChanged(progress, true);
}
}
}
@@ -251,7 +251,7 @@
mUiEventLogger.log(BrightnessSliderEvent.BRIGHTNESS_SLIDER_STARTED_TRACKING_TOUCH);
if (mListener != null) {
mListener.onChanged(mTracking, getValue(), false);
- mBrightnessSliderHapticPlugin.onStartTrackingTouch(seekBar);
+ mBrightnessSliderHapticPlugin.onStartTrackingTouch();
}
if (mMirrorController != null) {
@@ -266,7 +266,7 @@
mUiEventLogger.log(BrightnessSliderEvent.BRIGHTNESS_SLIDER_STOPPED_TRACKING_TOUCH);
if (mListener != null) {
mListener.onChanged(mTracking, getValue(), true);
- mBrightnessSliderHapticPlugin.onStopTrackingTouch(seekBar);
+ mBrightnessSliderHapticPlugin.onStopTrackingTouch();
}
if (mMirrorController != null) {
@@ -317,10 +317,11 @@
int layout = getLayout();
BrightnessSliderView root = (BrightnessSliderView) LayoutInflater.from(context)
.inflate(layout, viewRoot, false);
- SeekbarHapticPlugin plugin = new SeekbarHapticPlugin(
+ HapticSliderPlugin plugin = new HapticSliderPlugin(
mVibratorHelper,
mMSDLPlayer,
- mSystemClock);
+ mSystemClock,
+ new HapticSlider.SeekBar(root.requireViewById(R.id.slider)));
HapticSliderViewBinder.bind(viewRoot, plugin);
return new BrightnessSliderController(
root, mFalsingManager, mUiEventLogger, plugin, mActivityStarter);
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/footer/shared/NotifRedesignFooter.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/footer/shared/NotifRedesignFooter.kt
new file mode 100644
index 0000000..0307d90
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/footer/shared/NotifRedesignFooter.kt
@@ -0,0 +1,61 @@
+/*
+ * 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.statusbar.notification.footer.shared
+
+import com.android.systemui.Flags
+import com.android.systemui.flags.FlagToken
+import com.android.systemui.flags.RefactorFlagUtils
+
+/** Helper for reading or using the flag state for the footer redesign. */
+@Suppress("NOTHING_TO_INLINE")
+object NotifRedesignFooter {
+ /** The aconfig flag name */
+ const val FLAG_NAME = Flags.FLAG_NOTIFICATIONS_REDESIGN_FOOTER_VIEW
+
+ /** A token used for dependency declaration */
+ val token: FlagToken
+ get() = FlagToken(FLAG_NAME, isEnabled)
+
+ /** Is the refactor enabled */
+ @JvmStatic
+ inline val isEnabled
+ get() = Flags.notificationsRedesignFooterView()
+
+ /**
+ * Called to ensure code is only run when the flag is enabled. This protects users from the
+ * unintended behaviors caused by accidentally running new logic, while also crashing on an eng
+ * build to ensure that the refactor author catches issues in testing.
+ */
+ @JvmStatic
+ inline fun isUnexpectedlyInLegacyMode() =
+ RefactorFlagUtils.isUnexpectedlyInLegacyMode(isEnabled, FLAG_NAME)
+
+ /**
+ * Called to ensure code is only run when the flag is enabled. This will throw an exception if
+ * the flag is not enabled to ensure that the refactor author catches issues in testing.
+ * Caution!! Using this check incorrectly will cause crashes in nextfood builds!
+ */
+ @JvmStatic
+ inline fun assertInNewMode() = RefactorFlagUtils.assertInNewMode(isEnabled, FLAG_NAME)
+
+ /**
+ * Called to ensure code is only run when the flag is disabled. This will throw an exception if
+ * the flag is enabled to ensure that the refactor author catches issues in testing.
+ */
+ @JvmStatic
+ inline fun assertInLegacyMode() = RefactorFlagUtils.assertInLegacyMode(isEnabled, FLAG_NAME)
+}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/footer/ui/view/FooterView.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/footer/ui/view/FooterView.java
index bf30322..96f47e5 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/footer/ui/view/FooterView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/footer/ui/view/FooterView.java
@@ -40,10 +40,10 @@
import androidx.annotation.NonNull;
import com.android.settingslib.Utils;
-import com.android.systemui.Flags;
import com.android.systemui.res.R;
import com.android.systemui.statusbar.notification.ColorUpdateLogger;
import com.android.systemui.statusbar.notification.footer.shared.FooterViewRefactor;
+import com.android.systemui.statusbar.notification.footer.shared.NotifRedesignFooter;
import com.android.systemui.statusbar.notification.row.FooterViewButton;
import com.android.systemui.statusbar.notification.row.StackScrollerDecorView;
import com.android.systemui.statusbar.notification.stack.AnimationProperties;
@@ -107,11 +107,31 @@
setClearAllButtonVisible(visible, animate, /* onAnimationEnded = */ null);
}
- /** Set the visibility of the "Manage"/"History" button to {@code visible}. */
+ /**
+ * Set the visibility of the "Manage"/"History" button to {@code visible}. This is replaced by
+ * two separate buttons in the redesign.
+ */
public void setManageOrHistoryButtonVisible(boolean visible) {
+ NotifRedesignFooter.assertInLegacyMode();
mManageOrHistoryButton.setVisibility(visible ? View.VISIBLE : View.GONE);
}
+ /** Set the visibility of the Settings button to {@code visible}. */
+ public void setSettingsButtonVisible(boolean visible) {
+ if (NotifRedesignFooter.isUnexpectedlyInLegacyMode()) {
+ return;
+ }
+ mSettingsButton.setVisibility(visible ? View.VISIBLE : View.GONE);
+ }
+
+ /** Set the visibility of the History button to {@code visible}. */
+ public void setHistoryButtonVisible(boolean visible) {
+ if (NotifRedesignFooter.isUnexpectedlyInLegacyMode()) {
+ return;
+ }
+ mHistoryButton.setVisibility(visible ? View.VISIBLE : View.GONE);
+ }
+
/**
* Set the visibility of the "Clear all" button to {@code visible}. Animate the change if
* {@code animate} is true.
@@ -187,6 +207,7 @@
/** Set the text label for the "Manage"/"History" button. */
public void setManageOrHistoryButtonText(@StringRes int textId) {
+ NotifRedesignFooter.assertInLegacyMode();
if (FooterViewRefactor.isUnexpectedlyInLegacyMode()) return;
if (mManageOrHistoryButtonTextId == textId) {
return; // nothing changed
@@ -196,6 +217,7 @@
}
private void updateManageOrHistoryButtonText() {
+ NotifRedesignFooter.assertInLegacyMode();
if (mManageOrHistoryButtonTextId == 0) {
return; // not initialized yet
}
@@ -204,6 +226,7 @@
/** Set the accessibility content description for the "Clear all" button. */
public void setManageOrHistoryButtonDescription(@StringRes int contentDescriptionId) {
+ NotifRedesignFooter.assertInLegacyMode();
if (FooterViewRefactor.isUnexpectedlyInLegacyMode()) {
return;
}
@@ -215,6 +238,7 @@
}
private void updateManageOrHistoryButtonDescription() {
+ NotifRedesignFooter.assertInLegacyMode();
if (mManageOrHistoryButtonDescriptionId == 0) {
return; // not initialized yet
}
@@ -273,7 +297,7 @@
}
super.onFinishInflate();
mClearAllButton = (FooterViewButton) findSecondaryView();
- if (Flags.notificationsRedesignFooterView()) {
+ if (NotifRedesignFooter.isEnabled()) {
mSettingsButton = findViewById(R.id.settings_button);
mHistoryButton = findViewById(R.id.history_button);
} else {
@@ -311,11 +335,17 @@
/** Set onClickListener for the notification settings button. */
public void setSettingsButtonClickListener(OnClickListener listener) {
+ if (NotifRedesignFooter.isUnexpectedlyInLegacyMode()) {
+ return;
+ }
mSettingsButton.setOnClickListener(listener);
}
/** Set onClickListener for the notification history button. */
public void setHistoryButtonClickListener(OnClickListener listener) {
+ if (NotifRedesignFooter.isUnexpectedlyInLegacyMode()) {
+ return;
+ }
mHistoryButton.setOnClickListener(listener);
}
@@ -324,6 +354,7 @@
* in the redesign.
*/
public void setManageButtonClickListener(OnClickListener listener) {
+ NotifRedesignFooter.assertInLegacyMode();
mManageOrHistoryButton.setOnClickListener(listener);
}
@@ -364,7 +395,7 @@
updateClearAllButtonText();
updateClearAllButtonDescription();
- if (!Flags.notificationsRedesignFooterView()) {
+ if (!NotifRedesignFooter.isEnabled()) {
updateManageOrHistoryButtonText();
updateManageOrHistoryButtonDescription();
}
@@ -444,7 +475,7 @@
}
mClearAllButton.setBackground(clearAllBg);
mClearAllButton.setTextColor(onSurface);
- if (Flags.notificationsRedesignFooterView()) {
+ if (NotifRedesignFooter.isEnabled()) {
mSettingsButton.setBackground(manageBg);
mSettingsButton.setCompoundDrawableTintList(ColorStateList.valueOf(onSurface));
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/footer/ui/viewbinder/FooterViewBinder.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/footer/ui/viewbinder/FooterViewBinder.kt
index 34894a2..3383ce9 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/footer/ui/viewbinder/FooterViewBinder.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/footer/ui/viewbinder/FooterViewBinder.kt
@@ -20,11 +20,11 @@
import androidx.lifecycle.lifecycleScope
import com.android.app.tracing.coroutines.launchTraced as launch
import com.android.internal.jank.InteractionJankMonitor
-import com.android.systemui.Flags
import com.android.systemui.lifecycle.repeatWhenAttached
import com.android.systemui.statusbar.notification.NotificationActivityStarter
import com.android.systemui.statusbar.notification.NotificationActivityStarter.SettingsIntent
import com.android.systemui.statusbar.notification.emptyshade.shared.ModesEmptyShadeFix
+import com.android.systemui.statusbar.notification.footer.shared.NotifRedesignFooter
import com.android.systemui.statusbar.notification.footer.ui.view.FooterView
import com.android.systemui.statusbar.notification.footer.ui.viewmodel.FooterViewModel
import com.android.systemui.util.ui.isAnimating
@@ -66,7 +66,7 @@
notificationActivityStarter: NotificationActivityStarter,
) = coroutineScope {
launch { bindClearAllButton(footer, viewModel, clearAllNotifications) }
- if (!Flags.notificationsRedesignFooterView()) {
+ if (!NotifRedesignFooter.isEnabled) {
launch {
bindManageOrHistoryButton(
footer,
@@ -77,8 +77,8 @@
)
}
} else {
- bindSettingsButtonListener(footer, notificationActivityStarter)
- bindHistoryButtonListener(footer, notificationActivityStarter)
+ launch { bindSettingsButton(footer, viewModel, notificationActivityStarter) }
+ launch { bindHistoryButton(footer, viewModel, notificationActivityStarter) }
}
launch { bindMessage(footer, viewModel) }
}
@@ -122,10 +122,11 @@
}
}
- private fun bindSettingsButtonListener(
+ private suspend fun bindSettingsButton(
footer: FooterView,
+ viewModel: FooterViewModel,
notificationActivityStarter: NotificationActivityStarter,
- ) {
+ ) = coroutineScope {
val settingsIntent =
SettingsIntent.forNotificationSettings(
cujType = InteractionJankMonitor.CUJ_SHADE_APP_LAUNCH_FROM_HISTORY_BUTTON
@@ -134,12 +135,20 @@
notificationActivityStarter.startSettingsIntent(view, settingsIntent)
}
footer.setSettingsButtonClickListener(onClickListener)
+
+ launch {
+ // NOTE: This visibility change is never animated. We also don't need to do anything
+ // special about the onClickListener here, since we're changing the visibility to
+ // GONE so it won't be clickable anyway.
+ viewModel.settingsButtonVisible.collect { footer.setSettingsButtonVisible(it) }
+ }
}
- private fun bindHistoryButtonListener(
+ private suspend fun bindHistoryButton(
footer: FooterView,
+ viewModel: FooterViewModel,
notificationActivityStarter: NotificationActivityStarter,
- ) {
+ ) = coroutineScope {
val settingsIntent =
SettingsIntent.forNotificationHistory(
cujType = InteractionJankMonitor.CUJ_SHADE_APP_LAUNCH_FROM_HISTORY_BUTTON
@@ -148,6 +157,13 @@
notificationActivityStarter.startSettingsIntent(view, settingsIntent)
}
footer.setHistoryButtonClickListener(onClickListener)
+
+ launch {
+ // NOTE: This visibility change is never animated. We also don't need to do anything
+ // special about the onClickListener here, since we're changing the visibility to
+ // GONE so it won't be clickable anyway.
+ viewModel.historyButtonVisible.collect { footer.setHistoryButtonVisible(it) }
+ }
}
private suspend fun bindManageOrHistoryButton(
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/footer/ui/viewmodel/FooterViewModel.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/footer/ui/viewmodel/FooterViewModel.kt
index d8021fa..e724935 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/footer/ui/viewmodel/FooterViewModel.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/footer/ui/viewmodel/FooterViewModel.kt
@@ -95,6 +95,10 @@
.toAnimatedValueFlow(),
)
+ // Settings buttons are not visible when the message is.
+ val settingsButtonVisible: Flow<Boolean> = message.isVisible.map { !it }
+ val historyButtonVisible: Flow<Boolean> = message.isVisible.map { !it }
+
val manageButtonShouldLaunchHistory =
notificationSettingsInteractor.isNotificationHistoryEnabled
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ExpandableNotificationRow.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ExpandableNotificationRow.java
index a4c43a1..aa2a08f 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ExpandableNotificationRow.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ExpandableNotificationRow.java
@@ -116,7 +116,6 @@
import com.android.systemui.statusbar.notification.stack.NotificationChildrenContainerLogger;
import com.android.systemui.statusbar.notification.stack.NotificationStackScrollLayout;
import com.android.systemui.statusbar.notification.stack.SwipeableView;
-import com.android.systemui.statusbar.phone.ExpandHeadsUpOnInlineReply;
import com.android.systemui.statusbar.phone.KeyguardBypassController;
import com.android.systemui.statusbar.policy.HeadsUpManager;
import com.android.systemui.statusbar.policy.InflatedSmartReplyState;
@@ -2948,18 +2947,10 @@
}
public boolean isExpanded(boolean allowOnKeyguard) {
- final boolean isHeadsUpState = ExpandHeadsUpOnInlineReply.isEnabled()
- && canShowHeadsUp() && isHeadsUpState();
- // System expanded should be ignored in pinned heads up state
- final boolean isPinned = isHeadsUpState && isPinned();
- // Heads Up Notification can be expanded when it is pinned.
- final boolean isPinnedAndExpanded =
- isHeadsUpState && isPinnedAndExpanded();
-
return (!shouldShowPublic()) && (!mOnKeyguard || allowOnKeyguard)
- && (!hasUserChangedExpansion() && !isPinned
+ && (!hasUserChangedExpansion()
&& (isSystemExpanded() || isSystemChildExpanded())
- || isUserExpanded() || isPinnedAndExpanded);
+ || isUserExpanded());
}
private boolean isSystemChildExpanded() {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/ui/viewbinder/NotificationListViewBinder.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/ui/viewbinder/NotificationListViewBinder.kt
index fd19f1f..f75c89a 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/ui/viewbinder/NotificationListViewBinder.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/ui/viewbinder/NotificationListViewBinder.kt
@@ -22,7 +22,6 @@
import com.android.app.tracing.TraceUtils.traceAsync
import com.android.internal.logging.MetricsLogger
import com.android.internal.logging.nano.MetricsProto
-import com.android.systemui.Flags
import com.android.systemui.common.ui.ConfigurationState
import com.android.systemui.common.ui.view.setImportantForAccessibilityYesNo
import com.android.systemui.dagger.qualifiers.Background
@@ -40,6 +39,7 @@
import com.android.systemui.statusbar.notification.emptyshade.ui.viewbinder.EmptyShadeViewBinder
import com.android.systemui.statusbar.notification.emptyshade.ui.viewmodel.EmptyShadeViewModel
import com.android.systemui.statusbar.notification.footer.shared.FooterViewRefactor
+import com.android.systemui.statusbar.notification.footer.shared.NotifRedesignFooter
import com.android.systemui.statusbar.notification.footer.ui.view.FooterView
import com.android.systemui.statusbar.notification.footer.ui.viewbinder.FooterViewBinder
import com.android.systemui.statusbar.notification.footer.ui.viewmodel.FooterViewModel
@@ -146,7 +146,7 @@
// The footer needs to be re-inflated every time the theme or the font size changes.
configuration
.inflateLayout<FooterView>(
- if (Flags.notificationsRedesignFooterView())
+ if (NotifRedesignFooter.isEnabled)
R.layout.status_bar_notification_footer_redesign
else R.layout.status_bar_notification_footer,
parentView,
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/ScrimController.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/ScrimController.java
index dc4d66d..e7c6fb4 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/ScrimController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/ScrimController.java
@@ -446,6 +446,7 @@
mStatusBarKeyguardViewManager.onKeyguardFadedAway();
}
dispatchScrimsVisible();
+ dispatchBackScrimState(mScrimBehind.getViewAlpha());
}
};
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarRemoteInputCallback.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarRemoteInputCallback.java
index 200f080..1dc9de4 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarRemoteInputCallback.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarRemoteInputCallback.java
@@ -216,10 +216,19 @@
if (row.isChildInGroup() && !row.areChildrenExpanded()) {
// The group isn't expanded, let's make sure it's visible!
mGroupExpansionManager.toggleGroupExpansion(row.getEntry());
- } else if (!row.isChildInGroup() && !row.isExpanded()) {
- // notification isn't expanded, let's make sure it's visible!
- row.toggleExpansionState();
- row.getPrivateLayout().setOnExpandedVisibleListener(runnable);
+ } else if (!row.isChildInGroup()) {
+ final boolean expandNotification;
+ if (row.isPinned()) {
+ expandNotification = !row.isPinnedAndExpanded();
+ } else {
+ expandNotification = !row.isExpanded();
+ }
+
+ if (expandNotification) {
+ // notification isn't expanded, let's make sure it's expanded!
+ row.toggleExpansionState();
+ row.getPrivateLayout().setOnExpandedVisibleListener(runnable);
+ }
}
} else {
if (row.isChildInGroup() && !row.areChildrenExpanded()) {
diff --git a/packages/SystemUI/src/com/android/systemui/volume/VolumeDialogImpl.java b/packages/SystemUI/src/com/android/systemui/volume/VolumeDialogImpl.java
index 07509e6..639b46a 100644
--- a/packages/SystemUI/src/com/android/systemui/volume/VolumeDialogImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/volume/VolumeDialogImpl.java
@@ -120,9 +120,10 @@
import com.android.systemui.Flags;
import com.android.systemui.Prefs;
import com.android.systemui.dump.DumpManager;
+import com.android.systemui.haptics.slider.HapticSlider;
import com.android.systemui.haptics.slider.HapticSliderViewBinder;
import com.android.systemui.haptics.slider.SeekableSliderTrackerConfig;
-import com.android.systemui.haptics.slider.SeekbarHapticPlugin;
+import com.android.systemui.haptics.slider.HapticSliderPlugin;
import com.android.systemui.haptics.slider.SliderHapticFeedbackConfig;
import com.android.systemui.media.dialog.MediaOutputDialogManager;
import com.android.systemui.plugins.VolumeDialog;
@@ -939,7 +940,7 @@
}
private void addSliderHapticsToRow(VolumeRow row) {
- row.createPlugin(mVibratorHelper, mMSDLPlayer, mSystemClock);
+ row.createPlugin(row.slider, mVibratorHelper, mMSDLPlayer, mSystemClock);
HapticSliderViewBinder.bind(row.slider, row.mHapticPlugin);
}
@@ -2638,7 +2639,7 @@
if (D.BUG) Log.d(TAG, "onStartTrackingTouch"+ " " + mRow.stream);
Events.writeEvent(Events.EVENT_SLIDER_TOUCH_TRACKING, /* startedTracking= */true);
if (mRow.mHapticPlugin != null) {
- mRow.mHapticPlugin.onStartTrackingTouch(seekBar);
+ mRow.mHapticPlugin.onStartTrackingTouch();
}
mController.setActiveStream(mRow.stream);
mRow.tracking = true;
@@ -2649,7 +2650,7 @@
if (D.BUG) Log.d(TAG, "onStopTrackingTouch"+ " " + mRow.stream);
Events.writeEvent(Events.EVENT_SLIDER_TOUCH_TRACKING, /* startedTracking= */false);
if (mRow.mHapticPlugin != null) {
- mRow.mHapticPlugin.onStopTrackingTouch(seekBar);
+ mRow.mHapticPlugin.onStopTrackingTouch();
}
mRow.tracking = false;
mRow.userAttempt = SystemClock.uptimeMillis();
@@ -2726,7 +2727,7 @@
private ObjectAnimator anim; // slider progress animation for non-touch-related updates
private int animTargetProgress;
private int lastAudibleLevel = 1;
- private SeekbarHapticPlugin mHapticPlugin;
+ private HapticSliderPlugin mHapticPlugin;
void setIcon(int iconRes, Resources.Theme theme) {
if (icon != null) {
@@ -2739,15 +2740,17 @@
}
void createPlugin(
+ SeekBar seekBar,
VibratorHelper vibratorHelper,
MSDLPlayer msdlPlayer,
com.android.systemui.util.time.SystemClock systemClock) {
if (mHapticPlugin != null) return;
- mHapticPlugin = new SeekbarHapticPlugin(
+ mHapticPlugin = new HapticSliderPlugin(
vibratorHelper,
msdlPlayer,
systemClock,
+ new HapticSlider.SeekBar(seekBar),
sSliderHapticFeedbackConfig,
sSliderTrackerConfig);
}
@@ -2782,7 +2785,7 @@
boolean deliverOnProgressChangedHaptics(boolean fromUser, int progress) {
if (mHapticPlugin == null) return false;
- mHapticPlugin.onProgressChanged(slider, progress, fromUser);
+ mHapticPlugin.onProgressChanged(progress, fromUser);
if (!fromUser) {
// Consider a change from program as the volume key being continuously pressed
mHapticPlugin.onKeyDown();
diff --git a/packages/SystemUI/src/com/android/systemui/volume/dialog/sliders/ui/VolumeDialogSliderViewBinder.kt b/packages/SystemUI/src/com/android/systemui/volume/dialog/sliders/ui/VolumeDialogSliderViewBinder.kt
index 5c4d53a..3bf8c54 100644
--- a/packages/SystemUI/src/com/android/systemui/volume/dialog/sliders/ui/VolumeDialogSliderViewBinder.kt
+++ b/packages/SystemUI/src/com/android/systemui/volume/dialog/sliders/ui/VolumeDialogSliderViewBinder.kt
@@ -73,6 +73,7 @@
}
private suspend fun VolumeDialogStreamModel.bindToSlider(slider: Slider) {
+ slider.setOnScrollChangeListener { v, scrollX, scrollY, oldScrollX, oldScrollY -> }
with(slider) {
valueFrom = levelMin.toFloat()
valueTo = levelMax.toFloat()
diff --git a/packages/SystemUI/tests/src/com/android/keyguard/KeyguardUpdateMonitorTest.java b/packages/SystemUI/tests/src/com/android/keyguard/KeyguardUpdateMonitorTest.java
index b941fde..3d9eb53 100644
--- a/packages/SystemUI/tests/src/com/android/keyguard/KeyguardUpdateMonitorTest.java
+++ b/packages/SystemUI/tests/src/com/android/keyguard/KeyguardUpdateMonitorTest.java
@@ -2267,6 +2267,23 @@
}
@Test
+ public void isSimPinSecureReturnsFalseWhenEmpty() {
+ assertThat(mKeyguardUpdateMonitor.isSimPinSecure()).isFalse();
+ }
+
+ @Test
+ public void isSimPinSecureReturnsTrueWhenOneSlotIsLocked() {
+ // Slot 0 is locked
+ mKeyguardUpdateMonitor.handleSimStateChange(10, 0,
+ TelephonyManager.SIM_STATE_PIN_REQUIRED);
+ // Slot 1 is not ready
+ mKeyguardUpdateMonitor.handleSimStateChange(11, 1,
+ TelephonyManager.SIM_STATE_NOT_READY);
+
+ assertThat(mKeyguardUpdateMonitor.isSimPinSecure()).isTrue();
+ }
+
+ @Test
public void onAuthEnrollmentChangesCallbacksAreNotified() {
KeyguardUpdateMonitorCallback callback = mock(KeyguardUpdateMonitorCallback.class);
ArgumentCaptor<AuthController.Callback> authCallback = ArgumentCaptor.forClass(
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/ExpandableNotificationRowTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/ExpandableNotificationRowTest.java
index e3e2491..e313a05 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/ExpandableNotificationRowTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/ExpandableNotificationRowTest.java
@@ -71,7 +71,6 @@
import com.android.systemui.statusbar.notification.row.wrapper.NotificationViewWrapper;
import com.android.systemui.statusbar.notification.shared.NotificationContentAlphaOptimization;
import com.android.systemui.statusbar.notification.stack.NotificationChildrenContainer;
-import com.android.systemui.statusbar.phone.ExpandHeadsUpOnInlineReply;
import com.android.systemui.statusbar.phone.KeyguardBypassController;
import org.junit.Assert;
@@ -863,149 +862,6 @@
}
@Test
- @EnableFlags(ExpandHeadsUpOnInlineReply.FLAG_NAME)
- public void isExpanded_HUNsystemExpandedTrueForPinned_notExpanded() throws Exception {
- // GIVEN
- final ExpandableNotificationRow row = mNotificationTestHelper.createRow();
- row.setOnKeyguard(false);
- row.setSystemExpanded(true);
- row.setPinned(true);
- row.setHeadsUp(true);
-
- // THEN
- assertThat(row.isExpanded()).isFalse();
- }
-
- @Test
- @EnableFlags(ExpandHeadsUpOnInlineReply.FLAG_NAME)
- public void isExpanded_HUNsystemExpandedTrueForNotPinned_expanded() throws Exception {
- // GIVEN
- final ExpandableNotificationRow row = mNotificationTestHelper.createRow();
- row.setOnKeyguard(false);
- row.setSystemExpanded(true);
- row.setPinned(false);
- row.setHeadsUp(true);
-
- // THEN
- assertThat(row.isExpanded()).isTrue();
- }
-
- @Test
- @EnableFlags(ExpandHeadsUpOnInlineReply.FLAG_NAME)
- public void isExpanded_HUNDisappearingsystemExpandedTrueForPinned_notExpanded()
- throws Exception {
- // GIVEN
- final ExpandableNotificationRow row = mNotificationTestHelper.createRow();
- row.setOnKeyguard(false);
- row.setSystemExpanded(true);
- row.setPinned(true);
- row.setHeadsUpAnimatingAway(true);
-
- // THEN
- assertThat(row.isExpanded()).isFalse();
- }
-
- @Test
- @EnableFlags(ExpandHeadsUpOnInlineReply.FLAG_NAME)
- public void isExpanded_HUNDisappearingsystemExpandedTrueForNotPinned_expanded()
- throws Exception {
- // GIVEN
- final ExpandableNotificationRow row = mNotificationTestHelper.createRow();
- row.setOnKeyguard(false);
- row.setSystemExpanded(true);
- row.setPinned(false);
- row.setHeadsUpAnimatingAway(true);
-
- // THEN
- assertThat(row.isExpanded()).isTrue();
- }
-
- @Test
- @EnableFlags(ExpandHeadsUpOnInlineReply.FLAG_NAME)
- public void isExpanded_userExpandedTrueForHeadsUp_expanded() throws Exception {
- // GIVEN
- final ExpandableNotificationRow row = mNotificationTestHelper.createRow();
- row.setOnKeyguard(false);
- row.setSystemExpanded(true);
- row.setHeadsUpAnimatingAway(true);
- row.setUserExpanded(true);
-
- // THEN
- assertThat(row.isExpanded()).isTrue();
- }
- @Test
- @EnableFlags(ExpandHeadsUpOnInlineReply.FLAG_NAME)
- public void isExpanded_userExpandedTrueForHeadsUpDisappearRunning_expanded() throws Exception {
- // GIVEN
- final ExpandableNotificationRow row = mNotificationTestHelper.createRow();
- row.setOnKeyguard(false);
- row.setSystemExpanded(true);
- row.setHeadsUpAnimatingAway(true);
- row.setUserExpanded(true);
-
- // THEN
- assertThat(row.isExpanded()).isTrue();
- }
-
- @Test
- @EnableFlags(ExpandHeadsUpOnInlineReply.FLAG_NAME)
- public void isExpanded_userExpandedFalseForHeadsUp_notExpanded() throws Exception {
- // GIVEN
- final ExpandableNotificationRow row = mNotificationTestHelper.createRow();
- row.setOnKeyguard(false);
- row.setSystemExpanded(true);
- row.setHeadsUpAnimatingAway(true);
- row.setUserExpanded(false);
-
- // THEN
- assertThat(row.isExpanded()).isFalse();
- }
- @Test
- @EnableFlags(ExpandHeadsUpOnInlineReply.FLAG_NAME)
- public void isExpanded_userExpandedFalseForHeadsUpDisappearRunning_notExpanded()
- throws Exception {
- // GIVEN
- final ExpandableNotificationRow row = mNotificationTestHelper.createRow();
- row.setOnKeyguard(false);
- row.setSystemExpanded(true);
- row.setHeadsUpAnimatingAway(true);
- row.setUserExpanded(false);
-
- // THEN
- assertThat(row.isExpanded()).isFalse();
- }
-
- @Test
- @EnableFlags(ExpandHeadsUpOnInlineReply.FLAG_NAME)
- public void isExpanded_HUNexpandedWhenPinningTrue_expanded() throws Exception {
- // GIVEN
- final ExpandableNotificationRow row = mNotificationTestHelper.createRow();
- row.setOnKeyguard(false);
- row.setSystemExpanded(true);
- row.setHeadsUp(true);
- row.setPinned(true);
-
- // WHEN
- row.expandNotification();
-
- // THEN
- assertThat(row.isExpanded()).isTrue();
- }
-
- @Test
- @EnableFlags(ExpandHeadsUpOnInlineReply.FLAG_NAME)
- public void isExpanded_HUNexpandedWhenPinningFalse_notExpanded() throws Exception {
- // GIVEN
- final ExpandableNotificationRow row = mNotificationTestHelper.createRow();
- row.setOnKeyguard(false);
- row.setSystemExpanded(false);
- row.setHeadsUp(true);
- row.setPinned(true);
-
- // THEN
- assertThat(row.isExpanded()).isFalse();
- }
- @Test
public void onDisappearAnimationFinished_shouldSetFalse_headsUpAnimatingAway()
throws Exception {
final ExpandableNotificationRow row = mNotificationTestHelper.createRow();
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/ScrimControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/ScrimControllerTest.java
index c639b3a..33a4b7e 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/ScrimControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/ScrimControllerTest.java
@@ -1978,6 +1978,17 @@
}
@Test
+ public void primaryBouncerToGoneOnFinishCallsLightBarController() {
+ reset(mLightBarController);
+ mScrimController.mBouncerToGoneTransition.accept(
+ new TransitionStep(KeyguardState.PRIMARY_BOUNCER, KeyguardState.GONE, 0f,
+ TransitionState.FINISHED, "ScrimControllerTest"));
+
+ verify(mLightBarController).setScrimState(
+ any(ScrimState.class), anyFloat(), any(GradientColors.class));
+ }
+
+ @Test
public void testDoNotAnimateChangeIfOccludeAnimationPlaying() {
mScrimController.setOccludeAnimationPlaying(true);
mScrimController.legacyTransitionTo(ScrimState.UNLOCKED);
diff --git a/services/accessibility/java/com/android/server/accessibility/MouseKeysInterceptor.java b/services/accessibility/java/com/android/server/accessibility/MouseKeysInterceptor.java
index 1df5d1a..1212c75 100644
--- a/services/accessibility/java/com/android/server/accessibility/MouseKeysInterceptor.java
+++ b/services/accessibility/java/com/android/server/accessibility/MouseKeysInterceptor.java
@@ -625,7 +625,9 @@
});
mHandler.removeCallbacksAndMessages(null);
- mVirtualDevice.close();
+ if (mVirtualDevice != null) {
+ mVirtualDevice.close();
+ }
}
@Override
diff --git a/services/companion/java/com/android/server/companion/virtual/SensorController.java b/services/companion/java/com/android/server/companion/virtual/SensorController.java
index 8d075db..88b7910 100644
--- a/services/companion/java/com/android/server/companion/virtual/SensorController.java
+++ b/services/companion/java/com/android/server/companion/virtual/SensorController.java
@@ -256,8 +256,15 @@
Slog.e(TAG, "Received invalid ParcelFileDescriptor");
return BAD_VALUE;
}
+
+ SharedMemory sharedMemory;
+ try {
+ sharedMemory = SharedMemory.fromFileDescriptor(fd);
+ } catch (IllegalArgumentException e) {
+ Slog.e(TAG, "Failed to create shared memory: " + e);
+ return BAD_VALUE;
+ }
final int channelHandle = sNextDirectChannelHandle.getAndIncrement();
- SharedMemory sharedMemory = SharedMemory.fromFileDescriptor(fd);
try {
mCallback.onDirectChannelCreated(channelHandle, sharedMemory);
} catch (RemoteException e) {
diff --git a/services/core/java/com/android/server/integrity/parser/RuleBinaryParser.java b/services/core/java/com/android/server/integrity/parser/RuleBinaryParser.java
deleted file mode 100644
index ea3a3d5..0000000
--- a/services/core/java/com/android/server/integrity/parser/RuleBinaryParser.java
+++ /dev/null
@@ -1,193 +0,0 @@
-/*
- * Copyright (C) 2019 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.integrity.parser;
-
-import static com.android.server.integrity.model.ComponentBitSize.ATOMIC_FORMULA_START;
-import static com.android.server.integrity.model.ComponentBitSize.BYTE_BITS;
-import static com.android.server.integrity.model.ComponentBitSize.COMPOUND_FORMULA_END;
-import static com.android.server.integrity.model.ComponentBitSize.COMPOUND_FORMULA_START;
-import static com.android.server.integrity.model.ComponentBitSize.CONNECTOR_BITS;
-import static com.android.server.integrity.model.ComponentBitSize.EFFECT_BITS;
-import static com.android.server.integrity.model.ComponentBitSize.FORMAT_VERSION_BITS;
-import static com.android.server.integrity.model.ComponentBitSize.INSTALLER_ALLOWED_BY_MANIFEST_START;
-import static com.android.server.integrity.model.ComponentBitSize.IS_HASHED_BITS;
-import static com.android.server.integrity.model.ComponentBitSize.KEY_BITS;
-import static com.android.server.integrity.model.ComponentBitSize.OPERATOR_BITS;
-import static com.android.server.integrity.model.ComponentBitSize.SEPARATOR_BITS;
-import static com.android.server.integrity.model.ComponentBitSize.SIGNAL_BIT;
-import static com.android.server.integrity.model.ComponentBitSize.VALUE_SIZE_BITS;
-import static com.android.server.integrity.parser.BinaryFileOperations.getBooleanValue;
-import static com.android.server.integrity.parser.BinaryFileOperations.getIntValue;
-import static com.android.server.integrity.parser.BinaryFileOperations.getStringValue;
-
-import android.content.integrity.AtomicFormula;
-import android.content.integrity.CompoundFormula;
-import android.content.integrity.InstallerAllowedByManifestFormula;
-import android.content.integrity.IntegrityFormula;
-import android.content.integrity.Rule;
-
-import com.android.server.integrity.model.BitInputStream;
-
-import java.io.BufferedInputStream;
-import java.io.IOException;
-import java.util.ArrayList;
-import java.util.Collections;
-import java.util.List;
-
-/** A helper class to parse rules into the {@link Rule} model from Binary representation. */
-public class RuleBinaryParser implements RuleParser {
-
- @Override
- public List<Rule> parse(byte[] ruleBytes) throws RuleParseException {
- return parse(RandomAccessObject.ofBytes(ruleBytes), Collections.emptyList());
- }
-
- @Override
- public List<Rule> parse(RandomAccessObject randomAccessObject, List<RuleIndexRange> indexRanges)
- throws RuleParseException {
- try (RandomAccessInputStream randomAccessInputStream =
- new RandomAccessInputStream(randomAccessObject)) {
- return parseRules(randomAccessInputStream, indexRanges);
- } catch (Exception e) {
- throw new RuleParseException(e.getMessage(), e);
- }
- }
-
- private List<Rule> parseRules(
- RandomAccessInputStream randomAccessInputStream, List<RuleIndexRange> indexRanges)
- throws IOException {
-
- // Read the rule binary file format version.
- randomAccessInputStream.skip(FORMAT_VERSION_BITS / BYTE_BITS);
-
- return indexRanges.isEmpty()
- ? parseAllRules(randomAccessInputStream)
- : parseIndexedRules(randomAccessInputStream, indexRanges);
- }
-
- private List<Rule> parseAllRules(RandomAccessInputStream randomAccessInputStream)
- throws IOException {
- List<Rule> parsedRules = new ArrayList<>();
-
- BitInputStream inputStream =
- new BitInputStream(new BufferedInputStream(randomAccessInputStream));
- while (inputStream.hasNext()) {
- if (inputStream.getNext(SIGNAL_BIT) == 1) {
- parsedRules.add(parseRule(inputStream));
- }
- }
-
- return parsedRules;
- }
-
- private List<Rule> parseIndexedRules(
- RandomAccessInputStream randomAccessInputStream, List<RuleIndexRange> indexRanges)
- throws IOException {
- List<Rule> parsedRules = new ArrayList<>();
-
- for (RuleIndexRange range : indexRanges) {
- randomAccessInputStream.seek(range.getStartIndex());
-
- BitInputStream inputStream =
- new BitInputStream(
- new BufferedInputStream(
- new LimitInputStream(
- randomAccessInputStream,
- range.getEndIndex() - range.getStartIndex())));
-
- // Read the rules until we reach the end index. available() here is not reliable.
- while (inputStream.hasNext()) {
- if (inputStream.getNext(SIGNAL_BIT) == 1) {
- parsedRules.add(parseRule(inputStream));
- }
- }
- }
-
- return parsedRules;
- }
-
- private Rule parseRule(BitInputStream bitInputStream) throws IOException {
- IntegrityFormula formula = parseFormula(bitInputStream);
- int effect = bitInputStream.getNext(EFFECT_BITS);
-
- if (bitInputStream.getNext(SIGNAL_BIT) != 1) {
- throw new IllegalArgumentException("A rule must end with a '1' bit.");
- }
-
- return new Rule(formula, effect);
- }
-
- private IntegrityFormula parseFormula(BitInputStream bitInputStream) throws IOException {
- int separator = bitInputStream.getNext(SEPARATOR_BITS);
- switch (separator) {
- case ATOMIC_FORMULA_START:
- return parseAtomicFormula(bitInputStream);
- case COMPOUND_FORMULA_START:
- return parseCompoundFormula(bitInputStream);
- case COMPOUND_FORMULA_END:
- return null;
- case INSTALLER_ALLOWED_BY_MANIFEST_START:
- return new InstallerAllowedByManifestFormula();
- default:
- throw new IllegalArgumentException(
- String.format("Unknown formula separator: %s", separator));
- }
- }
-
- private CompoundFormula parseCompoundFormula(BitInputStream bitInputStream) throws IOException {
- int connector = bitInputStream.getNext(CONNECTOR_BITS);
- List<IntegrityFormula> formulas = new ArrayList<>();
-
- IntegrityFormula parsedFormula = parseFormula(bitInputStream);
- while (parsedFormula != null) {
- formulas.add(parsedFormula);
- parsedFormula = parseFormula(bitInputStream);
- }
-
- return new CompoundFormula(connector, formulas);
- }
-
- private AtomicFormula parseAtomicFormula(BitInputStream bitInputStream) throws IOException {
- int key = bitInputStream.getNext(KEY_BITS);
- int operator = bitInputStream.getNext(OPERATOR_BITS);
-
- switch (key) {
- case AtomicFormula.PACKAGE_NAME:
- case AtomicFormula.APP_CERTIFICATE:
- case AtomicFormula.APP_CERTIFICATE_LINEAGE:
- case AtomicFormula.INSTALLER_NAME:
- case AtomicFormula.INSTALLER_CERTIFICATE:
- case AtomicFormula.STAMP_CERTIFICATE_HASH:
- boolean isHashedValue = bitInputStream.getNext(IS_HASHED_BITS) == 1;
- int valueSize = bitInputStream.getNext(VALUE_SIZE_BITS);
- String stringValue = getStringValue(bitInputStream, valueSize, isHashedValue);
- return new AtomicFormula.StringAtomicFormula(key, stringValue, isHashedValue);
- case AtomicFormula.VERSION_CODE:
- // TODO(b/147880712): temporary hack until our input handles long
- long upper = getIntValue(bitInputStream);
- long lower = getIntValue(bitInputStream);
- long longValue = (upper << 32) | lower;
- return new AtomicFormula.LongAtomicFormula(key, operator, longValue);
- case AtomicFormula.PRE_INSTALLED:
- case AtomicFormula.STAMP_TRUSTED:
- boolean booleanValue = getBooleanValue(bitInputStream);
- return new AtomicFormula.BooleanAtomicFormula(key, booleanValue);
- default:
- throw new IllegalArgumentException(String.format("Unknown key: %d", key));
- }
- }
-}
diff --git a/services/core/java/com/android/server/notification/NotificationAttentionHelper.java b/services/core/java/com/android/server/notification/NotificationAttentionHelper.java
index 25741bc..0e390b6 100644
--- a/services/core/java/com/android/server/notification/NotificationAttentionHelper.java
+++ b/services/core/java/com/android/server/notification/NotificationAttentionHelper.java
@@ -1690,6 +1690,9 @@
@Override
public void onReceive(Context context, Intent intent) {
String action = intent.getAction();
+ if (action == null) {
+ return;
+ }
if (action.equals(Intent.ACTION_SCREEN_ON)) {
// Keep track of screen on/off state, but do not turn off the notification light
diff --git a/services/core/java/com/android/server/notification/TimeToLiveHelper.java b/services/core/java/com/android/server/notification/TimeToLiveHelper.java
index cabe766..b053dfe 100644
--- a/services/core/java/com/android/server/notification/TimeToLiveHelper.java
+++ b/services/core/java/com/android/server/notification/TimeToLiveHelper.java
@@ -188,7 +188,11 @@
timeoutKey = earliest.second;
}
}
- mNm.timeoutNotification(timeoutKey);
+ if (timeoutKey != null) {
+ mNm.timeoutNotification(timeoutKey);
+ } else {
+ Slog.wtf(TAG, "Alarm triggered but should have been cleaned up already");
+ }
}
}
};
diff --git a/services/core/java/com/android/server/wm/DisplayContent.java b/services/core/java/com/android/server/wm/DisplayContent.java
index d6ded51..aac756f 100644
--- a/services/core/java/com/android/server/wm/DisplayContent.java
+++ b/services/core/java/com/android/server/wm/DisplayContent.java
@@ -6923,27 +6923,25 @@
return;
}
if (mFixedRotationLaunchingApp.hasFixedRotationTransform(r)) {
+ if (!r.isVisible()) {
+ // Let the opening activity update orientation.
+ return;
+ }
if (mFixedRotationLaunchingApp.hasAnimatingFixedRotationTransition()) {
// Waiting until all of the associated activities have done animation, or the
// orientation would be updated too early and cause flickering.
return;
}
} else {
- // Handle a corner case that the task of {@link #mFixedRotationLaunchingApp} is no
- // longer animating but the corresponding transition finished event won't notify.
- // E.g. activity A transferred starting window to B, only A will receive transition
- // finished event. A doesn't have fixed rotation but B is the rotated launching app.
- final Task task = r.getTask();
- if (task != mFixedRotationLaunchingApp.getTask()
+ // Check to skip updating display orientation by a non-top activity.
+ if ((!r.isVisible() || !mFixedRotationLaunchingApp.fillsParent())
// When closing a translucent task A (r.fillsParent() is false) to a
// visible task B, because only A has visibility change, there is only A's
// transition callback. Then it still needs to update orientation for B.
- && (!mWmService.mFlags.mRespectNonTopVisibleFixedOrientation
- || r.fillsParent())) {
- // Different tasks won't be in one activity transition animation.
+ && r.fillsParent()) {
return;
}
- if (task.getActivity(ActivityRecord::isInTransition) != null) {
+ if (r.inTransition()) {
return;
// Continue to update orientation because the transition of the top rotated
// launching activity is done.
diff --git a/services/profcollect/src/com/android/server/profcollect/ProfcollectForwardingService.java b/services/profcollect/src/com/android/server/profcollect/ProfcollectForwardingService.java
index 42c171b..4e86888 100644
--- a/services/profcollect/src/com/android/server/profcollect/ProfcollectForwardingService.java
+++ b/services/profcollect/src/com/android/server/profcollect/ProfcollectForwardingService.java
@@ -16,6 +16,8 @@
package com.android.server.profcollect;
+import android.Manifest;
+import android.annotation.RequiresPermission;
import android.app.job.JobInfo;
import android.app.job.JobParameters;
import android.app.job.JobScheduler;
@@ -88,10 +90,11 @@
createAndUploadReport(sSelfService);
}
if (UsbManager.ACTION_USB_STATE.equals(intent.getAction())) {
- boolean connected = intent.getBooleanExtra(UsbManager.USB_CONNECTED, false);
boolean isADB = intent.getBooleanExtra(UsbManager.USB_FUNCTION_ADB, false);
if (isADB) {
- Log.d(LOG_TAG, "Received broadcast that ADB became " + connected);
+ boolean connected = intent.getBooleanExtra(UsbManager.USB_CONNECTED, false);
+ Log.d(LOG_TAG, "Received broadcast that ADB became " + connected
+ + ", was " + mAdbActive);
mAdbActive = connected;
}
}
@@ -117,9 +120,6 @@
mUploadEnabled =
context.getResources().getBoolean(R.bool.config_profcollectReportUploaderEnabled);
- // TODO: ADB might already be active when our service started.
- mAdbActive = false;
-
final IntentFilter filter = new IntentFilter();
filter.addAction(INTENT_UPLOAD_PROFILES);
filter.addAction(UsbManager.ACTION_USB_STATE);
@@ -140,7 +140,13 @@
}
@Override
+ @RequiresPermission(Manifest.permission.MANAGE_USB)
public void onBootPhase(int phase) {
+ if (phase == PHASE_SYSTEM_SERVICES_READY) {
+ UsbManager usbManager = getContext().getSystemService(UsbManager.class);
+ mAdbActive = ((usbManager.getCurrentFunctions() & UsbManager.FUNCTION_ADB) == 1);
+ Log.d(LOG_TAG, "ADB is " + mAdbActive + " on system startup");
+ }
if (phase == PHASE_BOOT_COMPLETED) {
if (mIProfcollect == null) {
return;
diff --git a/services/tests/servicestests/src/com/android/server/integrity/parser/RuleBinaryParserTest.java b/services/tests/servicestests/src/com/android/server/integrity/parser/RuleBinaryParserTest.java
deleted file mode 100644
index 03363a1..0000000
--- a/services/tests/servicestests/src/com/android/server/integrity/parser/RuleBinaryParserTest.java
+++ /dev/null
@@ -1,693 +0,0 @@
-/*
- * Copyright (C) 2019 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.integrity.parser;
-
-import static com.android.server.integrity.model.ComponentBitSize.ATOMIC_FORMULA_START;
-import static com.android.server.integrity.model.ComponentBitSize.COMPOUND_FORMULA_END;
-import static com.android.server.integrity.model.ComponentBitSize.COMPOUND_FORMULA_START;
-import static com.android.server.integrity.model.ComponentBitSize.CONNECTOR_BITS;
-import static com.android.server.integrity.model.ComponentBitSize.DEFAULT_FORMAT_VERSION;
-import static com.android.server.integrity.model.ComponentBitSize.EFFECT_BITS;
-import static com.android.server.integrity.model.ComponentBitSize.FORMAT_VERSION_BITS;
-import static com.android.server.integrity.model.ComponentBitSize.KEY_BITS;
-import static com.android.server.integrity.model.ComponentBitSize.OPERATOR_BITS;
-import static com.android.server.integrity.model.ComponentBitSize.SEPARATOR_BITS;
-import static com.android.server.integrity.model.ComponentBitSize.VALUE_SIZE_BITS;
-import static com.android.server.integrity.utils.TestUtils.getBits;
-import static com.android.server.integrity.utils.TestUtils.getBytes;
-import static com.android.server.integrity.utils.TestUtils.getValueBits;
-import static com.android.server.testutils.TestUtils.assertExpectException;
-
-import static com.google.common.truth.Truth.assertThat;
-
-import android.content.integrity.AtomicFormula;
-import android.content.integrity.CompoundFormula;
-import android.content.integrity.IntegrityUtils;
-import android.content.integrity.Rule;
-
-import org.junit.Test;
-import org.junit.runner.RunWith;
-import org.junit.runners.JUnit4;
-
-import java.nio.ByteBuffer;
-import java.nio.charset.StandardCharsets;
-import java.util.Arrays;
-import java.util.Collections;
-import java.util.List;
-
-@RunWith(JUnit4.class)
-public class RuleBinaryParserTest {
-
- private static final String COMPOUND_FORMULA_START_BITS =
- getBits(COMPOUND_FORMULA_START, SEPARATOR_BITS);
- private static final String COMPOUND_FORMULA_END_BITS =
- getBits(COMPOUND_FORMULA_END, SEPARATOR_BITS);
- private static final String ATOMIC_FORMULA_START_BITS =
- getBits(ATOMIC_FORMULA_START, SEPARATOR_BITS);
- private static final int INVALID_FORMULA_SEPARATOR_VALUE = (1 << SEPARATOR_BITS) - 1;
- private static final String INVALID_FORMULA_SEPARATOR_BITS =
- getBits(INVALID_FORMULA_SEPARATOR_VALUE, SEPARATOR_BITS);
-
- private static final String NOT = getBits(CompoundFormula.NOT, CONNECTOR_BITS);
- private static final String AND = getBits(CompoundFormula.AND, CONNECTOR_BITS);
- private static final String OR = getBits(CompoundFormula.OR, CONNECTOR_BITS);
- private static final int INVALID_CONNECTOR_VALUE = 3;
- private static final String INVALID_CONNECTOR =
- getBits(INVALID_CONNECTOR_VALUE, CONNECTOR_BITS);
-
- private static final String PACKAGE_NAME = getBits(AtomicFormula.PACKAGE_NAME, KEY_BITS);
- private static final String APP_CERTIFICATE = getBits(AtomicFormula.APP_CERTIFICATE, KEY_BITS);
- private static final String APP_CERTIFICATE_LINEAGE =
- getBits(AtomicFormula.APP_CERTIFICATE_LINEAGE, KEY_BITS);
- private static final String VERSION_CODE = getBits(AtomicFormula.VERSION_CODE, KEY_BITS);
- private static final String PRE_INSTALLED = getBits(AtomicFormula.PRE_INSTALLED, KEY_BITS);
- private static final int INVALID_KEY_VALUE = 9;
- private static final String INVALID_KEY = getBits(INVALID_KEY_VALUE, KEY_BITS);
-
- private static final String EQ = getBits(AtomicFormula.EQ, OPERATOR_BITS);
- private static final int INVALID_OPERATOR_VALUE = 5;
- private static final String INVALID_OPERATOR = getBits(INVALID_OPERATOR_VALUE, OPERATOR_BITS);
-
- private static final String IS_NOT_HASHED = "0";
- private static final String IS_HASHED = "1";
-
- private static final String DENY = getBits(Rule.DENY, EFFECT_BITS);
- private static final int INVALID_EFFECT_VALUE = 5;
- private static final String INVALID_EFFECT = getBits(INVALID_EFFECT_VALUE, EFFECT_BITS);
-
- private static final String START_BIT = "1";
- private static final String END_BIT = "1";
- private static final String INVALID_MARKER_BIT = "0";
-
- private static final byte[] DEFAULT_FORMAT_VERSION_BYTES =
- getBytes(getBits(DEFAULT_FORMAT_VERSION, FORMAT_VERSION_BITS));
-
- private static final List<RuleIndexRange> NO_INDEXING = Collections.emptyList();
-
- @Test
- public void testBinaryStream_validCompoundFormula_noIndexing() throws Exception {
- String packageName = "com.test.app";
- String ruleBits =
- START_BIT
- + COMPOUND_FORMULA_START_BITS
- + NOT
- + ATOMIC_FORMULA_START_BITS
- + PACKAGE_NAME
- + EQ
- + IS_NOT_HASHED
- + getBits(packageName.length(), VALUE_SIZE_BITS)
- + getValueBits(packageName)
- + COMPOUND_FORMULA_END_BITS
- + DENY
- + END_BIT;
- byte[] ruleBytes = getBytes(ruleBits);
- ByteBuffer rule =
- ByteBuffer.allocate(DEFAULT_FORMAT_VERSION_BYTES.length + ruleBytes.length);
- rule.put(DEFAULT_FORMAT_VERSION_BYTES);
- rule.put(ruleBytes);
- RuleParser binaryParser = new RuleBinaryParser();
- Rule expectedRule =
- new Rule(
- new CompoundFormula(
- CompoundFormula.NOT,
- Collections.singletonList(
- new AtomicFormula.StringAtomicFormula(
- AtomicFormula.PACKAGE_NAME,
- packageName,
- /* isHashedValue= */ false))),
- Rule.DENY);
-
- List<Rule> rules =
- binaryParser.parse(RandomAccessObject.ofBytes(rule.array()), NO_INDEXING);
-
- assertThat(rules).isEqualTo(Collections.singletonList(expectedRule));
- }
-
- @Test
- public void testBinaryString_validCompoundFormula_notConnector_noIndexing() throws Exception {
- String packageName = "com.test.app";
- String ruleBits =
- START_BIT
- + COMPOUND_FORMULA_START_BITS
- + NOT
- + ATOMIC_FORMULA_START_BITS
- + PACKAGE_NAME
- + EQ
- + IS_NOT_HASHED
- + getBits(packageName.length(), VALUE_SIZE_BITS)
- + getValueBits(packageName)
- + COMPOUND_FORMULA_END_BITS
- + DENY
- + END_BIT;
- byte[] ruleBytes = getBytes(ruleBits);
- ByteBuffer rule =
- ByteBuffer.allocate(DEFAULT_FORMAT_VERSION_BYTES.length + ruleBytes.length);
- rule.put(DEFAULT_FORMAT_VERSION_BYTES);
- rule.put(ruleBytes);
- RuleParser binaryParser = new RuleBinaryParser();
- Rule expectedRule =
- new Rule(
- new CompoundFormula(
- CompoundFormula.NOT,
- Collections.singletonList(
- new AtomicFormula.StringAtomicFormula(
- AtomicFormula.PACKAGE_NAME,
- packageName,
- /* isHashedValue= */ false))),
- Rule.DENY);
-
- List<Rule> rules = binaryParser.parse(rule.array());
-
- assertThat(rules).isEqualTo(Collections.singletonList(expectedRule));
- }
-
- @Test
- public void testBinaryString_validCompoundFormula_andConnector_noIndexing() throws Exception {
- String packageName = "com.test.app";
- String appCertificate = "test_cert";
- String ruleBits =
- START_BIT
- + COMPOUND_FORMULA_START_BITS
- + AND
- + ATOMIC_FORMULA_START_BITS
- + PACKAGE_NAME
- + EQ
- + IS_NOT_HASHED
- + getBits(packageName.length(), VALUE_SIZE_BITS)
- + getValueBits(packageName)
- + ATOMIC_FORMULA_START_BITS
- + APP_CERTIFICATE
- + EQ
- + IS_NOT_HASHED
- + getBits(appCertificate.length(), VALUE_SIZE_BITS)
- + getValueBits(appCertificate)
- + COMPOUND_FORMULA_END_BITS
- + DENY
- + END_BIT;
- byte[] ruleBytes = getBytes(ruleBits);
- ByteBuffer rule =
- ByteBuffer.allocate(DEFAULT_FORMAT_VERSION_BYTES.length + ruleBytes.length);
- rule.put(DEFAULT_FORMAT_VERSION_BYTES);
- rule.put(ruleBytes);
- RuleParser binaryParser = new RuleBinaryParser();
- Rule expectedRule =
- new Rule(
- new CompoundFormula(
- CompoundFormula.AND,
- Arrays.asList(
- new AtomicFormula.StringAtomicFormula(
- AtomicFormula.PACKAGE_NAME,
- packageName,
- /* isHashedValue= */ false),
- new AtomicFormula.StringAtomicFormula(
- AtomicFormula.APP_CERTIFICATE,
- appCertificate,
- /* isHashedValue= */ false))),
- Rule.DENY);
- List<Rule> rules = binaryParser.parse(rule.array());
-
- assertThat(rules).isEqualTo(Collections.singletonList(expectedRule));
- }
-
- @Test
- public void testBinaryString_validCompoundFormula_orConnector_noIndexing() throws Exception {
- String packageName = "com.test.app";
- String appCertificate = "test_cert";
- String ruleBits =
- START_BIT
- + COMPOUND_FORMULA_START_BITS
- + OR
- + ATOMIC_FORMULA_START_BITS
- + PACKAGE_NAME
- + EQ
- + IS_NOT_HASHED
- + getBits(packageName.length(), VALUE_SIZE_BITS)
- + getValueBits(packageName)
- + ATOMIC_FORMULA_START_BITS
- + APP_CERTIFICATE
- + EQ
- + IS_NOT_HASHED
- + getBits(appCertificate.length(), VALUE_SIZE_BITS)
- + getValueBits(appCertificate)
- + COMPOUND_FORMULA_END_BITS
- + DENY
- + END_BIT;
- byte[] ruleBytes = getBytes(ruleBits);
- ByteBuffer rule =
- ByteBuffer.allocate(DEFAULT_FORMAT_VERSION_BYTES.length + ruleBytes.length);
- rule.put(DEFAULT_FORMAT_VERSION_BYTES);
- rule.put(ruleBytes);
- RuleParser binaryParser = new RuleBinaryParser();
- Rule expectedRule =
- new Rule(
- new CompoundFormula(
- CompoundFormula.OR,
- Arrays.asList(
- new AtomicFormula.StringAtomicFormula(
- AtomicFormula.PACKAGE_NAME,
- packageName,
- /* isHashedValue= */ false),
- new AtomicFormula.StringAtomicFormula(
- AtomicFormula.APP_CERTIFICATE,
- appCertificate,
- /* isHashedValue= */ false))),
- Rule.DENY);
-
- List<Rule> rules = binaryParser.parse(rule.array());
-
- assertThat(rules).isEqualTo(Collections.singletonList(expectedRule));
- }
-
- @Test
- public void testBinaryString_validAtomicFormula_stringValue_noIndexing() throws Exception {
- String packageName = "com.test.app";
- String ruleBits =
- START_BIT
- + ATOMIC_FORMULA_START_BITS
- + PACKAGE_NAME
- + EQ
- + IS_NOT_HASHED
- + getBits(packageName.length(), VALUE_SIZE_BITS)
- + getValueBits(packageName)
- + DENY
- + END_BIT;
- byte[] ruleBytes = getBytes(ruleBits);
- ByteBuffer rule =
- ByteBuffer.allocate(DEFAULT_FORMAT_VERSION_BYTES.length + ruleBytes.length);
- rule.put(DEFAULT_FORMAT_VERSION_BYTES);
- rule.put(ruleBytes);
- RuleParser binaryParser = new RuleBinaryParser();
- Rule expectedRule =
- new Rule(
- new AtomicFormula.StringAtomicFormula(
- AtomicFormula.PACKAGE_NAME,
- packageName,
- /* isHashedValue= */ false),
- Rule.DENY);
-
- List<Rule> rules = binaryParser.parse(rule.array());
-
- assertThat(rules).isEqualTo(Collections.singletonList(expectedRule));
- }
-
- @Test
- public void testBinaryString_validAtomicFormula_hashedValue_noIndexing() throws Exception {
- String appCertificate = "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA";
- String ruleBits =
- START_BIT
- + ATOMIC_FORMULA_START_BITS
- + APP_CERTIFICATE
- + EQ
- + IS_HASHED
- + getBits(appCertificate.length(), VALUE_SIZE_BITS)
- + getValueBits(appCertificate)
- + DENY
- + END_BIT;
- byte[] ruleBytes = getBytes(ruleBits);
- ByteBuffer rule =
- ByteBuffer.allocate(DEFAULT_FORMAT_VERSION_BYTES.length + ruleBytes.length);
- rule.put(DEFAULT_FORMAT_VERSION_BYTES);
- rule.put(ruleBytes);
-
- RuleParser binaryParser = new RuleBinaryParser();
- Rule expectedRule =
- new Rule(
- new AtomicFormula.StringAtomicFormula(
- AtomicFormula.APP_CERTIFICATE,
- IntegrityUtils.getHexDigest(
- appCertificate.getBytes(StandardCharsets.UTF_8)),
- /* isHashedValue= */ true),
- Rule.DENY);
-
- List<Rule> rules = binaryParser.parse(rule.array());
-
- assertThat(rules).isEqualTo(Collections.singletonList(expectedRule));
- }
-
- @Test
- public void testBinaryString_validAtomicFormulaWithCertificateLineage() throws Exception {
- String appCertificate = "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA";
- String ruleBits =
- START_BIT
- + ATOMIC_FORMULA_START_BITS
- + APP_CERTIFICATE_LINEAGE
- + EQ
- + IS_HASHED
- + getBits(appCertificate.length(), VALUE_SIZE_BITS)
- + getValueBits(appCertificate)
- + DENY
- + END_BIT;
- byte[] ruleBytes = getBytes(ruleBits);
- ByteBuffer rule =
- ByteBuffer.allocate(DEFAULT_FORMAT_VERSION_BYTES.length + ruleBytes.length);
- rule.put(DEFAULT_FORMAT_VERSION_BYTES);
- rule.put(ruleBytes);
-
- RuleParser binaryParser = new RuleBinaryParser();
- Rule expectedRule =
- new Rule(
- new AtomicFormula.StringAtomicFormula(
- AtomicFormula.APP_CERTIFICATE_LINEAGE,
- IntegrityUtils.getHexDigest(
- appCertificate.getBytes(StandardCharsets.UTF_8)),
- /* isHashedValue= */ true),
- Rule.DENY);
-
- List<Rule> rules = binaryParser.parse(rule.array());
-
- assertThat(rules).isEqualTo(Collections.singletonList(expectedRule));
- }
-
- @Test
- public void testBinaryString_validAtomicFormula_integerValue_noIndexing() throws Exception {
- int versionCode = 1;
- String ruleBits =
- START_BIT
- + ATOMIC_FORMULA_START_BITS
- + VERSION_CODE
- + EQ
- + getBits(versionCode, /* numOfBits= */ 64)
- + DENY
- + END_BIT;
- byte[] ruleBytes = getBytes(ruleBits);
- ByteBuffer rule =
- ByteBuffer.allocate(DEFAULT_FORMAT_VERSION_BYTES.length + ruleBytes.length);
- rule.put(DEFAULT_FORMAT_VERSION_BYTES);
- rule.put(ruleBytes);
- RuleParser binaryParser = new RuleBinaryParser();
- Rule expectedRule =
- new Rule(
- new AtomicFormula.LongAtomicFormula(
- AtomicFormula.VERSION_CODE, AtomicFormula.EQ, 1),
- Rule.DENY);
-
- List<Rule> rules = binaryParser.parse(rule.array());
-
- assertThat(rules).isEqualTo(Collections.singletonList(expectedRule));
- }
-
- @Test
- public void testBinaryString_validAtomicFormula_booleanValue_noIndexing() throws Exception {
- String isPreInstalled = "1";
- String ruleBits =
- START_BIT
- + ATOMIC_FORMULA_START_BITS
- + PRE_INSTALLED
- + EQ
- + isPreInstalled
- + DENY
- + END_BIT;
- byte[] ruleBytes = getBytes(ruleBits);
- ByteBuffer rule =
- ByteBuffer.allocate(DEFAULT_FORMAT_VERSION_BYTES.length + ruleBytes.length);
- rule.put(DEFAULT_FORMAT_VERSION_BYTES);
- rule.put(ruleBytes);
- RuleParser binaryParser = new RuleBinaryParser();
- Rule expectedRule =
- new Rule(
- new AtomicFormula.BooleanAtomicFormula(
- AtomicFormula.PRE_INSTALLED, true),
- Rule.DENY);
-
- List<Rule> rules = binaryParser.parse(rule.array());
-
- assertThat(rules).isEqualTo(Collections.singletonList(expectedRule));
- }
-
- @Test
- public void testBinaryString_invalidAtomicFormula_noIndexing() {
- int versionCode = 1;
- String ruleBits =
- START_BIT
- + ATOMIC_FORMULA_START_BITS
- + VERSION_CODE
- + EQ
- + getBits(versionCode, /* numOfBits= */ 64)
- + DENY;
- byte[] ruleBytes = getBytes(ruleBits);
- ByteBuffer rule =
- ByteBuffer.allocate(DEFAULT_FORMAT_VERSION_BYTES.length + ruleBytes.length);
- rule.put(DEFAULT_FORMAT_VERSION_BYTES);
- rule.put(ruleBytes);
- RuleParser binaryParser = new RuleBinaryParser();
-
- assertExpectException(
- RuleParseException.class,
- /* expectedExceptionMessageRegex= */ "A rule must end with a '1' bit.",
- () -> binaryParser.parse(rule.array()));
- }
-
- @Test
- public void testBinaryString_withNoRuleList_noIndexing() throws RuleParseException {
- ByteBuffer rule = ByteBuffer.allocate(DEFAULT_FORMAT_VERSION_BYTES.length);
- rule.put(DEFAULT_FORMAT_VERSION_BYTES);
- RuleParser binaryParser = new RuleBinaryParser();
-
- List<Rule> rules = binaryParser.parse(rule.array());
-
- assertThat(rules).isEmpty();
- }
-
- @Test
- public void testBinaryString_withEmptyRule_noIndexing() {
- String ruleBits = START_BIT;
- byte[] ruleBytes = getBytes(ruleBits);
- ByteBuffer rule =
- ByteBuffer.allocate(DEFAULT_FORMAT_VERSION_BYTES.length + ruleBytes.length);
- rule.put(DEFAULT_FORMAT_VERSION_BYTES);
- rule.put(ruleBytes);
- RuleParser binaryParser = new RuleBinaryParser();
-
- assertExpectException(
- RuleParseException.class,
- /* expectedExceptionMessageRegex */ "",
- () -> binaryParser.parse(rule.array()));
- }
-
- @Test
- public void testBinaryString_invalidCompoundFormula_invalidNumberOfFormulas_noIndexing() {
- String packageName = "com.test.app";
- String appCertificate = "test_cert";
- String ruleBits =
- START_BIT
- + COMPOUND_FORMULA_START_BITS
- + NOT
- + ATOMIC_FORMULA_START_BITS
- + PACKAGE_NAME
- + EQ
- + IS_NOT_HASHED
- + getBits(packageName.length(), VALUE_SIZE_BITS)
- + getValueBits(packageName)
- + ATOMIC_FORMULA_START_BITS
- + APP_CERTIFICATE
- + EQ
- + IS_NOT_HASHED
- + getBits(appCertificate.length(), VALUE_SIZE_BITS)
- + getValueBits(appCertificate)
- + COMPOUND_FORMULA_END_BITS
- + DENY
- + END_BIT;
- byte[] ruleBytes = getBytes(ruleBits);
- ByteBuffer rule =
- ByteBuffer.allocate(DEFAULT_FORMAT_VERSION_BYTES.length + ruleBytes.length);
- rule.put(DEFAULT_FORMAT_VERSION_BYTES);
- rule.put(ruleBytes);
- RuleParser binaryParser = new RuleBinaryParser();
-
- assertExpectException(
- RuleParseException.class,
- /* expectedExceptionMessageRegex */ "Connector NOT must have 1 formula only",
- () -> binaryParser.parse(rule.array()));
- }
-
- @Test
- public void testBinaryString_invalidRule_invalidOperator_noIndexing() {
- int versionCode = 1;
- String ruleBits =
- START_BIT
- + COMPOUND_FORMULA_START_BITS
- + NOT
- + ATOMIC_FORMULA_START_BITS
- + VERSION_CODE
- + INVALID_OPERATOR
- + getBits(versionCode, /* numOfBits= */ 64)
- + COMPOUND_FORMULA_END_BITS
- + DENY
- + END_BIT;
- byte[] ruleBytes = getBytes(ruleBits);
- ByteBuffer rule =
- ByteBuffer.allocate(DEFAULT_FORMAT_VERSION_BYTES.length + ruleBytes.length);
- rule.put(DEFAULT_FORMAT_VERSION_BYTES);
- rule.put(ruleBytes);
- RuleParser binaryParser = new RuleBinaryParser();
-
- assertExpectException(
- RuleParseException.class,
- /* expectedExceptionMessageRegex */ String.format(
- "Unknown operator: %d", INVALID_OPERATOR_VALUE),
- () -> binaryParser.parse(rule.array()));
- }
-
- @Test
- public void testBinaryString_invalidRule_invalidEffect_noIndexing() {
- String packageName = "com.test.app";
- String ruleBits =
- START_BIT
- + COMPOUND_FORMULA_START_BITS
- + NOT
- + ATOMIC_FORMULA_START_BITS
- + PACKAGE_NAME
- + EQ
- + IS_NOT_HASHED
- + getBits(packageName.length(), VALUE_SIZE_BITS)
- + getValueBits(packageName)
- + COMPOUND_FORMULA_END_BITS
- + INVALID_EFFECT
- + END_BIT;
- byte[] ruleBytes = getBytes(ruleBits);
- ByteBuffer rule =
- ByteBuffer.allocate(DEFAULT_FORMAT_VERSION_BYTES.length + ruleBytes.length);
- rule.put(DEFAULT_FORMAT_VERSION_BYTES);
- rule.put(ruleBytes);
- RuleParser binaryParser = new RuleBinaryParser();
-
- assertExpectException(
- RuleParseException.class,
- /* expectedExceptionMessageRegex */ String.format(
- "Unknown effect: %d", INVALID_EFFECT_VALUE),
- () -> binaryParser.parse(rule.array()));
- }
-
- @Test
- public void testBinaryString_invalidRule_invalidConnector_noIndexing() {
- String packageName = "com.test.app";
- String ruleBits =
- START_BIT
- + COMPOUND_FORMULA_START_BITS
- + INVALID_CONNECTOR
- + ATOMIC_FORMULA_START_BITS
- + PACKAGE_NAME
- + EQ
- + IS_NOT_HASHED
- + getBits(packageName.length(), VALUE_SIZE_BITS)
- + getValueBits(packageName)
- + COMPOUND_FORMULA_END_BITS
- + DENY
- + END_BIT;
- byte[] ruleBytes = getBytes(ruleBits);
- ByteBuffer rule =
- ByteBuffer.allocate(DEFAULT_FORMAT_VERSION_BYTES.length + ruleBytes.length);
- rule.put(DEFAULT_FORMAT_VERSION_BYTES);
- rule.put(ruleBytes);
- RuleParser binaryParser = new RuleBinaryParser();
-
- assertExpectException(
- RuleParseException.class,
- /* expectedExceptionMessageRegex */ String.format(
- "Unknown connector: %d", INVALID_CONNECTOR_VALUE),
- () -> binaryParser.parse(rule.array()));
- }
-
- @Test
- public void testBinaryString_invalidRule_invalidKey_noIndexing() {
- String packageName = "com.test.app";
- String ruleBits =
- START_BIT
- + COMPOUND_FORMULA_START_BITS
- + NOT
- + ATOMIC_FORMULA_START_BITS
- + INVALID_KEY
- + EQ
- + IS_NOT_HASHED
- + getBits(packageName.length(), VALUE_SIZE_BITS)
- + getValueBits(packageName)
- + COMPOUND_FORMULA_END_BITS
- + DENY
- + END_BIT;
- byte[] ruleBytes = getBytes(ruleBits);
- ByteBuffer rule =
- ByteBuffer.allocate(DEFAULT_FORMAT_VERSION_BYTES.length + ruleBytes.length);
- rule.put(DEFAULT_FORMAT_VERSION_BYTES);
- rule.put(ruleBytes);
- RuleParser binaryParser = new RuleBinaryParser();
-
- assertExpectException(
- RuleParseException.class,
- /* expectedExceptionMessageRegex */ String.format(
- "Unknown key: %d", INVALID_KEY_VALUE),
- () -> binaryParser.parse(rule.array()));
- }
-
- @Test
- public void testBinaryString_invalidRule_invalidSeparator_noIndexing() {
- String packageName = "com.test.app";
- String ruleBits =
- START_BIT
- + INVALID_FORMULA_SEPARATOR_BITS
- + NOT
- + ATOMIC_FORMULA_START_BITS
- + PACKAGE_NAME
- + EQ
- + IS_NOT_HASHED
- + getBits(packageName.length(), VALUE_SIZE_BITS)
- + getValueBits(packageName)
- + COMPOUND_FORMULA_END_BITS
- + DENY
- + END_BIT;
- byte[] ruleBytes = getBytes(ruleBits);
- ByteBuffer rule =
- ByteBuffer.allocate(DEFAULT_FORMAT_VERSION_BYTES.length + ruleBytes.length);
- rule.put(DEFAULT_FORMAT_VERSION_BYTES);
- rule.put(ruleBytes);
- RuleParser binaryParser = new RuleBinaryParser();
-
- assertExpectException(
- RuleParseException.class,
- /* expectedExceptionMessageRegex */ String.format(
- "Unknown formula separator: %d", INVALID_FORMULA_SEPARATOR_VALUE),
- () -> binaryParser.parse(rule.array()));
- }
-
- @Test
- public void testBinaryString_invalidRule_invalidEndMarker_noIndexing() {
- String packageName = "com.test.app";
- String ruleBits =
- START_BIT
- + COMPOUND_FORMULA_START_BITS
- + NOT
- + ATOMIC_FORMULA_START_BITS
- + PACKAGE_NAME
- + EQ
- + IS_NOT_HASHED
- + getBits(packageName.length(), VALUE_SIZE_BITS)
- + getValueBits(packageName)
- + COMPOUND_FORMULA_END_BITS
- + DENY
- + INVALID_MARKER_BIT;
- byte[] ruleBytes = getBytes(ruleBits);
- ByteBuffer rule =
- ByteBuffer.allocate(DEFAULT_FORMAT_VERSION_BYTES.length + ruleBytes.length);
- rule.put(DEFAULT_FORMAT_VERSION_BYTES);
- rule.put(ruleBytes);
- RuleParser binaryParser = new RuleBinaryParser();
-
- assertExpectException(
- RuleParseException.class,
- /* expectedExceptionMessageRegex */ "A rule must end with a '1' bit",
- () -> binaryParser.parse(rule.array()));
- }
-}
diff --git a/services/tests/uiservicestests/src/com/android/server/notification/TimeToLiveHelperTest.java b/services/tests/uiservicestests/src/com/android/server/notification/TimeToLiveHelperTest.java
index ad6c233..09a6840 100644
--- a/services/tests/uiservicestests/src/com/android/server/notification/TimeToLiveHelperTest.java
+++ b/services/tests/uiservicestests/src/com/android/server/notification/TimeToLiveHelperTest.java
@@ -19,6 +19,7 @@
import static com.google.common.truth.Truth.assertThat;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.anyInt;
+import static org.mockito.ArgumentMatchers.anyString;
import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.Mockito.never;
import static org.mockito.Mockito.verify;
@@ -108,6 +109,21 @@
}
@Test
+ public void testTimeoutExpiresButNotifEntryGone() {
+ NotificationRecord r = getRecord("testTimeoutExpires", 1);
+
+ mHelper.scheduleTimeoutLocked(r, 1);
+ ArgumentCaptor<PendingIntent> captor = ArgumentCaptor.forClass(PendingIntent.class);
+ verify(mAm).setExactAndAllowWhileIdle(anyInt(), eq(2L), captor.capture());
+
+ mHelper.mKeys.clear();
+
+ mHelper.mNotificationTimeoutReceiver.onReceive(mContext, captor.getValue().getIntent());
+
+ verify(mNm, never()).timeoutNotification(anyString());
+ }
+
+ @Test
public void testTimeoutExpires_twoEntries() {
NotificationRecord first = getRecord("testTimeoutFirst", 1);
NotificationRecord later = getRecord("testTimeoutSecond", 2);
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 2bebcc3..9408f90 100644
--- a/services/tests/wmtests/src/com/android/server/wm/DisplayContentTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/DisplayContentTests.java
@@ -1609,8 +1609,10 @@
final ActivityRecord app = mAppWindow.mActivityRecord;
app.setVisible(false);
- mDisplayContent.prepareAppTransition(WindowManager.TRANSIT_OPEN);
- mDisplayContent.mOpeningApps.add(app);
+ app.setVisibleRequested(false);
+ registerTestTransitionPlayer();
+ mDisplayContent.requestTransitionAndLegacyPrepare(WindowManager.TRANSIT_OPEN, 0);
+ app.setVisibility(true);
final int newOrientation = getRotatedOrientation(mDisplayContent);
app.setRequestedOrientation(newOrientation);
@@ -1641,14 +1643,6 @@
assertEquals(state.isSourceOrDefaultVisible(statusBarId, statusBars()),
rotatedState.isSourceOrDefaultVisible(statusBarId, statusBars()));
- final Rect outFrame = new Rect();
- final Rect outInsets = new Rect();
- final Rect outStableInsets = new Rect();
- final Rect outSurfaceInsets = new Rect();
- mAppWindow.getAnimationFrames(outFrame, outInsets, outStableInsets, outSurfaceInsets);
- // The animation frames should not be rotated because display hasn't rotated.
- assertEquals(mDisplayContent.getBounds(), outFrame);
-
// The display should keep current orientation and the rotated configuration should apply
// to the activity.
assertEquals(config.orientation, mDisplayContent.getConfiguration().orientation);
@@ -1676,9 +1670,8 @@
// Launch another activity before the transition is finished.
final Task task2 = new TaskBuilder(mSupervisor).setDisplay(mDisplayContent).build();
final ActivityRecord app2 = new ActivityBuilder(mAtm).setTask(task2)
- .setUseProcess(app.app).build();
- app2.setVisible(false);
- mDisplayContent.mOpeningApps.add(app2);
+ .setUseProcess(app.app).setVisible(false).build();
+ app2.setVisibility(true);
app2.setRequestedOrientation(newOrientation);
// The activity should share the same transform state as the existing one. The activity
@@ -1701,14 +1694,15 @@
assertTrue(mImeWindow.isAnimating(PARENTS, ANIMATION_TYPE_TOKEN_TRANSFORM));
// The fixed rotation transform can only be finished when all animation finished.
- doReturn(false).when(app2).isAnimating(anyInt(), anyInt());
- mDisplayContent.mAppTransition.notifyAppTransitionFinishedLocked(app2.token);
+ doReturn(false).when(app2).inTransition();
+ mDisplayContent.mFixedRotationTransitionListener.onAppTransitionFinishedLocked(app2.token);
assertTrue(app.hasFixedRotationTransform());
assertTrue(app2.hasFixedRotationTransform());
// The display should be rotated after the launch is finished.
- doReturn(false).when(app).isAnimating(anyInt(), anyInt());
- mDisplayContent.mAppTransition.notifyAppTransitionFinishedLocked(app.token);
+ app.setVisible(true);
+ doReturn(false).when(app).inTransition();
+ mDisplayContent.mFixedRotationTransitionListener.onAppTransitionFinishedLocked(app.token);
mStatusBarWindow.finishSeamlessRotation(t);
mNavBarWindow.finishSeamlessRotation(t);
@@ -1726,7 +1720,7 @@
final Task task = app.getTask();
final ActivityRecord app2 = new ActivityBuilder(mWm.mAtmService).setTask(task).build();
mDisplayContent.setFixedRotationLaunchingApp(app2, (mDisplayContent.getRotation() + 1) % 4);
- doReturn(true).when(app).inTransitionSelfOrParent();
+ doReturn(true).when(app).inTransition();
// If the task contains a transition, this should be no-op.
mDisplayContent.mFixedRotationTransitionListener.onAppTransitionFinishedLocked(app.token);
@@ -1736,7 +1730,7 @@
// The display should be unlikely to be in transition, but if it happens, the fixed
// rotation should proceed to finish because the activity/task level transition is finished.
doReturn(true).when(mDisplayContent).inTransition();
- doReturn(false).when(app).inTransitionSelfOrParent();
+ doReturn(false).when(app).inTransition();
// Although this notifies app instead of app2 that uses the fixed rotation, app2 should
// still finish the transform because there is no more transition event.
mDisplayContent.mFixedRotationTransitionListener.onAppTransitionFinishedLocked(app.token);